diff --git a/backend/src/Squidex.Data.EntityFramework/Providers/MySql/MySqlDialect.cs b/backend/src/Squidex.Data.EntityFramework/Providers/MySql/MySqlDialect.cs index 48d3500c7..adb26b01f 100644 --- a/backend/src/Squidex.Data.EntityFramework/Providers/MySql/MySqlDialect.cs +++ b/backend/src/Squidex.Data.EntityFramework/Providers/MySql/MySqlDialect.cs @@ -110,51 +110,66 @@ public sealed class MySqlDialect : SqlDialect var sqlPath = path.JsonPath(); var sqlOp = FormatOperator(op, value); var sqlRhs = FormatValues(op, value, queryParameters); - var isBoolean = value.ValueType is ClrValueType.Boolean; - string ScalarCondition() + string BuildCondition(string path) { - if (isBoolean) + var isNumeric = value.ValueType is + ClrValueType.Single or + ClrValueType.Double or + ClrValueType.Int32 or + ClrValueType.Int64; + if (isNumeric) { - return $"IF(JSON_VALUE({sqlPath}) = 'true', 1, 0) {sqlOp} {sqlRhs}"; + return $""" + (CASE WHEN JSON_TYPE({path}) IN ('INTEGER', 'DOUBLE', 'DECIMAL') + THEN CAST(JSON_UNQUOTE({path}) AS DECIMAL(65,10)) {sqlOp} {sqlRhs} + ELSE FALSE + END) + """; } - return base.Where(path, op, value, queryParameters, isJson); - } + var isBoolean = value.ValueType is ClrValueType.Boolean; + if (isBoolean) + { + return $""" + (CASE WHEN JSON_TYPE({path}) = 'BOOLEAN' + THEN IF(JSON_UNQUOTE({path}) = 'true', TRUE, FALSE) {sqlOp} {sqlRhs} + ELSE FALSE + END) + """; + } - if (value.IsList && op == CompareOperator.In) - { - return $""" - IF( - JSON_TYPE(JSON_EXTRACT({sqlPath})) = 'ARRAY', - JSON_OVERLAPS(JSON_EXTRACT({sqlPath}), JSON_ARRAY{sqlRhs}), - JSON_CONTAINS(JSON_ARRAY{sqlRhs}, JSON_EXTRACT({sqlPath})) - ) - """; - } + var isString = value.ValueType is + ClrValueType.Instant or + ClrValueType.Guid or + ClrValueType.String; + if (isString) + { + return $"JSON_UNQUOTE({path}) {sqlOp} {sqlRhs}"; + } - if (op == CompareOperator.Equals) - { - var valueExpr = value.ValueType switch + var isNull = value.ValueType is ClrValueType.Null; + if (isNull) { - ClrValueType.Boolean => - $"IF({sqlRhs} = 1, 'true', 'false')", - ClrValueType.String => - $"JSON_QUOTE({sqlRhs})", - _ => - $"CAST({sqlRhs} AS JSON)", - }; - - return $""" - IF( - JSON_TYPE(JSON_EXTRACT({sqlPath})) = 'ARRAY', - JSON_CONTAINS(JSON_EXTRACT({sqlPath}), {valueExpr}), - {ScalarCondition()} - ) - """; + var nullOp = FormatOperator(op, "null"); + return $"COALESCE(JSON_TYPE({path}), 'NULL') {nullOp} 'NULL'"; + } + + return base.Where(path, op, value, queryParameters, false); } - return ScalarCondition(); + return $""" + CASE WHEN JSON_TYPE(JSON_EXTRACT({sqlPath})) = 'ARRAY' + THEN EXISTS ( + SELECT 1 + FROM JSON_TABLE(JSON_EXTRACT({sqlPath}), '$[*]' COLUMNS ( + __element JSON PATH '$' + )) AS __jt + WHERE {BuildCondition("__element")} + ) + ELSE {BuildCondition($"JSON_EXTRACT({sqlPath})")} + END + """; } return base.Where(path, op, value, queryParameters, isJson); diff --git a/backend/src/Squidex.Data.EntityFramework/Providers/Postgres/PostgresDialect.cs b/backend/src/Squidex.Data.EntityFramework/Providers/Postgres/PostgresDialect.cs index 88e5a960c..dc439fbb3 100644 --- a/backend/src/Squidex.Data.EntityFramework/Providers/Postgres/PostgresDialect.cs +++ b/backend/src/Squidex.Data.EntityFramework/Providers/Postgres/PostgresDialect.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System.Text; using Npgsql; using Squidex.Infrastructure.Queries; using Squidex.Providers.Postgres.App; @@ -77,69 +76,54 @@ public class PostgresDialect : SqlDialect var sqlOp = FormatOperator(op, value); var sqlRhs = FormatValues(op, value, queryParameters); - var isBoolean = value.ValueType is ClrValueType.Boolean; - - var isNumeric = value.ValueType is - ClrValueType.Single or - ClrValueType.Double or - ClrValueType.Int32 or - ClrValueType.Int64; - - string ScalarCondition() + string BuildCondition(string path, string castPath) { + var isNumeric = value.ValueType is + ClrValueType.Single or + ClrValueType.Double or + ClrValueType.Int32 or + ClrValueType.Int64; + if (isNumeric) { - return $"(CASE WHEN jsonb_typeof({sqlPath}) = 'number' THEN ({sqlPathCast})::numeric {sqlOp} {sqlRhs} ELSE FALSE END)"; + return $"(CASE WHEN jsonb_typeof({path}) = 'number' THEN ({castPath})::numeric {sqlOp} {sqlRhs} ELSE FALSE END)"; } + var isBoolean = value.ValueType is ClrValueType.Boolean; if (isBoolean) { - return $"(CASE WHEN jsonb_typeof({sqlPath}) = 'boolean' THEN ({sqlPathCast})::boolean {sqlOp} {sqlRhs} ELSE FALSE END)"; + return $"(CASE WHEN jsonb_typeof({path}) = 'boolean' THEN ({castPath})::boolean {sqlOp} {sqlRhs} ELSE FALSE END)"; } - return base.Where(path, op, value, queryParameters, true); - } - - string ToJsonbValue() - { - if (isNumeric) + var isString = value.ValueType is + ClrValueType.Instant or + ClrValueType.Guid or + ClrValueType.String; + if (isString) { - return $"to_jsonb({sqlRhs}::numeric)"; + return $"{path} #>> '{{{{}}}}' {sqlOp} {sqlRhs}"; } - if (isBoolean) + var isNull = value.ValueType is ClrValueType.Null; + if (isNull) { - return $"to_jsonb({sqlRhs}::boolean)"; + var nullOp = FormatOperator(op, "null"); + return $"jsonb_typeof({path}) {nullOp} 'null'"; } - return $"to_jsonb({sqlRhs}::text)"; - } - - if (value.IsList && op == CompareOperator.In) - { - return $""" - CASE WHEN jsonb_typeof({sqlPath}) = 'array' - THEN EXISTS ( - SELECT 1 - FROM jsonb_array_elements({sqlPath}) AS elem - WHERE jsonb_build_array{sqlRhs} @> elem - ) - ELSE {sqlPath} <@ jsonb_build_array{sqlRhs} - END - """; - } - - if (op == CompareOperator.Equals) - { - return $""" - CASE WHEN jsonb_typeof({sqlPath}) = 'array' - THEN {sqlPath} @> jsonb_build_array({ToJsonbValue()}) - ELSE {ScalarCondition()} - END - """; + return base.Where(path, op, value, queryParameters, false); } - return ScalarCondition(); + return $""" + CASE WHEN jsonb_typeof({sqlPath}) = 'array' + THEN EXISTS ( + SELECT 1 + FROM jsonb_array_elements({sqlPath}) AS __element + WHERE {BuildCondition("__element", "__element")} + ) + ELSE {BuildCondition(sqlPath, sqlPathCast)} + END + """; } return base.Where(path, op, value, queryParameters, isJson); @@ -148,12 +132,16 @@ public class PostgresDialect : SqlDialect protected override string FormatField(PropertyPath path, bool isJson) { var baseField = path[0]; - if (isJson && path.Count > 1) { return path.JsonPath(true); } + if (baseField == "__element" || baseField.Contains("->", StringComparison.Ordinal)) + { + return baseField; + } + return $"\"{baseField}\""; } } diff --git a/backend/src/Squidex.Data.EntityFramework/Providers/SqlServer/SqlServerDialect.cs b/backend/src/Squidex.Data.EntityFramework/Providers/SqlServer/SqlServerDialect.cs index e58cf0ea5..843a03184 100644 --- a/backend/src/Squidex.Data.EntityFramework/Providers/SqlServer/SqlServerDialect.cs +++ b/backend/src/Squidex.Data.EntityFramework/Providers/SqlServer/SqlServerDialect.cs @@ -92,92 +92,62 @@ public sealed class SqlServerDialect : SqlDialect var sqlOp = FormatOperator(op, value); var sqlRhs = FormatValues(op, value, queryParameters); - var isNull = value.ValueType is ClrValueType.Null; - var isBoolean = value.ValueType is ClrValueType.Boolean; - var isNumeric = value.ValueType is - ClrValueType.Single or - ClrValueType.Double or - ClrValueType.Int32 or - ClrValueType.Int64; - - string ScalarCondition() + string BuildCondition(string path, string queryPath) { - if (isNull) - { - if (op == CompareOperator.Equals) - { - return $"JSON_QUERY({sqlPath}) IS NULL AND JSON_VALUE({sqlPath}) IS NULL"; - } - - if (op == CompareOperator.NotEquals) - { - return $"JSON_QUERY({sqlPath}) IS NOT NULL OR JSON_VALUE({sqlPath}) IS NOT NULL"; - } - } - + var isNumeric = value.ValueType is + ClrValueType.Single or + ClrValueType.Double or + ClrValueType.Int32 or + ClrValueType.Int64; if (isNumeric) { - return $"TRY_CAST(JSON_VALUE({sqlPath}) AS NUMERIC) {sqlOp} {sqlRhs}"; + return $"TRY_CAST({path} AS NUMERIC) {sqlOp} {sqlRhs}"; } + var isBoolean = value.ValueType is ClrValueType.Boolean; if (isBoolean) { - return $"IIF(JSON_VALUE({sqlPath}) = 'true', 1, 0) {sqlOp} {sqlRhs}"; + return $"IIF({path} = 'true', 1, IIF({path} = 'false', 0, NULL)) {sqlOp} {sqlRhs}"; } - return base.Where(path, op, value, queryParameters, isJson); - } - - string ArrayCondition(string field, string op) - { - if (isNumeric) + var isString = value.ValueType is + ClrValueType.Instant or + ClrValueType.Guid or + ClrValueType.String; + if (isString) { - return $"TRY_CAST({field} AS NUMERIC) {op} {sqlRhs}"; + return $"{path} {sqlOp} {sqlRhs}"; } - if (isBoolean) + var isNull = value.ValueType is ClrValueType.Null; + if (isNull) { - return $"IIF({field} = 'true', 1, 0) {op} {sqlRhs}"; - } - - return $"{field} = {sqlRhs}"; - } + if (op == CompareOperator.Equals) + { + return $"{queryPath} IS NULL AND {path} IS NULL"; + } - if (value.IsList && op == CompareOperator.In) - { - return $""" - CASE WHEN LEFT(JSON_QUERY({sqlPath}), 1) = '[' - THEN ( - SELECT COUNT(*) - FROM OPENJSON({sqlPath}) AS field_arr - WHERE {ArrayCondition("field_arr.value", "IN")} - ) - ELSE ( - SELECT COUNT(*) - WHERE {ScalarCondition()} - ) - END > 0 - """; - } + if (op == CompareOperator.NotEquals) + { + return $"{queryPath} IS NOT NULL OR {path} IS NOT NULL"; + } + } - if (op == CompareOperator.Equals) - { - return $""" - CASE WHEN LEFT(JSON_QUERY({sqlPath}), 1) = '[' - THEN ( - SELECT COUNT(*) - FROM OPENJSON({sqlPath}) AS field_arr - WHERE {ArrayCondition("field_arr.value", "=")} - ) - ELSE ( - SELECT COUNT(*) - WHERE {ScalarCondition()} - ) - END > 0 - """; + return base.Where(path, op, value, queryParameters, false); } - return ScalarCondition(); + return $""" + ( + CASE WHEN LEFT(LTRIM(JSON_QUERY({sqlPath})), 1) = '[' + THEN CASE WHEN EXISTS ( + SELECT 1 + FROM OPENJSON({sqlPath}) AS __element + WHERE {BuildCondition("__element.[value]", "__element.[value]")} + ) THEN 1 ELSE 0 END + ELSE CASE WHEN {BuildCondition($"JSON_VALUE({sqlPath})", $"JSON_QUERY({sqlPath})")} THEN 1 ELSE 0 END + END + ) = 1 + """; } return base.Where(path, op, value, queryParameters, isJson); diff --git a/backend/src/Squidex.Infrastructure/Queries/QueryModel.cs b/backend/src/Squidex.Infrastructure/Queries/QueryModel.cs index 6d87646a4..ab326f111 100644 --- a/backend/src/Squidex.Infrastructure/Queries/QueryModel.cs +++ b/backend/src/Squidex.Infrastructure/Queries/QueryModel.cs @@ -117,14 +117,12 @@ public sealed class QueryModel public QueryModel Flatten(int maxDepth = 7, bool onlyWithOperators = true) { var predicate = (Predicate?)null; - if (onlyWithOperators) { predicate = x => Operators.TryGetValue(x.Type, out var operators) && operators.Count > 0; } var flatten = Schema.Flatten(maxDepth, predicate); - if (ReferenceEquals(flatten, Schema)) { return this; diff --git a/backend/tests/Squidex.Data.Tests/EntityFramework/Infrastructure/Queries/EFQueryTests.cs b/backend/tests/Squidex.Data.Tests/EntityFramework/Infrastructure/Queries/EFQueryTests.cs index 1f5daa2de..0fb0e3710 100644 --- a/backend/tests/Squidex.Data.Tests/EntityFramework/Infrastructure/Queries/EFQueryTests.cs +++ b/backend/tests/Squidex.Data.Tests/EntityFramework/Infrastructure/Queries/EFQueryTests.cs @@ -79,12 +79,16 @@ public abstract class EFQueryTests(ISqlFixture fixture) Json = new TestJson { Boolean = i > 10, + BooleanArray = [i > 10, i > 15], BooleanOrNull = i > 10 ? true : null, Mixed = mixed, + MixedArray = [i, i % 3 == 0 ? null : $"T{i}", i > 10], Number = i, + NumberArray = [0, i], NumberOrNull = i > 10 ? null : i, - Array = [0, i], Text = $"Prefix{i}Suffix", + TextArray = [$"X{i}", $"Y{i}"], + TextOrNull = i > 10 ? null : $"Prefix{i}Suffix", }, Point = new Point(i * 2, i * 2) { SRID = 4326 }, }); @@ -142,260 +146,805 @@ public abstract class EFQueryTests(ISqlFixture fixture) } [Fact] - public async Task Should_sort_by_text() + public async Task Should_query_with_skip_and_take_sorted_descending() + { + var actual = await QueryAsync(new ClrQuery + { + Take = 5, + Skip = 5, + Sort = [new SortNode("Number", SortOrder.Descending)], + }); + + Assert.Equal(Range(15, 11), actual); + } + + [Fact] + public async Task Should_sort_by_number_ascending() + { + var actual = await QueryAsync(new ClrQuery + { + Sort = [new SortNode("Number", SortOrder.Ascending)], + }); + + Assert.Equal(Range(1, 20), actual); + } + + [Fact] + public async Task Should_sort_by_number_descending() + { + var actual = await QueryAsync(new ClrQuery + { + Sort = [new SortNode("Number", SortOrder.Descending)], + }); + + Assert.Equal(Range(20, 1), actual); + } + + [Fact] + public async Task Should_sort_by_number_ascending_in_json() + { + var actual = await QueryAsync(new ClrQuery + { + Sort = [new SortNode("Json.number", SortOrder.Ascending)], + }); + + Assert.Equal(Range(1, 20), actual); + } + + [Fact] + public async Task Should_sort_by_number_descending_in_json() + { + var actual = await QueryAsync(new ClrQuery + { + Sort = [new SortNode("Json.number", SortOrder.Descending)], + }); + + Assert.Equal(Range(20, 1), actual); + } + + [Fact] + public async Task Should_sort_by_text_ascending() + { + var actual = await QueryAsync(new ClrQuery + { + Sort = [new SortNode("Text", SortOrder.Ascending)], + }); + + Assert.Equal([.. Range(10, 19), 1, 2, 20, .. Range(3, 9)], actual); + } + + [Fact] + public async Task Should_sort_by_text_descending() { var actual = await QueryAsync(new ClrQuery { Sort = [new SortNode("Text", SortOrder.Descending)], }); - Assert.Equal([.. Range(9, 3), 2, 20, 1, .. Range(19, 10)], actual); + Assert.Equal([.. Range(9, 3), 2, 20, 1, .. Range(19, 10)], actual); + } + + [Fact] + public async Task Should_sort_by_text_ascending_in_json() + { + var actual = await QueryAsync(new ClrQuery + { + Sort = [new SortNode("Json.text", SortOrder.Ascending)], + }); + + Assert.Equal([.. Range(10, 19), 1, 2, 20, .. Range(3, 9)], actual); + } + + [Fact] + public async Task Should_sort_by_text_descending_in_json() + { + var actual = await QueryAsync(new ClrQuery + { + Sort = [new SortNode("Json.text", SortOrder.Descending)], + }); + + Assert.Equal([.. Range(9, 3), 2, 20, 1, .. Range(19, 10)], actual); + } + + [Fact] + public async Task Should_sort_by_boolean_ascending() + { + var actual = await QueryAsync(new ClrQuery + { + Sort = [new SortNode("Boolean", SortOrder.Ascending), new SortNode("Number", SortOrder.Ascending)], + }); + + Assert.Equal([.. Range(1, 10), .. Range(11, 20)], actual); + } + + [Fact] + public async Task Should_sort_by_boolean_descending() + { + var actual = await QueryAsync(new ClrQuery + { + Sort = [new SortNode("Boolean", SortOrder.Descending), new SortNode("Number", SortOrder.Ascending)], + }); + + Assert.Equal([.. Range(11, 20), .. Range(1, 10)], actual); + } + + [Fact] + public async Task Should_sort_by_boolean_ascending_in_json() + { + var actual = await QueryAsync(new ClrQuery + { + Sort = [new SortNode("Json.boolean", SortOrder.Ascending), new SortNode("Number", SortOrder.Ascending)], + }); + + Assert.Equal([.. Range(1, 10), .. Range(11, 20)], actual); + } + + [Fact] + public async Task Should_sort_by_boolean_descending_in_json() + { + var actual = await QueryAsync(new ClrQuery + { + Sort = [new SortNode("Json.boolean", SortOrder.Descending), new SortNode("Number", SortOrder.Ascending)], + }); + + Assert.Equal([.. Range(11, 20), .. Range(1, 10)], actual); + } + + [Fact] + public async Task Should_sort_by_mixed_json_descending() + { + var actual = await QueryAsync(new ClrQuery + { + Sort = [new SortNode("Json.mixed", SortOrder.Descending)], + }); + + Assert.Equal([20, 14, 8, 2], actual.Take(4)); + } + + [Fact] + public async Task Should_sort_by_multiple_fields() + { + var actual = await QueryAsync(new ClrQuery + { + Sort = + [ + new SortNode("Boolean", SortOrder.Ascending), + new SortNode("Number", SortOrder.Descending), + ], + }); + + Assert.Equal([.. Range(10, 1), .. Range(20, 11)], actual); + } + + [Fact] + public async Task Should_filter_with_or() + { + var actual = await QueryAsync(new ClrQuery + { + Filter = ClrFilter.Or(ClrFilter.Lt("Number", 3), ClrFilter.Gt("Number", 17)), + }); + + Assert.Equal([1, 2, 18, 19, 20], actual.Order().ToArray()); + } + + [Fact] + public async Task Should_filter_with_and() + { + var actual = await QueryAsync(new ClrQuery + { + Filter = ClrFilter.And(ClrFilter.Gt("Json.number", 5), ClrFilter.Lt("Json.number", 16)), + }); + + Assert.Equal(Range(6, 15), actual.Order().ToArray()); + } + + [Fact] + public async Task Should_filter_with_not() + { + var actual = await QueryAsync(new ClrQuery + { + Filter = ClrFilter.Not(ClrFilter.Gt("Number", 10)), + }); + + Assert.Equal(Range(1, 10), actual.Order().ToArray()); + } + + [Fact] + public async Task Should_filter_by_number_equal() + { + var actual = await QueryAsync(new ClrQuery + { + Filter = ClrFilter.Eq("Number", 7), + }); + + Assert.Equal([7], actual.Order().ToArray()); + } + + [Fact] + public async Task Should_filter_by_number_not_equal() + { + var actual = await QueryAsync(new ClrQuery + { + Filter = ClrFilter.Ne("Number", 7), + }); + + Assert.Equal(AllExept(7), actual.Order().ToArray()); + } + + [Fact] + public async Task Should_filter_by_number_greater_than() + { + var actual = await QueryAsync(new ClrQuery + { + Filter = ClrFilter.Gt("Number", 15), + }); + + Assert.Equal(Range(16, 20), actual.Order().ToArray()); + } + + [Fact] + public async Task Should_filter_by_number_greater_than_or_equal() + { + var actual = await QueryAsync(new ClrQuery + { + Filter = ClrFilter.Ge("Number", 15), + }); + + Assert.Equal(Range(15, 20), actual.Order().ToArray()); + } + + [Fact] + public async Task Should_filter_by_number_less_than() + { + var actual = await QueryAsync(new ClrQuery + { + Filter = ClrFilter.Lt("Number", 5), + }); + + Assert.Equal(Range(1, 4), actual.Order().ToArray()); + } + + [Fact] + public async Task Should_filter_by_number_less_than_or_equal() + { + var actual = await QueryAsync(new ClrQuery + { + Filter = ClrFilter.Le("Number", 5), + }); + + Assert.Equal(Range(1, 5), actual.Order().ToArray()); + } + + [Fact] + public async Task Should_filter_by_number_equal_in_json() + { + var actual = await QueryAsync(new ClrQuery + { + Filter = ClrFilter.Eq("Json.number", 7), + }); + + Assert.Equal([7], actual.Order().ToArray()); + } + + [Fact] + public async Task Should_filter_by_number_not_equal_in_json() + { + var actual = await QueryAsync(new ClrQuery + { + Filter = ClrFilter.Ne("Json.number", 7), + }); + + Assert.Equal(AllExept(7), actual.Order().ToArray()); + } + + [Fact] + public async Task Should_filter_by_number_greater_than_in_json() + { + var actual = await QueryAsync(new ClrQuery + { + Filter = ClrFilter.Gt("Json.number", 15), + }); + + Assert.Equal(Range(16, 20), actual.Order().ToArray()); + } + + [Fact] + public async Task Should_filter_by_number_greater_than_or_equal_in_json() + { + var actual = await QueryAsync(new ClrQuery + { + Filter = ClrFilter.Ge("Json.number", 15), + }); + + Assert.Equal(Range(15, 20), actual.Order().ToArray()); + } + + [Fact] + public async Task Should_filter_by_number_less_than_in_json() + { + var actual = await QueryAsync(new ClrQuery + { + Filter = ClrFilter.Lt("Json.number", 5), + }); + + Assert.Equal(Range(1, 4), actual.Order().ToArray()); + } + + [Fact] + public async Task Should_filter_by_number_less_than_or_equal_in_json() + { + var actual = await QueryAsync(new ClrQuery + { + Filter = ClrFilter.Le("Json.number", 5), + }); + + Assert.Equal(Range(1, 5), actual.Order().ToArray()); + } + + [Fact] + public async Task Should_filter_by_number_null_in_nullable_json() + { + var actual = await QueryAsync(new ClrQuery + { + Filter = ClrFilter.Eq("Json.numberOrNull", ClrValue.Null), + }); + + Assert.Equal(Range(11, 20), actual.Order().ToArray()); + } + + [Fact] + public async Task Should_filter_by_number_not_null_in_nullable_json() + { + var actual = await QueryAsync(new ClrQuery + { + Filter = ClrFilter.Ne("Json.numberOrNull", ClrValue.Null), + }); + + Assert.Equal(Range(1, 10), actual.Order().ToArray()); + } + + [Fact] + public async Task Should_filter_by_number_equal_in_nullable_json() + { + var actual = await QueryAsync(new ClrQuery + { + Filter = ClrFilter.Eq("Json.numberOrNull", 5), + }); + + Assert.Equal([5], actual.Order().ToArray()); + } + + [Fact] + public async Task Should_filter_by_number_greater_than_in_nullable_json() + { + var actual = await QueryAsync(new ClrQuery + { + Filter = ClrFilter.Gt("Json.numberOrNull", 7), + }); + + Assert.Equal([8, 9, 10], actual.Order().ToArray()); + } + + [Fact] + public async Task Should_filter_by_number_less_than_in_nullable_json() + { + var actual = await QueryAsync(new ClrQuery + { + Filter = ClrFilter.Lt("Json.numberOrNull", 4), + }); + + Assert.Equal([1, 2, 3], actual.Order().ToArray()); + } + + [Fact] + public async Task Should_filter_by_number_equal_in_mixed_json() + { + var actual = await QueryAsync(new ClrQuery + { + Filter = ClrFilter.Eq("Json.mixed", 8), + }); + + Assert.Equal([8], actual.Order().ToArray()); + } + + [Fact] + public async Task Should_filter_by_number_greater_than_in_mixed_json() + { + var actual = await QueryAsync(new ClrQuery + { + Filter = ClrFilter.Gt("Json.mixed", 5), + }); + + Assert.Equal([8, 10, 14, 16, 20], actual.Order().ToArray()); + } + + [Fact] + public async Task Should_filter_by_number_in_mixed_json() + { + var actual = await QueryAsync(new ClrQuery + { + Filter = ClrFilter.In("Json.mixed", new List { 2, 8, 14 }), + }); + + Assert.Equal([2, 8, 14], actual.Order().ToArray()); + } + + [Fact] + public async Task Should_filter_by_number_equal_in_json_number_array() + { + var actual = await QueryAsync(new ClrQuery + { + Filter = ClrFilter.Eq("Json.numberArray", 7), + }); + + Assert.Equal([7], actual.Order().ToArray()); + } + + [Fact] + public async Task Should_filter_by_number_greater_than_in_json_number_array() + { + var actual = await QueryAsync(new ClrQuery + { + Filter = ClrFilter.Gt("Json.numberArray", 18), + }); + + Assert.Equal([19, 20], actual.Order().ToArray()); + } + + [Fact] + public async Task Should_filter_by_number_greater_than_or_equal_in_json_number_array() + { + var actual = await QueryAsync(new ClrQuery + { + Filter = ClrFilter.Ge("Json.numberArray", 18), + }); + + Assert.Equal([18, 19, 20], actual.Order().ToArray()); + } + + [Fact] + public async Task Should_filter_by_number_in_json_number_array() + { + var actual = await QueryAsync(new ClrQuery + { + Filter = ClrFilter.In("Json.numberArray", new List { 3, 5, 7 }), + }); + + Assert.Equal([3, 5, 7], actual.Order().ToArray()); + } + + [Fact] + public async Task Should_filter_by_number_with_index_in_json_number_array() + { + var actual = await QueryAsync(new ClrQuery + { + Filter = ClrFilter.And(ClrFilter.Gt("Json.numberArray.1", 5), ClrFilter.Lt("Json.numberArray.1", 16)), + }); + + Assert.Equal(Range(6, 15), actual.Order().ToArray()); + } + + [Fact] + public async Task Should_filter_by_number_equal_in_json_mixed_array() + { + var actual = await QueryAsync(new ClrQuery + { + Filter = ClrFilter.Eq("Json.mixedArray", 7), + }); + + Assert.Equal([7], actual.Order().ToArray()); + } + + [Fact] + public async Task Should_filter_by_number_greater_than_in_json_mixed_array() + { + var actual = await QueryAsync(new ClrQuery + { + Filter = ClrFilter.Gt("Json.mixedArray", 16), + }); + + Assert.Equal([17, 18, 19, 20], actual.Order().ToArray()); + } + + [Fact] + public async Task Should_filter_by_number_less_than_or_equal_in_json_mixed_array() + { + var actual = await QueryAsync(new ClrQuery + { + Filter = ClrFilter.Le("Json.mixedArray", 3), + }); + + Assert.Equal([1, 2, 3], actual.Order().ToArray()); + } + + [Fact] + public async Task Should_filter_by_number_with_index_in_json_mixed_array() + { + var actual = await QueryAsync(new ClrQuery + { + Filter = ClrFilter.And(ClrFilter.Gt("Json.mixedArray.0", 5), ClrFilter.Lt("Json.mixedArray.0", 16)), + }); + + Assert.Equal(Range(6, 15), actual.Order().ToArray()); + } + + [Fact] + public async Task Should_filter_by_string_equal() + { + var actual = await QueryAsync(new ClrQuery + { + Filter = ClrFilter.Eq("Text", "Prefix7Suffix"), + }); + + Assert.Equal([7], actual.Order().ToArray()); + } + + [Fact] + public async Task Should_filter_by_string_not_equal() + { + var actual = await QueryAsync(new ClrQuery + { + Filter = ClrFilter.Ne("Text", "Prefix7Suffix"), + }); + + Assert.Equal(AllExept(7), actual.Order().ToArray()); } [Fact] - public async Task Should_sort_by_text_in_json() + public async Task Should_filter_by_string_contains() { var actual = await QueryAsync(new ClrQuery { - Sort = [new SortNode("Json.text", SortOrder.Descending)], + Filter = ClrFilter.Contains("Text", "7"), }); - Assert.Equal([.. Range(9, 3), 2, 20, 1, .. Range(19, 10)], actual); + Assert.Equal([7, 17], actual.Order().ToArray()); } [Fact] - public async Task Should_sort_by_number() + public async Task Should_filter_by_string_starts_with() { var actual = await QueryAsync(new ClrQuery { - Sort = [new SortNode("Number", SortOrder.Descending)], + Filter = ClrFilter.StartsWith("Text", "Prefix5"), }); - Assert.Equal(Range(20, 1), actual); + Assert.Equal([5], actual.Order().ToArray()); } [Fact] - public async Task Should_sort_by_number_in_json() + public async Task Should_filter_by_string_ends_with() { var actual = await QueryAsync(new ClrQuery { - Sort = [new SortNode("Json.number", SortOrder.Descending)], + Filter = ClrFilter.EndsWith("Text", "5Suffix"), }); - Assert.Equal(Range(20, 1), actual); + Assert.Equal([5, 15], actual.Order().ToArray()); } [Fact] - public async Task Should_sort_by_boolean_in_json() + public async Task Should_filter_by_string_equal_in_json() { var actual = await QueryAsync(new ClrQuery { - Sort = [new SortNode("Boolean", SortOrder.Descending), new SortNode("Number", SortOrder.Ascending)], + Filter = ClrFilter.Eq("Json.text", "Prefix7Suffix"), }); - Assert.Equal([.. Range(11, 20), .. Range(1, 10)], actual); + Assert.Equal([7], actual.Order().ToArray()); } [Fact] - public async Task Should_sort_by_boolean() + public async Task Should_filter_by_string_not_equal_in_json() { var actual = await QueryAsync(new ClrQuery { - Sort = [new SortNode("Json.boolean", SortOrder.Descending), new SortNode("Number", SortOrder.Ascending)], + Filter = ClrFilter.Ne("Json.text", "Prefix7Suffix"), }); - Assert.Equal([.. Range(11, 20), .. Range(1, 10)], actual); + Assert.Equal(AllExept(7), actual.Order().ToArray()); } [Fact] - public async Task Should_sort_by_mixed_json() + public async Task Should_filter_by_string_contains_in_json() { var actual = await QueryAsync(new ClrQuery { - Sort = [new SortNode("Json.mixed", SortOrder.Descending)], + Filter = ClrFilter.Contains("Json.text", "7"), }); - Assert.Equal([20, 14, 8, 2], actual.Take(4)); + Assert.Equal([7, 17], actual.Order().ToArray()); } [Fact] - public async Task Should_filter_with_or() + public async Task Should_filter_by_string_starts_with_in_json() { var actual = await QueryAsync(new ClrQuery { - Filter = ClrFilter.Or(ClrFilter.Lt("Number", 3), ClrFilter.Gt("Number", 17)), + Filter = ClrFilter.StartsWith("Json.text", "Prefix5"), }); - Assert.Equal([1, 2, 18, 19, 20], actual.Order().ToArray()); + Assert.Equal([5], actual.Order().ToArray()); } [Fact] - public async Task Should_filter_with_and() + public async Task Should_filter_by_string_ends_with_in_json() { var actual = await QueryAsync(new ClrQuery { - Filter = ClrFilter.And(ClrFilter.Gt("Json.number", 5), ClrFilter.Lt("Json.number", 16)), + Filter = ClrFilter.EndsWith("Json.text", "5Suffix"), }); - Assert.Equal(Range(6, 15), actual.Order().ToArray()); + Assert.Equal([5, 15], actual.Order().ToArray()); } [Fact] - public async Task Should_filter_with_not() + public async Task Should_filter_by_string_null_in_nullable_json() { var actual = await QueryAsync(new ClrQuery { - Filter = ClrFilter.Not(ClrFilter.Gt("Number", 10)), + Filter = ClrFilter.Eq("Json.textOrNull", ClrValue.Null), + }); + + Assert.Equal(Range(11, 20), actual.Order().ToArray()); + } + + [Fact] + public async Task Should_filter_by_string_not_null_in_nullable_json() + { + var actual = await QueryAsync(new ClrQuery + { + Filter = ClrFilter.Ne("Json.textOrNull", ClrValue.Null), }); Assert.Equal(Range(1, 10), actual.Order().ToArray()); } [Fact] - public async Task Should_filter_by_number() + public async Task Should_filter_by_string_equal_in_nullable_json() { var actual = await QueryAsync(new ClrQuery { - Filter = ClrFilter.Gt("Number", 5), + Filter = ClrFilter.Eq("Json.textOrNull", "Prefix5Suffix"), }); - Assert.Equal(Range(6, 20), actual.Order().ToArray()); + Assert.Equal([5], actual.Order().ToArray()); } [Fact] - public async Task Should_filter_by_number_in_json() + public async Task Should_filter_by_string_contains_in_nullable_json() { var actual = await QueryAsync(new ClrQuery { - Filter = ClrFilter.Gt("Json.number", 5), + Filter = ClrFilter.Contains("Json.textOrNull", "5"), }); - Assert.Equal(Range(6, 20), actual.Order().ToArray()); + Assert.Equal([5], actual.Order().ToArray()); } [Fact] - public async Task Should_filter_by_number_in_mixed_json() + public async Task Should_filter_by_string_starts_with_in_nullable_json() { var actual = await QueryAsync(new ClrQuery { - Filter = ClrFilter.Gt("Json.mixed", 5), + Filter = ClrFilter.StartsWith("Json.textOrNull", "Prefix"), }); - Assert.Equal([8, 14, 20], actual.Order().ToArray()); + Assert.Equal(Range(1, 10), actual.Order().ToArray()); } [Fact] - public async Task Should_filter_by_null() + public async Task Should_filter_by_string_contains_in_mixed_json() { var actual = await QueryAsync(new ClrQuery { - Filter = ClrFilter.Eq("NumberOrNull", ClrValue.Null), + Filter = ClrFilter.Contains("Json.mixed", "7"), }); - Assert.Equal(Range(11, 20), actual.Order().ToArray()); + Assert.Equal([7], actual.Order().ToArray()); } [Fact] - public async Task Should_filter_by_null_in_json() + public async Task Should_filter_by_string_starts_with_in_mixed_json() { var actual = await QueryAsync(new ClrQuery { - Filter = ClrFilter.Eq("Json.numberOrNull", ClrValue.Null), + Filter = ClrFilter.StartsWith("Json.mixed", "Prefix"), }); - Assert.Equal(Range(11, 20), actual.Order().ToArray()); + Assert.Equal([1, 7, 13, 19], actual.Order().ToArray()); } [Fact] - public async Task Should_filter_by_null_in_mixed_json() + public async Task Should_filter_by_string_ends_with_in_mixed_json() { var actual = await QueryAsync(new ClrQuery { - Filter = ClrFilter.Eq("Json.mixed", ClrValue.Null), + Filter = ClrFilter.EndsWith("Json.mixed", "Suffix"), }); - Assert.Equal([6, 12, 18], actual.Order().ToArray()); + Assert.Equal([1, 7, 13, 19], actual.Order().ToArray()); } [Fact] - public async Task Should_filter_with_many() + public async Task Should_filter_by_string_equal_in_json_text_array() { var actual = await QueryAsync(new ClrQuery { - Filter = ClrFilter.In("Number", new List { 3, 5, 7 }), + Filter = ClrFilter.Eq("Json.textArray", "X5"), }); - Assert.Equal([3, 5, 7], actual.Order().ToArray()); + Assert.Equal([5], actual.Order().ToArray()); } [Fact] - public async Task Should_filter_with_many_in_json() + public async Task Should_filter_by_string_not_equal_in_json_text_array() { var actual = await QueryAsync(new ClrQuery { - Filter = ClrFilter.In("Json.number", new List { 3, 5, 7 }), + Filter = ClrFilter.Ne("Json.textArray", "X5"), }); - Assert.Equal([3, 5, 7], actual.Order().ToArray()); + Assert.Equal(20, actual.Count); } [Fact] - public async Task Should_filter_with_equal_in_json_array() + public async Task Should_filter_by_string_contains_in_json_text_array() { var actual = await QueryAsync(new ClrQuery { - Filter = ClrFilter.Eq("Json.array", 3), + Filter = ClrFilter.Contains("Json.textArray", "5"), }); - Assert.Equal([3], actual.Order().ToArray()); + Assert.Equal([5, 15], actual.Order().ToArray()); } [Fact] - public async Task Should_filter_with_many_in_json_array() + public async Task Should_filter_by_string_starts_with_in_json_text_array() { var actual = await QueryAsync(new ClrQuery { - Filter = ClrFilter.In("Json.array", new List { 3, 5, 7 }), + Filter = ClrFilter.StartsWith("Json.textArray", "X5"), }); - Assert.Equal([3, 5, 7], actual.Order().ToArray()); + Assert.Equal([5], actual.Order().ToArray()); } [Fact] - public async Task Should_filter_with_many_in_mixed_json() + public async Task Should_filter_by_string_ends_with_in_json_text_array() { var actual = await QueryAsync(new ClrQuery { - Filter = ClrFilter.In("Json.mixed", new List { 2, 8, 14 }), + Filter = ClrFilter.EndsWith("Json.textArray", "5"), }); - Assert.Equal([2, 8, 14], actual.Order().ToArray()); + Assert.Equal([5, 15], actual.Order().ToArray()); } [Fact] - public async Task Should_filter_in_json_array() + public async Task Should_filter_by_string_contains_in_json_mixed_array() { var actual = await QueryAsync(new ClrQuery { - Filter = ClrFilter.And(ClrFilter.Gt("Json.array.1", 5), ClrFilter.Lt("Json.array.1", 16)), + Filter = ClrFilter.Contains("Json.mixedArray", "7"), }); - Assert.Equal(Range(6, 15), actual.Order().ToArray()); + Assert.Equal([7, 17], actual.Order().ToArray()); } [Fact] - public async Task Should_filter_in_mixed_json_array() + public async Task Should_filter_by_string_starts_with_in_json_mixed_array() { var actual = await QueryAsync(new ClrQuery { - Filter = ClrFilter.And(ClrFilter.Gt("Json.mixed.0", 5), ClrFilter.Lt("Json.mixed.0", 16)), + Filter = ClrFilter.StartsWith("Json.mixedArray", "T5"), }); - Assert.Contains(10, actual); + Assert.Equal([5], actual.Order().ToArray()); } [Fact] - public async Task Should_filter_by_boolean() + public async Task Should_filter_by_boolean_true() { var actual = await QueryAsync(new ClrQuery { @@ -406,7 +955,18 @@ public abstract class EFQueryTests(ISqlFixture fixture) } [Fact] - public async Task Should_filter_by_boolean_in_json() + public async Task Should_filter_by_boolean_false() + { + var actual = await QueryAsync(new ClrQuery + { + Filter = ClrFilter.Eq("Boolean", false), + }); + + Assert.Equal(Range(1, 10), actual.Order().ToArray()); + } + + [Fact] + public async Task Should_filter_by_boolean_true_in_json() { var actual = await QueryAsync(new ClrQuery { @@ -417,7 +977,51 @@ public abstract class EFQueryTests(ISqlFixture fixture) } [Fact] - public async Task Should_filter_by_boolean_in_mixed_json() + public async Task Should_filter_by_boolean_false_in_json() + { + var actual = await QueryAsync(new ClrQuery + { + Filter = ClrFilter.Eq("Json.boolean", false), + }); + + Assert.Equal(Range(1, 10), actual.Order().ToArray()); + } + + [Fact] + public async Task Should_filter_by_boolean_null_in_nullable_json() + { + var actual = await QueryAsync(new ClrQuery + { + Filter = ClrFilter.Eq("Json.booleanOrNull", ClrValue.Null), + }); + + Assert.Equal(Range(1, 10), actual.Order().ToArray()); + } + + [Fact] + public async Task Should_filter_by_boolean_not_null_in_nullable_json() + { + var actual = await QueryAsync(new ClrQuery + { + Filter = ClrFilter.Ne("Json.booleanOrNull", ClrValue.Null), + }); + + Assert.Equal(Range(11, 20), actual.Order().ToArray()); + } + + [Fact] + public async Task Should_filter_by_boolean_true_in_nullable_json() + { + var actual = await QueryAsync(new ClrQuery + { + Filter = ClrFilter.Eq("Json.booleanOrNull", true), + }); + + Assert.Equal(Range(11, 20), actual.Order().ToArray()); + } + + [Fact] + public async Task Should_filter_by_boolean_true_in_mixed_json() { var actual = await QueryAsync(new ClrQuery { @@ -428,69 +1032,190 @@ public abstract class EFQueryTests(ISqlFixture fixture) } [Fact] - public async Task Should_filter_by_string_contains() + public async Task Should_filter_by_boolean_false_in_mixed_json() { var actual = await QueryAsync(new ClrQuery { - Filter = ClrFilter.Contains("Text", "7"), + Filter = ClrFilter.Eq("Json.mixed", false), }); - Assert.Equal([7, 17], actual.Order().ToArray()); + Assert.Empty(actual); } [Fact] - public async Task Should_filter_by_string_contains_in_json() + public async Task Should_filter_by_boolean_true_in_json_boolean_array() { var actual = await QueryAsync(new ClrQuery { - Filter = ClrFilter.Contains("Json.text", "7"), + Filter = ClrFilter.Eq("Json.booleanArray", true), }); - Assert.Equal([7, 17], actual.Order().ToArray()); + Assert.Equal(Range(11, 20), actual.Order().ToArray()); } [Fact] - public async Task Should_filter_by_string_startsWith() + public async Task Should_filter_by_boolean_false_in_json_boolean_array() { var actual = await QueryAsync(new ClrQuery { - Filter = ClrFilter.StartsWith("Text", "Prefix5"), + Filter = ClrFilter.Eq("Json.booleanArray", false), }); - Assert.Equal([5], actual.Order().ToArray()); + Assert.Equal(Range(1, 15), actual.Order().ToArray()); } [Fact] - public async Task Should_filter_by_string_startsWith_in_json() + public async Task Should_filter_by_boolean_true_in_json_mixed_array() { var actual = await QueryAsync(new ClrQuery { - Filter = ClrFilter.StartsWith("Json.text", "Prefix5"), + Filter = ClrFilter.Eq("Json.mixedArray", true), }); - Assert.Equal([5], actual.Order().ToArray()); + Assert.Equal(Range(11, 20), actual.Order().ToArray()); } [Fact] - public async Task Should_filter_by_string_endWith() + public async Task Should_filter_by_boolean_false_in_json_mixed_array() { var actual = await QueryAsync(new ClrQuery { - Filter = ClrFilter.EndsWith("Text", "5Suffix"), + Filter = ClrFilter.Eq("Json.mixedArray", false), }); - Assert.Equal([5, 15], actual.Order().ToArray()); + Assert.Equal(Range(1, 10), actual.Order().ToArray()); } [Fact] - public async Task Should_filter_by_string_endWith_in_json() + public async Task Should_filter_by_null_on_number() { var actual = await QueryAsync(new ClrQuery { - Filter = ClrFilter.EndsWith("Json.text", "5Suffix"), + Filter = ClrFilter.Eq("NumberOrNull", ClrValue.Null), }); - Assert.Equal([5, 15], actual.Order().ToArray()); + Assert.Equal(Range(11, 20), actual.Order().ToArray()); + } + + [Fact] + public async Task Should_filter_by_not_null_on_number() + { + var actual = await QueryAsync(new ClrQuery + { + Filter = ClrFilter.Ne("NumberOrNull", ClrValue.Null), + }); + + Assert.Equal(Range(1, 10), actual.Order().ToArray()); + } + + [Fact] + public async Task Should_filter_by_null_on_boolean() + { + var actual = await QueryAsync(new ClrQuery + { + Filter = ClrFilter.Eq("BooleanOrNull", ClrValue.Null), + }); + + Assert.Equal(Range(1, 10), actual.Order().ToArray()); + } + + [Fact] + public async Task Should_filter_by_not_null_on_boolean() + { + var actual = await QueryAsync(new ClrQuery + { + Filter = ClrFilter.Ne("BooleanOrNull", ClrValue.Null), + }); + + Assert.Equal(Range(11, 20), actual.Order().ToArray()); + } + + [Fact] + public async Task Should_filter_by_null_in_json() + { + var actual = await QueryAsync(new ClrQuery + { + Filter = ClrFilter.Eq("Json.numberOrNull", ClrValue.Null), + }); + + Assert.Equal(Range(11, 20), actual.Order().ToArray()); + } + + [Fact] + public async Task Should_filter_by_not_null_in_json() + { + var actual = await QueryAsync(new ClrQuery + { + Filter = ClrFilter.Ne("Json.numberOrNull", ClrValue.Null), + }); + + Assert.Equal(Range(1, 10), actual.Order().ToArray()); + } + + [Fact] + public async Task Should_filter_by_null_on_text_in_nullable_json() + { + var actual = await QueryAsync(new ClrQuery + { + Filter = ClrFilter.Eq("Json.textOrNull", ClrValue.Null), + }); + + Assert.Equal(Range(11, 20), actual.Order().ToArray()); + } + + [Fact] + public async Task Should_filter_by_not_null_on_text_in_nullable_json() + { + var actual = await QueryAsync(new ClrQuery + { + Filter = ClrFilter.Ne("Json.textOrNull", ClrValue.Null), + }); + + Assert.Equal(Range(1, 10), actual.Order().ToArray()); + } + + [Fact] + public async Task Should_filter_by_null_in_mixed_json() + { + var actual = await QueryAsync(new ClrQuery + { + Filter = ClrFilter.Eq("Json.mixed", ClrValue.Null), + }); + + Assert.Equal([6, 12, 18], actual.Order().ToArray()); + } + + [Fact] + public async Task Should_filter_by_not_null_in_mixed_json() + { + var actual = await QueryAsync(new ClrQuery + { + Filter = ClrFilter.Ne("Json.mixed", ClrValue.Null), + }); + + Assert.Equal(AllExept(6, 12, 18), actual.Order().ToArray()); + } + + [Fact] + public async Task Should_filter_by_null_in_json_mixed_array() + { + var actual = await QueryAsync(new ClrQuery + { + Filter = ClrFilter.Eq("Json.mixedArray", ClrValue.Null), + }); + + Assert.Equal([3, 6, 9, 12, 15, 18], actual.Order().ToArray()); + } + + [Fact] + public async Task Should_filter_by_not_null_in_json_mixed_array() + { + var actual = await QueryAsync(new ClrQuery + { + Filter = ClrFilter.Ne("Json.mixedArray", ClrValue.Null), + }); + + Assert.Equal(20, actual.Count); } [Fact] @@ -508,6 +1233,27 @@ public abstract class EFQueryTests(ISqlFixture fixture) Assert.Equal(20, dbResult); } + [Fact] + public async Task Should_query_count_with_filter() + { + var dbContext = await CreateAndPrepareDbContextAsync(); + + var query = new ClrQuery + { + Filter = ClrFilter.Gt("Number", 10), + }; + + var builder = + new TestSqlBuilder(dbContext.Dialect, nameof(TestEntity)) + .Count() + .Where(query); + + var (sql, parameters) = builder.Compile(); + var dbResult = await dbContext.Database.SqlQueryRaw(sql, parameters).FirstOrDefaultAsync(); + + Assert.Equal(10, dbResult); + } + [Fact] public async Task Should_query_by_distance() { @@ -549,6 +1295,11 @@ public abstract class EFQueryTests(ISqlFixture fixture) Assert.Empty(dbResult); } + private static long[] AllExept(params long[] values) + { + return Range(1, 20).Except(values).ToArray(); + } + private static long[] Range(int from, int to) { var result = new List(); @@ -582,6 +1333,7 @@ public abstract class EFQueryTests(ISqlFixture fixture) .Where(query); var (sql, parameters) = queryBuilder.Compile(); + File.WriteAllText("D:\\last.json", sql); var dbResult = await dbContext.Set().FromSqlRaw(sql, parameters).ToListAsync(); return dbResult.Select(x => x.Number).ToList(); diff --git a/backend/tests/Squidex.Data.Tests/EntityFramework/TestHelpers/TestEntity.cs b/backend/tests/Squidex.Data.Tests/EntityFramework/TestHelpers/TestEntity.cs index ef1e22bdd..6e96820ad 100644 --- a/backend/tests/Squidex.Data.Tests/EntityFramework/TestHelpers/TestEntity.cs +++ b/backend/tests/Squidex.Data.Tests/EntityFramework/TestHelpers/TestEntity.cs @@ -41,13 +41,21 @@ public class TestJson public long? NumberOrNull { get; set; } + public long[] NumberArray { get; set; } + public string Text { get; set; } + public string? TextOrNull { get; set; } + + public string[] TextArray { get; set; } + public bool Boolean { get; set; } public bool? BooleanOrNull { get; set; } + public bool[] BooleanArray { get; set; } + public object? Mixed { get; set; } - public long[] Array { get; set; } + public object?[] MixedArray { get; set; } } diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 0e7970371..9f23110b4 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -41,7 +41,7 @@ "mousetrap": "1.6.5", "ng2-charts": "^8.0.0", "ngx-doc-viewer": "15.0.1", - "ngx-inline-filter": "^0.2.5", + "ngx-inline-filter": "^0.3.0", "ngx-scrollbar": "^19.1.4", "ngx-ui-tour-core": "16.0.0", "oidc-client-ts": "^3.4.1", @@ -439,6 +439,24 @@ } } }, + "node_modules/@angular-devkit/architect/node_modules/chokidar": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz", + "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "readdirp": "^5.0.0" + }, + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/@angular-devkit/architect/node_modules/picomatch": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", @@ -459,6 +477,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "engines": { "node": ">= 20.19.0" }, @@ -714,6 +733,24 @@ } } }, + "node_modules/@angular-devkit/build-angular/node_modules/chokidar": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz", + "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "readdirp": "^5.0.0" + }, + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/@angular-devkit/build-angular/node_modules/convert-source-map": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", @@ -792,6 +829,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "engines": { "node": ">= 20.19.0" }, @@ -848,6 +886,7 @@ "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-18.0.2.tgz", "integrity": "sha512-QXcEdfmODc0rKblBerk30yw70fypIkFm6gQBLJgsshpwc+TMA+fuMLcPQebOTzKLtD2tNUkk/7SrWPQIGqeXaA==", "dev": true, + "peer": true, "dependencies": { "ajv": "8.13.0", "ajv-formats": "3.0.1", @@ -875,6 +914,7 @@ "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", "dev": true, + "peer": true, "dependencies": { "ajv": "^8.0.0" }, @@ -891,13 +931,15 @@ "version": "3.2.1", "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.1.tgz", "integrity": "sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA==", - "dev": true + "dev": true, + "peer": true }, "node_modules/@angular-devkit/core/node_modules/picomatch": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", "dev": true, + "peer": true, "engines": { "node": ">=12" }, @@ -911,6 +953,7 @@ "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", "dev": true, "license": "Apache-2.0", + "peer": true, "dependencies": { "tslib": "^2.1.0" } @@ -919,6 +962,7 @@ "version": "0.7.4", "dev": true, "license": "BSD-3-Clause", + "peer": true, "engines": { "node": ">= 8" } @@ -1005,6 +1049,24 @@ } } }, + "node_modules/@angular-devkit/schematics/node_modules/chokidar": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz", + "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "readdirp": "^5.0.0" + }, + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/@angular-devkit/schematics/node_modules/picomatch": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", @@ -1025,6 +1087,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "engines": { "node": ">= 20.19.0" }, @@ -1122,6 +1185,24 @@ } } }, + "node_modules/@angular-eslint/builder/node_modules/chokidar": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz", + "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "readdirp": "^5.0.0" + }, + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/@angular-eslint/builder/node_modules/picomatch": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", @@ -1142,6 +1223,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "engines": { "node": ">= 20.19.0" }, @@ -1296,6 +1378,24 @@ } } }, + "node_modules/@angular-eslint/schematics/node_modules/chokidar": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz", + "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "readdirp": "^5.0.0" + }, + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/@angular-eslint/schematics/node_modules/ignore": { "version": "7.0.5", "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", @@ -1326,6 +1426,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "engines": { "node": ">= 20.19.0" }, @@ -1363,7 +1464,6 @@ "integrity": "sha512-TCb3qYOC/uXKZCo56cJ6N9sHeWdFhyVqrbbYfFjTi09081T6jllgHDZL5Ms7gOMNY8KywWGGbhxwvzeA0RwTgA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@angular-eslint/bundled-angular-compiler": "21.2.0", "eslint-scope": "^9.0.0" @@ -1613,7 +1713,6 @@ "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-21.1.3.tgz", "integrity": "sha512-jMiEKCcZMIAnyx2jxrJHmw5c7JXAiN56ErZ4X+OuQ5yFvYRocRVEs25I0OMxntcXNdPTJQvpGwGlhWhS0yDorg==", "license": "MIT", - "peer": true, "dependencies": { "parse5": "^8.0.0", "tslib": "^2.3.0" @@ -1644,7 +1743,6 @@ "integrity": "sha512-UPtDcpKyrKZRPfym9gTovcibPzl2O/Woy7B8sm45sAnjDH+jDUCcCvuIak7GpH47shQkC2J4yvnHZbD4c6XxcQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@angular-devkit/architect": "0.2101.3", "@angular-devkit/core": "21.1.3", @@ -1738,6 +1836,24 @@ } } }, + "node_modules/@angular/cli/node_modules/chokidar": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz", + "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "readdirp": "^5.0.0" + }, + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/@angular/cli/node_modules/picomatch": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", @@ -1758,6 +1874,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "engines": { "node": ">= 20.19.0" }, @@ -1794,7 +1911,6 @@ "resolved": "https://registry.npmjs.org/@angular/common/-/common-21.1.3.tgz", "integrity": "sha512-Wdbln/UqZM5oVnpfIydRdhhL8A9x3bKZ9Zy1/mM0q+qFSftPvmFZIXhEpFqbDwNYbGUhGzx7t8iULC4sVVp/zA==", "license": "MIT", - "peer": true, "dependencies": { "tslib": "^2.3.0" }, @@ -1811,7 +1927,6 @@ "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-21.1.3.tgz", "integrity": "sha512-gDNLh7MEf7Qf88ktZzS4LJQXCA5U8aQTfK9ak+0mi2ruZ0x4XSjQCro4H6OPKrrbq94+6GcnlSX5+oVIajEY3w==", "license": "MIT", - "peer": true, "dependencies": { "tslib": "^2.3.0" }, @@ -1824,7 +1939,6 @@ "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-21.1.3.tgz", "integrity": "sha512-nKxoQ89W2B1WdonNQ9kgRnvLNS6DAxDrRHBslsKTlV+kbdv7h59M9PjT4ZZ2sp1M/M8LiofnUfa/s2jd/xYj5w==", "license": "MIT", - "peer": true, "dependencies": { "@babel/core": "7.28.5", "@jridgewell/sourcemap-codec": "^1.4.14", @@ -1930,7 +2044,6 @@ "resolved": "https://registry.npmjs.org/@angular/core/-/core-21.1.3.tgz", "integrity": "sha512-TbhQxRC7Lb/3WBdm1n8KRsktmVEuGBBp0WRF5mq0Ze4s1YewIM6cULrSw9ACtcL5jdcq7c74ms+uKQsaP/gdcQ==", "license": "MIT", - "peer": true, "dependencies": { "tslib": "^2.3.0" }, @@ -2061,7 +2174,6 @@ "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-21.1.3.tgz", "integrity": "sha512-W+ZMXAioaP7CsACafBCHsIxiiKrRTPOlQ+hcC7XNBwy+bn5mjGONoCgLreQs76M8HNWLtr/OAUAr6h26OguOuA==", "license": "MIT", - "peer": true, "dependencies": { "tslib": "^2.3.0" }, @@ -2084,7 +2196,6 @@ "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-21.1.3.tgz", "integrity": "sha512-wWEjrNtJfxzZmbDWdJSyRau7NWpQ6IFM9QAyn7xH3cQDGCj+Gy9lTU5sUIYQc+7sx3nKWztolc7h/M5meYCTAg==", "license": "MIT", - "peer": true, "dependencies": { "tslib": "^2.3.0" }, @@ -2103,7 +2214,6 @@ "resolved": "https://registry.npmjs.org/@angular/platform-server/-/platform-server-21.1.3.tgz", "integrity": "sha512-o6S9t52d00PKC9nAjN3DXkLiY41iQvpLLl2DnerNU23njA7lF3mwH2+IJxVPB0EkR/H9rAJr+7bo/S9LUoU7xw==", "license": "MIT", - "peer": true, "dependencies": { "tslib": "^2.3.0", "xhr2": "^0.2.0" @@ -2124,7 +2234,6 @@ "resolved": "https://registry.npmjs.org/@angular/router/-/router-21.1.3.tgz", "integrity": "sha512-uAw4LAMHXAPCe4SywhlUEWjMYVbbLHwTxLyduSp1b+9aVwep0juy5O/Xttlxd/oigVe0NMnOyJG9y1Br/ubnrg==", "license": "MIT", - "peer": true, "dependencies": { "tslib": "^2.3.0" }, @@ -2230,7 +2339,6 @@ } ], "license": "MIT", - "peer": true, "engines": { "node": ">=18" }, @@ -2254,7 +2362,6 @@ } ], "license": "MIT", - "peer": true, "engines": { "node": ">=18" } @@ -2308,7 +2415,6 @@ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.6.tgz", "integrity": "sha512-H3mcG6ZDLTlYfaSNi0iOKkigqMFvkTKlGUYlD8GW7nNOYRrevuA46iTypPyv+06V3fEmvvazfntkBU34L0azAw==", "license": "MIT", - "peer": true, "dependencies": { "@babel/code-frame": "^7.28.6", "@babel/generator": "^7.28.6", @@ -3989,7 +4095,6 @@ "integrity": "sha512-CYDD3SOtsHtyXeEORYRx2qBtpDJFjRTGXUtmNEMGyzYOKj1TE3tycdlho7kA1Ufx9OYWZzg52QFBGALTirzDSw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@keyv/serialize": "^1.1.1" } @@ -4035,6 +4140,7 @@ "resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.5.2.tgz", "integrity": "sha512-FVqsPqtPWKVVL3dPSxy8wEF/ymIEuVzF1PK3VbUgrxXpJUSHQWWZz4JMToquRxnkw+36LTamCZG2iua2Ptq0fA==", "license": "MIT", + "peer": true, "dependencies": { "@marijn/find-cluster-break": "^1.0.0" } @@ -4044,6 +4150,7 @@ "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.37.1.tgz", "integrity": "sha512-Qy4CAUwngy/VQkEz0XzMKVRcckQuqLYWKqVpDDDghBe5FSXSqfVrJn49nw3ePZHxRUz4nRmb05Lgi+9csWo4eg==", "license": "MIT", + "peer": true, "dependencies": { "@codemirror/state": "^6.5.0", "crelt": "^1.0.6", @@ -4056,6 +4163,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "engines": { "node": ">=0.1.90" } @@ -4363,7 +4471,6 @@ "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "readdirp": "^5.0.0" }, @@ -4766,7 +4873,6 @@ } ], "license": "MIT", - "peer": true, "engines": { "node": ">=20.19.0" }, @@ -4807,7 +4913,6 @@ } ], "license": "MIT", - "peer": true, "engines": { "node": ">=20.19.0" } @@ -4895,7 +5000,6 @@ "node_modules/@egjs/hammerjs": { "version": "2.0.17", "license": "MIT", - "peer": true, "dependencies": { "@types/hammerjs": "^2.0.36" }, @@ -6070,7 +6174,6 @@ "integrity": "sha512-Dx/y9bCQcXLI5ooQ5KyvA4FTgeo2jYj/7plWfV5Ak5wDPKQZgudKez2ixyfz7tKXzcJciTxqLeK7R9HItwiByg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@inquirer/checkbox": "^4.3.2", "@inquirer/confirm": "^5.1.21", @@ -6722,7 +6825,8 @@ "node_modules/@kurkle/color": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/@kurkle/color/-/color-0.3.1.tgz", - "integrity": "sha512-hW0GwZj06z/ZFUW2Espl7toVDjghJN+EKqyXzPSV8NV89d5BYp5rRMBJoc+aUN0x5OXDMeRQHazejr2Xmqj2tw==" + "integrity": "sha512-hW0GwZj06z/ZFUW2Espl7toVDjghJN+EKqyXzPSV8NV89d5BYp5rRMBJoc+aUN0x5OXDMeRQHazejr2Xmqj2tw==", + "peer": true }, "node_modules/@leichtgewicht/ip-codec": { "version": "2.0.5", @@ -6735,13 +6839,15 @@ "version": "1.2.3", "resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.2.3.tgz", "integrity": "sha512-w7ojc8ejBqr2REPsWxJjrMFsA/ysDCFICn8zEOR9mrqzOu2amhITYuLD8ag6XZf0CFXDrhKqw7+tW8cX66NaDA==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/@lezer/highlight": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.2.1.tgz", "integrity": "sha512-Z5duk4RN/3zuVO7Jq0pGLJ3qynpxUVsh7IbUbGj88+uV2ApSAn6kWg2au3iJb+0Zi7kKtqffIESgNcRXWZWmSA==", "license": "MIT", + "peer": true, "dependencies": { "@lezer/common": "^1.0.0" } @@ -6751,6 +6857,7 @@ "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.4.2.tgz", "integrity": "sha512-pu0K1jCIdnQ12aWNaAVU5bzi7Bd1w54J3ECgANPmYLtQKP0HBj2cE/5coBD66MT10xbtIuUr7tg0Shbsvk0mDA==", "license": "MIT", + "peer": true, "dependencies": { "@lezer/common": "^1.0.0" } @@ -6888,7 +6995,8 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/@marijn/find-cluster-break/-/find-cluster-break-1.0.2.tgz", "integrity": "sha512-l0h88YhZFyKdXIFNfSWpyjStDjGHwZ/U7iobcK1cQQD8sejsONdQtTVU+1wVN1PBw40PiiHB1vA5S7VTfQiP9g==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/@modelcontextprotocol/sdk": { "version": "1.26.0", @@ -9608,6 +9716,24 @@ } } }, + "node_modules/@schematics/angular/node_modules/chokidar": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz", + "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "readdirp": "^5.0.0" + }, + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/@schematics/angular/node_modules/picomatch": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", @@ -9628,6 +9754,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "engines": { "node": ">= 20.19.0" }, @@ -9772,7 +9899,8 @@ "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz", "integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==", "dev": true, - "optional": true + "optional": true, + "peer": true }, "node_modules/@standard-schema/spec": { "version": "1.1.0", @@ -10001,7 +10129,6 @@ "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-9.3.4.tgz", "integrity": "sha512-FlS4ZWlp97iiNWig0Muq8p+3rVDjRiYE+YKGbAqXOu9nwJFFOdL00kFpz42M+4huzYi86vAK1sOOfyOG45muIQ==", "dev": true, - "peer": true, "dependencies": { "@babel/code-frame": "^7.10.4", "@babel/runtime": "^7.12.5", @@ -10307,6 +10434,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "dependencies": { "@types/node": "*" } @@ -10443,7 +10571,6 @@ "integrity": "sha512-CPrnr8voK8vC6eEtyRzvMpgp3VyVRhgclonE7qYi6P9sXwYb59ucfrnmFBTaP0yUi8Gk4yZg/LlTJULGxvTNsg==", "devOptional": true, "license": "MIT", - "peer": true, "dependencies": { "undici-types": "~7.16.0" } @@ -10478,7 +10605,6 @@ "integrity": "sha512-KkiJeU6VbYbUOp5ITMIc7kBfqlYkKA5KhEHVrGMmUUMt7NeaZg65ojdPk+FtNrBAOXNVM5QM72jnADjM+XVRAQ==", "devOptional": true, "license": "MIT", - "peer": true, "dependencies": { "csstype": "^3.2.2" } @@ -10489,7 +10615,6 @@ "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", "devOptional": true, "license": "MIT", - "peer": true, "peerDependencies": { "@types/react": "^19.2.0" } @@ -10616,7 +10741,6 @@ "integrity": "sha512-BtE0k6cjwjLZoZixN0t5AKP0kSzlGu7FctRXYuPAm//aaiZhmfq1JwdYpYr1brzEspYyFeF+8XF5j2VK6oalrA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.54.0", "@typescript-eslint/types": "8.54.0", @@ -10799,7 +10923,6 @@ "integrity": "sha512-PDUI9R1BVjqu7AUDsRBbKMtwmjWcn4J3le+5LpcFgWULN3LvHC5rkc9gCVxbrsrGmO1jfPybN5s6h4Jy+OnkAA==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, @@ -10906,7 +11029,6 @@ "integrity": "sha512-9Cnda8GS57AQakvRyG0PTejJNlA2xhvyNtEVIMlDWOOeEyBkYWhGPnfrIAnqxLMTSTo6q8g12XVjjev5l1NvMA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", "@typescript-eslint/scope-manager": "8.54.0", @@ -11424,7 +11546,6 @@ "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, "license": "MIT", - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -11509,7 +11630,6 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.13.0.tgz", "integrity": "sha512-PRA911Blj99jR5RMeTunVbNXMF6Lp4vZXnk5GQjcnUWUTsrXtekg/pnmFFI2u/I36Y/2bITGS30GZCXei6uNkA==", "dev": true, - "peer": true, "dependencies": { "fast-deep-equal": "^3.1.3", "json-schema-traverse": "^1.0.0", @@ -12039,6 +12159,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "engines": { "node": "^4.5.0 || >= 5.9" } @@ -12389,7 +12510,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "baseline-browser-mapping": "^2.9.0", "caniuse-lite": "^1.0.30001759", @@ -13139,6 +13259,7 @@ "dev": true, "license": "ISC", "optional": true, + "peer": true, "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.0", @@ -13180,8 +13301,7 @@ "version": "5.65.19", "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.65.19.tgz", "integrity": "sha512-+aFkvqhaAVr1gferNMuN8vkTSrWIFvzlMV9I2KBLCWS2WpZ2+UAkZjlMZmEuT+gcXTi6RrGQCkWq1/bDtGqhIA==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/codemirror-graphql": { "version": "2.2.2", @@ -13587,7 +13707,8 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.6.tgz", "integrity": "sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/cropperjs": { "version": "1.6.2", @@ -13755,7 +13876,8 @@ "version": "1.0.1", "dev": true, "license": "MIT", - "optional": true + "optional": true, + "peer": true }, "node_modules/damerau-levenshtein": { "version": "1.0.8", @@ -13855,6 +13977,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "engines": { "node": ">=4.0" } @@ -14074,7 +14197,8 @@ "version": "0.0.1", "dev": true, "license": "MIT", - "optional": true + "optional": true, + "peer": true }, "node_modules/dns-packet": { "version": "5.6.1", @@ -14112,6 +14236,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "dependencies": { "custom-event": "~1.0.0", "ent": "~2.2.0", @@ -14314,6 +14439,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "dependencies": { "@types/cors": "^2.8.12", "@types/node": ">=10.0.0", @@ -14336,6 +14462,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "engines": { "node": ">=10.0.0" } @@ -14358,7 +14485,8 @@ "version": "2.2.0", "dev": true, "license": "MIT", - "optional": true + "optional": true, + "peer": true }, "node_modules/entities": { "version": "2.2.0", @@ -14693,7 +14821,6 @@ "integrity": "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", @@ -15549,7 +15676,8 @@ "version": "3.0.2", "dev": true, "license": "MIT", - "optional": true + "optional": true, + "peer": true }, "node_modules/fancy-log": { "version": "2.0.0", @@ -15811,7 +15939,6 @@ "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -16036,7 +16163,8 @@ "version": "1.0.0", "dev": true, "license": "ISC", - "optional": true + "optional": true, + "peer": true }, "node_modules/fsevents": { "version": "2.3.3", @@ -16198,6 +16326,7 @@ "dev": true, "license": "ISC", "optional": true, + "peer": true, "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -16399,7 +16528,6 @@ "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.12.0.tgz", "integrity": "sha512-DKKrynuQRne0PNpEbzuEdHlYOMksHSUI8Zc9Unei5gTsMNA2/vMpoMz/yKba50pejK56qj98qM0SjYxAKi13gQ==", "license": "MIT", - "peer": true, "engines": { "node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0" } @@ -16426,7 +16554,6 @@ "resolved": "https://registry.npmjs.org/graphql-ws/-/graphql-ws-6.0.7.tgz", "integrity": "sha512-yoLRW+KRlDmnnROdAu7sX77VNLC0bsFoZyGQJLy1cF+X/SkLg/fWkRGrEEYQK8o2cafJ2wmEaMqMEZB3U3DYDg==", "license": "MIT", - "peer": true, "engines": { "node": ">=20" }, @@ -16589,7 +16716,6 @@ "integrity": "sha512-eVkB/CYCCei7K2WElZW9yYQFWssG0DhaDhVvr7wy5jJ22K+ck8fWW0EsLpB0sITUTvPnc97+rrbQqIr5iqiy9Q==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=16.9.0" } @@ -16728,7 +16854,6 @@ "version": "5.5.0", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@types/html-minifier-terser": "^6.0.0", "html-minifier-terser": "^6.0.2", @@ -17120,6 +17245,7 @@ "dev": true, "license": "ISC", "optional": true, + "peer": true, "dependencies": { "once": "^1.3.0", "wrappy": "1" @@ -17801,6 +17927,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "engines": { "node": ">= 8.0.0" }, @@ -18066,6 +18193,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "dependencies": { "@colors/colors": "1.5.0", "body-parser": "^1.19.0", @@ -18112,6 +18240,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "dependencies": { "minimist": "^1.2.6" }, @@ -18124,6 +18253,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "dependencies": { "cliui": "^7.0.2", "escalade": "^3.1.1", @@ -18142,6 +18272,7 @@ "dev": true, "license": "ISC", "optional": true, + "peer": true, "engines": { "node": ">=10" } @@ -18210,8 +18341,7 @@ "node_modules/leaflet": { "version": "1.9.4", "resolved": "https://registry.npmjs.org/leaflet/-/leaflet-1.9.4.tgz", - "integrity": "sha512-nxS1ynzJOmOlHp+iL3FyWqK89GtNL8U8rvlMOsQdTTssxZwCXh8N2NB3GDQOL+YR3XnWyZAxwQixURb+FA74PA==", - "peer": true + "integrity": "sha512-nxS1ynzJOmOlHp+iL3FyWqK89GtNL8U8rvlMOsQdTTssxZwCXh8N2NB3GDQOL+YR3XnWyZAxwQixURb+FA74PA==" }, "node_modules/leaflet-control-geocoder": { "version": "3.3.1", @@ -18231,7 +18361,6 @@ "integrity": "sha512-j1n1IuTX1VQjIy3tT7cyGbX7nvQOsFLoIqobZv4ttI5axP923gA44zUj6miiA6R5Aoms4sEGVIIcucXUbRI14g==", "dev": true, "license": "Apache-2.0", - "peer": true, "dependencies": { "copy-anything": "^2.0.1", "parse-node-version": "^1.0.1", @@ -18390,7 +18519,6 @@ "integrity": "sha512-ME4Fb83LgEgwNw96RKNvKV4VTLuXfoKudAmm2lP8Kk87KaMK0/Xrx/aAkMWmT8mDb+3MlFDspfbCs7adjRxA2g==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "cli-truncate": "^5.0.0", "colorette": "^2.0.20", @@ -18750,6 +18878,7 @@ "dev": true, "license": "Apache-2.0", "optional": true, + "peer": true, "dependencies": { "date-format": "^4.0.14", "debug": "^4.3.4", @@ -19095,6 +19224,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "bin": { "mime": "cli.js" }, @@ -19624,9 +19754,9 @@ } }, "node_modules/ngx-inline-filter": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/ngx-inline-filter/-/ngx-inline-filter-0.2.5.tgz", - "integrity": "sha512-lBucvPs+VbhA6SR9wb6akXUHBT6RyHHLAOa+Et1wJ6sb8CQzpy2xkE+bvSulQb+QQwFIFUS2bqusBPa2d7t+Nw==", + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/ngx-inline-filter/-/ngx-inline-filter-0.3.0.tgz", + "integrity": "sha512-Yb4VIt4+QrEXr5LYQSEx0nQlM/Aj0udGk1ncdGVKNYY6YwrjgCVk8UiJFk+b1WMWWJW2O3uayl/JTkBMeqsHwA==", "dependencies": { "tslib": "^2.3.0" }, @@ -19642,7 +19772,6 @@ "resolved": "https://registry.npmjs.org/ngx-scrollbar/-/ngx-scrollbar-19.1.4.tgz", "integrity": "sha512-VzmLli1Uq+tZ40s5BpBDVO5mxjeNL7L7JbVluuokKsrIfi1GmXmkx69iz0zruyVWmyzU5VeuiqhMobPYazGKOQ==", "license": "MIT", - "peer": true, "dependencies": { "tslib": "^2.3.0" }, @@ -20640,6 +20769,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "engines": { "node": ">=0.10.0" } @@ -20826,7 +20956,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", @@ -21005,7 +21134,6 @@ "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" @@ -21054,7 +21182,6 @@ "integrity": "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==", "dev": true, "license": "MIT", - "peer": true, "bin": { "prettier": "bin/prettier.cjs" }, @@ -21240,6 +21367,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "engines": { "node": ">=0.9" } @@ -21314,7 +21442,6 @@ "version": "18.3.1", "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", - "peer": true, "dependencies": { "loose-envify": "^1.1.0" }, @@ -21335,7 +21462,6 @@ "version": "18.3.1", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", - "peer": true, "dependencies": { "loose-envify": "^1.1.0", "scheduler": "^0.23.2" @@ -21607,6 +21733,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "engines": { "node": ">=0.10.0" } @@ -21752,6 +21879,7 @@ "dev": true, "license": "ISC", "optional": true, + "peer": true, "dependencies": { "glob": "^7.1.3" }, @@ -21931,7 +22059,6 @@ "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", "license": "Apache-2.0", - "peer": true, "dependencies": { "tslib": "^2.1.0" } @@ -22725,6 +22852,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "dependencies": { "accepts": "~1.3.4", "base64id": "~2.0.0", @@ -22745,6 +22873,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "dependencies": { "debug": "~4.3.4", "ws": "~8.17.1" @@ -22756,6 +22885,7 @@ "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==", "dev": true, "optional": true, + "peer": true, "dependencies": { "@socket.io/component-emitter": "~3.1.0", "debug": "~4.3.1" @@ -23025,7 +23155,6 @@ "integrity": "sha512-LFKSuZyF6EW2/Kkl5d7CvqgwhXXfuWv+aLBuoc616boLKJ3mxXuea+GxIgfk02NEyTKctJ0QsnSh5pAomf6Qkg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@storybook/global": "^5.0.0", "@storybook/icons": "^2.0.1", @@ -23169,6 +23298,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "dependencies": { "date-format": "^4.0.14", "debug": "^4.3.4", @@ -23183,6 +23313,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^4.0.0", @@ -23197,6 +23328,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "optionalDependencies": { "graceful-fs": "^4.1.6" } @@ -23206,6 +23338,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "engines": { "node": ">= 4.0.0" } @@ -23400,7 +23533,8 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.1.2.tgz", "integrity": "sha512-wnD1HyVqpJUI2+eKZ+eo1UwghftP6yuFheBqqe+bWCotBjC2K1YnteJILRMs3SM4V/0dLEW1SC27MWP5y+mwmw==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/stylelint": { "version": "17.1.1", @@ -23418,7 +23552,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "@csstools/css-parser-algorithms": "^4.0.0", "@csstools/css-syntax-patches-for-csstree": "^1.0.25", @@ -24028,7 +24161,6 @@ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, @@ -24082,6 +24214,7 @@ "integrity": "sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==", "dev": true, "optional": true, + "peer": true, "engines": { "node": ">=14.14" } @@ -24295,8 +24428,7 @@ "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "license": "0BSD", - "peer": true + "license": "0BSD" }, "node_modules/tuf-js": { "version": "4.1.0", @@ -24488,7 +24620,6 @@ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "license": "Apache-2.0", - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -24518,6 +24649,7 @@ ], "license": "MIT", "optional": true, + "peer": true, "bin": { "ua-parser-js": "script/cli.js" }, @@ -24796,7 +24928,6 @@ "node_modules/uuid": { "version": "8.3.2", "license": "MIT", - "peer": true, "bin": { "uuid": "dist/bin/uuid" } @@ -24835,7 +24966,6 @@ "resolved": "https://registry.npmjs.org/video.js/-/video.js-8.23.6.tgz", "integrity": "sha512-qjS3HTDo7iapedJuso62scA303i+6CaCUnwyRr8GYd/BYAp7XGb7InUMw2Eu6zrN6IWooPOb78NzyMyjRbIN+Q==", "license": "Apache-2.0", - "peer": true, "dependencies": { "@babel/runtime": "^7.12.5", "@videojs/http-streaming": "^3.17.2", @@ -24885,7 +25015,6 @@ "resolved": "https://registry.npmjs.org/vis-data/-/vis-data-8.0.3.tgz", "integrity": "sha512-jhnb6rJNqkKR1Qmlay0VuDXY9ZlvAnYN1udsrP4U+krgZEq7C0yNSKdZqmnCe13mdnf9AdVcdDGFOzy2mpPoqw==", "license": "(Apache-2.0 OR MIT)", - "peer": true, "funding": { "type": "opencollective", "url": "https://opencollective.com/visjs" @@ -24918,7 +25047,6 @@ "resolved": "https://registry.npmjs.org/vis-util/-/vis-util-6.0.0.tgz", "integrity": "sha512-qtpts3HRma0zPe4bO7t9A2uejkRNj8Z2Tb6do6lN85iPNWExFkUiVhdAq5uLGIUqBFduyYeqWJKv/jMkxX0R5g==", "license": "(Apache-2.0 OR MIT)", - "peer": true, "engines": { "node": ">=8" }, @@ -24937,7 +25065,6 @@ "integrity": "sha512-dZwN5L1VlUBewiP6H9s2+B3e3Jg96D0vzN+Ry73sOefebhYr9f94wwkMNN/9ouoU8pV1BqA1d1zGk8928cx0rg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "esbuild": "^0.27.0", "fdir": "^6.5.0", @@ -25046,7 +25173,6 @@ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, @@ -25060,7 +25186,6 @@ "integrity": "sha512-hOQuK7h0FGKgBAas7v0mSAsnvrIgAvWmRFjmzpJ7SwFHH3g1k2u37JtYwOwmEKhK6ZO3v9ggDBBm0La1LCK4uQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@vitest/expect": "4.0.18", "@vitest/mocker": "4.0.18", @@ -25226,6 +25351,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "engines": { "node": ">=0.10.0" } @@ -25240,7 +25366,8 @@ "version": "2.2.8", "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz", "integrity": "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/w3c-xmlserializer": { "version": "5.0.0", @@ -25303,7 +25430,6 @@ "integrity": "sha512-gX/dMkRQc7QOMzgTe6KsYFM7DxeIONQSui1s0n/0xht36HvrgbxtM1xBlgx596NbpHuQU8P7QpKwrZYwUX48nw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@types/eslint-scope": "^3.7.7", "@types/estree": "^1.0.8", @@ -25453,7 +25579,6 @@ "integrity": "sha512-QcQ72gh8a+7JO63TAx/6XZf/CWhgMzu5m0QirvPfGvptOusAxG12w2+aua1Jkjr7hzaWDnJ2n6JFeexMHI+Zjg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@types/bonjour": "^3.5.13", "@types/connect-history-api-fallback": "^1.5.4", @@ -26278,6 +26403,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -26322,6 +26448,29 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/ws": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", + "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", + "license": "MIT", + "optional": true, + "peer": true, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/wsl-utils": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/wsl-utils/-/wsl-utils-0.3.1.tgz", @@ -26620,7 +26769,6 @@ "integrity": "sha512-k7Nwx6vuWx1IJ9Bjuf4Zt1PEllcwe7cls3VNzm4CQ1/hgtFUK2bRNG3rvnpPUhFjmqJKAKtjV576KnUkHocg/g==", "dev": true, "license": "MIT", - "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" } @@ -26639,8 +26787,7 @@ "version": "0.16.0", "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.16.0.tgz", "integrity": "sha512-LqLPpIQANebrlxY6jKcYKdgN5DTXyyHAKnnWWjE5pPfEQ4n7j5zn7mOEEpwNZVKGqx3kKKmvplEmoBrvpgROTA==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/zustand": { "version": "5.0.5", diff --git a/frontend/package.json b/frontend/package.json index ae5c1fb42..e7f48cce0 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -50,7 +50,7 @@ "mousetrap": "1.6.5", "ng2-charts": "^8.0.0", "ngx-doc-viewer": "15.0.1", - "ngx-inline-filter": "^0.2.5", + "ngx-inline-filter": "^0.3.0", "ngx-scrollbar": "^19.1.4", "ngx-ui-tour-core": "16.0.0", "oidc-client-ts": "^3.4.1", diff --git a/frontend/src/app/shared/components/search/search-form.component.ts b/frontend/src/app/shared/components/search/search-form.component.ts index 6961a1582..7bd8d8c16 100644 --- a/frontend/src/app/shared/components/search/search-form.component.ts +++ b/frontend/src/app/shared/components/search/search-form.component.ts @@ -157,6 +157,8 @@ export class SearchFormComponent { let args; let component: Type> | undefined = undefined; + let operators = [...model.operators[field.schema.type]]; + const { type, extra } = field.schema; if (field.schema.type === 'Boolean') { component = BooleanValue; @@ -176,6 +178,7 @@ export class SearchFormComponent { } else if (type === 'String' && !extra) { component = StringValue; } else if (type === 'StringArray' && extra?.schemaIds) { + operators = ['eq']; args = { editor: 'Reference', schemaIds: extra.schemaIds }; } else if (type === 'StringArray') { component = StringValue; @@ -189,7 +192,7 @@ export class SearchFormComponent { defaultValue: null, description: field.description, label: field.path, - operators: model.operators[field.schema.type] as any, + operators, path: field.path, };