public void LikeClauseIsCorrectlyTranslated(string query)
        {
            var parsedQuery = DataApiSqlQueryParser.Parse(query);
            var actual      = AggregatePipelineBuilder.Build(parsedQuery);

            Assert.That(actual.ToString(), Contains.Substring("$regex"));
        }
示例#2
0
        public async Task <IActionResult> Search([FromBody] SearchBody body)
        {
            if (body == null)
            {
                return(BadRequest("No search body submitted"));
            }
            var             query = body.Query;
            DataApiSqlQuery parsedQuery;

            try
            {
                parsedQuery = DataApiSqlQueryParser.Parse(query);
            }
            catch (FormatException formatException)
            {
                return(BadRequest(formatException.Message));
            }

            // Validate
            var dataType = parsedQuery.FromArguments;

            // Authorize
            var loggedInUsername    = UsernameNormalizer.Normalize(HttpContext.User.Identity.Name);
            var resourceDescription = new SearchResourceDescription(dataType);
            var authorizationResult = await authorizationModule.AuthorizeAsync(resourceDescription, loggedInUsername);

            if (!authorizationResult.IsAuthorized)
            {
                return(StatusCode((int)HttpStatusCode.Unauthorized, "Not authorized"));
            }

            apiEventLogger.Log(LogLevel.Info, $"User '{authorizationResult.User.UserName}' submitted query '{query.RemoveLineBreaks()}'");
            return(await SearchExecutor.PerformSearch(dataRouter, query, body.Format));
        }
示例#3
0
        public void DuplicateWhereKeywordIsParsed()
        {
            var             query  = "SELECT * FROM Component WHERE Data.business_name LIKE '%arla%' WHERE Data.source_id = '3'";
            DataApiSqlQuery actual = null;

            Assert.That(() => actual = DataApiSqlQueryParser.Parse(query), Throws.Nothing);
            Assert.That(actual.WhereArguments, Is.EqualTo("(Data.business_name LIKE '%arla%') AND (Data.source_id = '3')"));
        }
示例#4
0
        private static string DetermineViewCollection(string query)
        {
            var placeholderReplacement  = "#PLACEHOLDER#";
            var placeholderRemovedQuery = Regex.Replace(query, "{[^}]+}", placeholderReplacement);
            var parsedQuery             = DataApiSqlQueryParser.Parse(placeholderRemovedQuery);

            return(parsedQuery.FromArguments);
        }
示例#5
0
        public void QueryAsExpected(string input, string expected)
        {
            var sut         = new QueryBuilder(x => x.Replace("Data.", ""));
            var parsedQuery = DataApiSqlQueryParser.Parse(input);
            var actual      = sut.Build(parsedQuery, parsedQuery.FromArguments);
            var whitespaceNormalizedActual = Regex.Replace(actual, "\\s+", " ");

            Assert.That(whitespaceNormalizedActual, Is.EqualTo(expected));
        }
示例#6
0
        private static bool FromArgumentIsNullOrContainsPlaceholder(string query)
        {
            var placeholderReplacement  = "#PLACEHOLDER#";
            var placeholderRemovedQuery = Regex.Replace(query, "{[^}]+}", placeholderReplacement);
            var parsedQuery             = DataApiSqlQueryParser.Parse(placeholderRemovedQuery);

            if (parsedQuery.FromArguments == null)
            {
                return(true);
            }
            return(parsedQuery.FromArguments.Contains(placeholderReplacement));
        }
示例#7
0
        public static async Task <IActionResult> PerformSearch(IDataRouter dataRouter, string query, ResultFormat resultFormat)
        {
            try
            {
                var parsedQuery   = DataApiSqlQueryParser.Parse(query);
                var collection    = parsedQuery.FromArguments.Trim();
                var rdDataStorage = await dataRouter.GetSourceSystemAsync(collection);

                var result = rdDataStorage.SearchAsync(parsedQuery);
                switch (resultFormat)
                {
                case ResultFormat.Json:
                    return(BuildJsonResultAsync(result));

                case ResultFormat.Csv:
                    return(BuildCsvResultAsync(result));

                default:
                    throw new ArgumentOutOfRangeException(nameof(resultFormat), resultFormat, null);
                }
            }
            catch (FormatException formatException)
            {
                return(new ContentResult
                {
                    ContentType = "text/plain",
                    Content = formatException.Message,
                    StatusCode = (int)HttpStatusCode.BadRequest
                });
            }
            catch (AggregateException aggregateException)
            {
                var innermostException = aggregateException.InnermostException();
                if (innermostException is FormatException)
                {
                    return(new ContentResult
                    {
                        ContentType = "text/plain",
                        Content = aggregateException.Message,
                        StatusCode = (int)HttpStatusCode.BadRequest
                    });
                }
                return(new ContentResult
                {
                    Content = aggregateException.InnerException?.Message ?? aggregateException.Message,
                    ContentType = "text/plain",
                    StatusCode = (int)HttpStatusCode.InternalServerError
                });
            }
        }
示例#8
0
        private async Task <bool> MatchesFilterAsync(string dataType, string dataObjectId, string filter)
        {
            if (string.IsNullOrWhiteSpace(dataType))
            {
                throw new ArgumentException("Value cannot be null or whitespace.", nameof(dataType));
            }
            if (string.IsNullOrEmpty(filter))
            {
                return(true);
            }
            var query       = $"SELECT * FROM {dataType} WHERE _id = '{dataObjectId}' AND ({filter})";
            var parsedQuery = DataApiSqlQueryParser.Parse(query);
            var collection  = await dataRouter.GetSourceSystemAsync(dataType);

            return(await collection.SearchAsync(parsedQuery).AnyAsync());
        }
示例#9
0
        public void SqlLikeQueryHandlesDifferentWhitespaces()
        {
            var query = "SELECT Product.Name From Products where timestamp >= '2018-01-01'      AND Product.Price.Netto < 300\n" +
                        "ORDER BY timestamp ASC SKIP 5 LIMIT 10";

            DataApiSqlQuery actual = null;

            Assert.That(() => actual = DataApiSqlQueryParser.Parse(query), Throws.Nothing);
            Assert.That(actual.SelectArguments, Is.EqualTo("Product.Name"));
            Assert.That(actual.FromArguments, Is.EqualTo("Products"));
            Assert.That(actual.WhereArguments, Is.EqualTo("timestamp >= '2018-01-01' AND Product.Price.Netto < 300"));
            Assert.That(actual.OrderByArguments, Is.EqualTo("timestamp ASC"));
            Assert.That(actual.SkipArguments, Is.EqualTo("5"));
            Assert.That(actual.LimitArguments, Is.EqualTo("10"));
            Assert.That(actual.GroupByArguments, Is.Null);
            Assert.That(actual.JoinArguments, Is.Null);
        }
示例#10
0
 public void SqlLikeQueryIsUnderstood(string query)
 {
     Assert.That(() => DataApiSqlQueryParser.Parse(query), Throws.Nothing);
 }
示例#11
0
        public void DuplicateFromKeywordThrowsException()
        {
            var query = "SELECT * FROM Component FROM Plate WHERE _id = '3'";

            Assert.That(() => DataApiSqlQueryParser.Parse(query), Throws.TypeOf <FormatException>());
        }
示例#12
0
        public async Task <IActionResult> DeleteMany([FromQuery] string dataType, [FromQuery] string whereArguments)
        {
            // Validate
            if (string.IsNullOrWhiteSpace(dataType))
            {
                return(BadRequest("Data type not specified"));
            }

            IRdDataStorage rdDataStorage;

            try
            {
                rdDataStorage = await dataRouter.GetSourceSystemAsync(dataType);
            }
            catch (KeyNotFoundException e)
            {
                return(BadRequest(e.Message));
            }

            var loggedInUsername   = UsernameNormalizer.Normalize(HttpContext.User.Identity.Name);
            var overwritingAllowed = await authorizationModule.IsOverwritingAllowedForCollectionAsync(dataType);

            // Check existance
            var query         = $"SELECT _id, Submitter FROM {dataType} WHERE {whereArguments}";
            var searchResult  = rdDataStorage.SearchAsync(DataApiSqlQueryParser.Parse(query));
            var deleteResults = new List <DeleteResult>();

            await foreach (var doc in searchResult)
            {
                var submitter = doc["Submitter"].AsString;
                var id        = doc["_id"].AsString;

                // Authorize
                var resourceDescription = new DeleteDataResourceDescription(dataType, submitter, overwritingAllowed);
                var authorizationResult = await authorizationModule.AuthorizeAsync(resourceDescription, loggedInUsername);

                if (!authorizationResult.IsAuthorized)
                {
                    deleteResults.Add(DeleteResult.Failed(dataType, id, "Not authorized"));
                    continue;
                }

                // Delete
                if (await rdDataStorage.DeleteDataContainerAsync(dataType, id))
                {
                    await subscriptionManager.NotifyDataChangedAsync(dataType, id, DataModificationType.Deleted);

                    deleteResults.Add(DeleteResult.Success(dataType, id));
                }
                else
                {
                    deleteResults.Add(DeleteResult.Failed(dataType, id, "Not found"));
                }
            }

            apiEventLogger.Log(LogLevel.Warning, $"User '{loggedInUsername}' has deleted data of type '{dataType}' with matching '{whereArguments}'");

            return(new ContentResult
            {
                ContentType = Conventions.JsonContentType,
                Content = JsonConvert.SerializeObject(deleteResults),
                StatusCode = (int)HttpStatusCode.OK
            });
        }