Browse Source

Fix queries.

pull/1295/head
Sebastian Stehle 6 months ago
parent
commit
954d142d61
  1. 37
      backend/src/Squidex.Data.EntityFramework/Providers/MySql/json_function.sql
  2. 43
      backend/src/Squidex.Data.EntityFramework/Providers/Postgres/json_function.sql
  3. 15
      backend/src/Squidex.Data.EntityFramework/Providers/SqlServer/JsonFunction.cs
  4. 178
      backend/src/Squidex.Data.EntityFramework/Providers/SqlServer/json_function.sql
  5. 88
      backend/tests/Squidex.Data.Tests/EntityFramework/Infrastructure/Queries/EFQueryTests.cs
  6. 1
      frontend/src/app/shared/components/comments/comments.component.html
  7. 1
      frontend/src/app/shared/components/comments/comments.component.ts

37
backend/src/Squidex.Data.EntityFramework/Providers/MySql/json_function.sql

@ -60,9 +60,10 @@ BEGIN
IF JSON_TYPE(val) = 'ARRAY' THEN
RETURN EXISTS (
SELECT 1 FROM JSON_TABLE(val, '$[*]' COLUMNS (elem JSON PATH '$')) AS jt
WHERE JSON_UNQUOTE(jt.elem) = target
WHERE JSON_TYPE(jt.elem) = 'STRING' AND JSON_UNQUOTE(jt.elem) = target
);
END IF;
IF JSON_TYPE(val) != 'STRING' THEN RETURN 0; END IF;
RETURN JSON_UNQUOTE(val) = target;
END;;
@ -75,9 +76,10 @@ BEGIN
IF JSON_TYPE(val) = 'ARRAY' THEN
RETURN NOT EXISTS (
SELECT 1 FROM JSON_TABLE(val, '$[*]' COLUMNS (elem JSON PATH '$')) AS jt
WHERE JSON_UNQUOTE(jt.elem) = target
WHERE JSON_TYPE(jt.elem) = 'STRING' AND JSON_UNQUOTE(jt.elem) = target
);
END IF;
IF JSON_TYPE(val) != 'STRING' THEN RETURN 1; END IF;
RETURN JSON_UNQUOTE(val) != target;
END;;
@ -90,9 +92,10 @@ BEGIN
IF JSON_TYPE(val) = 'ARRAY' THEN
RETURN EXISTS (
SELECT 1 FROM JSON_TABLE(val, '$[*]' COLUMNS (elem JSON PATH '$')) AS jt
WHERE JSON_UNQUOTE(jt.elem) < target
WHERE JSON_TYPE(jt.elem) = 'STRING' AND JSON_UNQUOTE(jt.elem) < target
);
END IF;
IF JSON_TYPE(val) != 'STRING' THEN RETURN 0; END IF;
RETURN JSON_UNQUOTE(val) < target;
END;;
@ -105,9 +108,10 @@ BEGIN
IF JSON_TYPE(val) = 'ARRAY' THEN
RETURN EXISTS (
SELECT 1 FROM JSON_TABLE(val, '$[*]' COLUMNS (elem JSON PATH '$')) AS jt
WHERE JSON_UNQUOTE(jt.elem) <= target
WHERE JSON_TYPE(jt.elem) = 'STRING' AND JSON_UNQUOTE(jt.elem) <= target
);
END IF;
IF JSON_TYPE(val) != 'STRING' THEN RETURN 0; END IF;
RETURN JSON_UNQUOTE(val) <= target;
END;;
@ -120,9 +124,10 @@ BEGIN
IF JSON_TYPE(val) = 'ARRAY' THEN
RETURN EXISTS (
SELECT 1 FROM JSON_TABLE(val, '$[*]' COLUMNS (elem JSON PATH '$')) AS jt
WHERE JSON_UNQUOTE(jt.elem) > target
WHERE JSON_TYPE(jt.elem) = 'STRING' AND JSON_UNQUOTE(jt.elem) > target
);
END IF;
IF JSON_TYPE(val) != 'STRING' THEN RETURN 0; END IF;
RETURN JSON_UNQUOTE(val) > target;
END;;
@ -135,9 +140,10 @@ BEGIN
IF JSON_TYPE(val) = 'ARRAY' THEN
RETURN EXISTS (
SELECT 1 FROM JSON_TABLE(val, '$[*]' COLUMNS (elem JSON PATH '$')) AS jt
WHERE JSON_UNQUOTE(jt.elem) >= target
WHERE JSON_TYPE(jt.elem) = 'STRING' AND JSON_UNQUOTE(jt.elem) >= target
);
END IF;
IF JSON_TYPE(val) != 'STRING' THEN RETURN 0; END IF;
RETURN JSON_UNQUOTE(val) >= target;
END;;
@ -150,9 +156,10 @@ BEGIN
IF JSON_TYPE(val) = 'ARRAY' THEN
RETURN EXISTS (
SELECT 1 FROM JSON_TABLE(val, '$[*]' COLUMNS (elem JSON PATH '$')) AS jt
WHERE JSON_UNQUOTE(jt.elem) LIKE CONCAT('%', target, '%')
WHERE JSON_TYPE(jt.elem) = 'STRING' AND JSON_UNQUOTE(jt.elem) LIKE CONCAT('%', target, '%')
);
END IF;
IF JSON_TYPE(val) != 'STRING' THEN RETURN 0; END IF;
RETURN JSON_UNQUOTE(val) LIKE CONCAT('%', target, '%');
END;;
@ -165,9 +172,10 @@ BEGIN
IF JSON_TYPE(val) = 'ARRAY' THEN
RETURN EXISTS (
SELECT 1 FROM JSON_TABLE(val, '$[*]' COLUMNS (elem JSON PATH '$')) AS jt
WHERE JSON_UNQUOTE(jt.elem) LIKE CONCAT(target, '%')
WHERE JSON_TYPE(jt.elem) = 'STRING' AND JSON_UNQUOTE(jt.elem) LIKE CONCAT(target, '%')
);
END IF;
IF JSON_TYPE(val) != 'STRING' THEN RETURN 0; END IF;
RETURN JSON_UNQUOTE(val) LIKE CONCAT(target, '%');
END;;
@ -180,9 +188,10 @@ BEGIN
IF JSON_TYPE(val) = 'ARRAY' THEN
RETURN EXISTS (
SELECT 1 FROM JSON_TABLE(val, '$[*]' COLUMNS (elem JSON PATH '$')) AS jt
WHERE JSON_UNQUOTE(jt.elem) LIKE CONCAT('%', target)
WHERE JSON_TYPE(jt.elem) = 'STRING' AND JSON_UNQUOTE(jt.elem) LIKE CONCAT('%', target)
);
END IF;
IF JSON_TYPE(val) != 'STRING' THEN RETURN 0; END IF;
RETURN JSON_UNQUOTE(val) LIKE CONCAT('%', target);
END;;
@ -195,9 +204,10 @@ BEGIN
IF JSON_TYPE(val) = 'ARRAY' THEN
RETURN EXISTS (
SELECT 1 FROM JSON_TABLE(val, '$[*]' COLUMNS (elem JSON PATH '$')) AS jt
WHERE JSON_UNQUOTE(jt.elem) REGEXP target
WHERE JSON_TYPE(jt.elem) = 'STRING' AND JSON_UNQUOTE(jt.elem) REGEXP target
);
END IF;
IF JSON_TYPE(val) != 'STRING' THEN RETURN 0; END IF;
RETURN JSON_UNQUOTE(val) REGEXP target;
END;;
@ -210,9 +220,10 @@ BEGIN
IF JSON_TYPE(val) = 'ARRAY' THEN
RETURN EXISTS (
SELECT 1 FROM JSON_TABLE(val, '$[*]' COLUMNS (elem JSON PATH '$')) AS jt
WHERE JSON_CONTAINS(targets, jt.elem)
WHERE JSON_TYPE(jt.elem) = 'STRING' AND JSON_CONTAINS(targets, jt.elem)
);
END IF;
IF JSON_TYPE(val) != 'STRING' THEN RETURN 0; END IF;
RETURN JSON_CONTAINS(targets, val);
END;;
@ -252,7 +263,7 @@ BEGIN
END = target
);
END IF;
IF JSON_TYPE(val) NOT IN ('INTEGER', 'DOUBLE', 'DECIMAL') THEN RETURN 0; END IF;
IF JSON_TYPE(val) NOT IN ('INTEGER', 'DOUBLE', 'DECIMAL') THEN RETURN 1; END IF;
RETURN CAST(JSON_UNQUOTE(val) AS DECIMAL(65, 10)) != target;
END;;
@ -381,7 +392,7 @@ BEGIN
WHERE CASE WHEN JSON_TYPE(jt.elem) = 'BOOLEAN' THEN jt.elem END = target_json
);
END IF;
IF JSON_TYPE(val) != 'BOOLEAN' THEN RETURN 0; END IF;
IF JSON_TYPE(val) != 'BOOLEAN' THEN RETURN 1; END IF;
RETURN val != target_json;
END;;

43
backend/src/Squidex.Data.EntityFramework/Providers/Postgres/json_function.sql

@ -27,9 +27,11 @@ RETURNS boolean LANGUAGE plpgsql IMMUTABLE AS $$
BEGIN
IF jsonb_typeof(val) = 'array' THEN
RETURN EXISTS (
SELECT 1 FROM jsonb_array_elements(val) AS e WHERE e #>> '{}' = target
SELECT 1 FROM jsonb_array_elements(val) AS e
WHERE jsonb_typeof(e) = 'string' AND e #>> '{}' = target
);
END IF;
IF jsonb_typeof(val) != 'string' THEN RETURN FALSE; END IF;
RETURN val #>> '{}' = target;
END;
$$;
@ -39,9 +41,11 @@ RETURNS boolean LANGUAGE plpgsql IMMUTABLE AS $$
BEGIN
IF jsonb_typeof(val) = 'array' THEN
RETURN NOT EXISTS (
SELECT 1 FROM jsonb_array_elements(val) AS e WHERE e #>> '{}' = target
SELECT 1 FROM jsonb_array_elements(val) AS e
WHERE jsonb_typeof(e) = 'string' AND e #>> '{}' = target
);
END IF;
IF jsonb_typeof(val) != 'string' THEN RETURN TRUE; END IF;
RETURN val #>> '{}' != target;
END;
$$;
@ -51,9 +55,11 @@ RETURNS boolean LANGUAGE plpgsql IMMUTABLE AS $$
BEGIN
IF jsonb_typeof(val) = 'array' THEN
RETURN EXISTS (
SELECT 1 FROM jsonb_array_elements(val) AS e WHERE e #>> '{}' < target
SELECT 1 FROM jsonb_array_elements(val) AS e
WHERE jsonb_typeof(e) = 'string' AND e #>> '{}' < target
);
END IF;
IF jsonb_typeof(val) != 'string' THEN RETURN FALSE; END IF;
RETURN val #>> '{}' < target;
END;
$$;
@ -63,9 +69,11 @@ RETURNS boolean LANGUAGE plpgsql IMMUTABLE AS $$
BEGIN
IF jsonb_typeof(val) = 'array' THEN
RETURN EXISTS (
SELECT 1 FROM jsonb_array_elements(val) AS e WHERE e #>> '{}' <= target
SELECT 1 FROM jsonb_array_elements(val) AS e
WHERE jsonb_typeof(e) = 'string' AND e #>> '{}' <= target
);
END IF;
IF jsonb_typeof(val) != 'string' THEN RETURN FALSE; END IF;
RETURN val #>> '{}' <= target;
END;
$$;
@ -75,9 +83,11 @@ RETURNS boolean LANGUAGE plpgsql IMMUTABLE AS $$
BEGIN
IF jsonb_typeof(val) = 'array' THEN
RETURN EXISTS (
SELECT 1 FROM jsonb_array_elements(val) AS e WHERE e #>> '{}' > target
SELECT 1 FROM jsonb_array_elements(val) AS e
WHERE jsonb_typeof(e) = 'string' AND e #>> '{}' > target
);
END IF;
IF jsonb_typeof(val) != 'string' THEN RETURN FALSE; END IF;
RETURN val #>> '{}' > target;
END;
$$;
@ -87,9 +97,11 @@ RETURNS boolean LANGUAGE plpgsql IMMUTABLE AS $$
BEGIN
IF jsonb_typeof(val) = 'array' THEN
RETURN EXISTS (
SELECT 1 FROM jsonb_array_elements(val) AS e WHERE e #>> '{}' >= target
SELECT 1 FROM jsonb_array_elements(val) AS e
WHERE jsonb_typeof(e) = 'string' AND e #>> '{}' >= target
);
END IF;
IF jsonb_typeof(val) != 'string' THEN RETURN FALSE; END IF;
RETURN val #>> '{}' >= target;
END;
$$;
@ -100,9 +112,10 @@ BEGIN
IF jsonb_typeof(val) = 'array' THEN
RETURN EXISTS (
SELECT 1 FROM jsonb_array_elements(val) AS e
WHERE e #>> '{}' LIKE '%' || target || '%'
WHERE jsonb_typeof(e) = 'string' AND e #>> '{}' LIKE '%' || target || '%'
);
END IF;
IF jsonb_typeof(val) != 'string' THEN RETURN FALSE; END IF;
RETURN val #>> '{}' LIKE '%' || target || '%';
END;
$$;
@ -113,9 +126,10 @@ BEGIN
IF jsonb_typeof(val) = 'array' THEN
RETURN EXISTS (
SELECT 1 FROM jsonb_array_elements(val) AS e
WHERE e #>> '{}' LIKE target || '%'
WHERE jsonb_typeof(e) = 'string' AND e #>> '{}' LIKE target || '%'
);
END IF;
IF jsonb_typeof(val) != 'string' THEN RETURN FALSE; END IF;
RETURN val #>> '{}' LIKE target || '%';
END;
$$;
@ -126,9 +140,10 @@ BEGIN
IF jsonb_typeof(val) = 'array' THEN
RETURN EXISTS (
SELECT 1 FROM jsonb_array_elements(val) AS e
WHERE e #>> '{}' LIKE '%' || target
WHERE jsonb_typeof(e) = 'string' AND e #>> '{}' LIKE '%' || target
);
END IF;
IF jsonb_typeof(val) != 'string' THEN RETURN FALSE; END IF;
RETURN val #>> '{}' LIKE '%' || target;
END;
$$;
@ -139,9 +154,10 @@ BEGIN
IF jsonb_typeof(val) = 'array' THEN
RETURN EXISTS (
SELECT 1 FROM jsonb_array_elements(val) AS e
WHERE e #>> '{}' ~ target
WHERE jsonb_typeof(e) = 'string' AND e #>> '{}' ~ target
);
END IF;
IF jsonb_typeof(val) != 'string' THEN RETURN FALSE; END IF;
RETURN val #>> '{}' ~ target;
END;
$$;
@ -152,9 +168,10 @@ BEGIN
IF jsonb_typeof(val) = 'array' THEN
RETURN EXISTS (
SELECT 1 FROM jsonb_array_elements(val) AS e
WHERE e #>> '{}' = ANY(targets)
WHERE jsonb_typeof(e) = 'string' AND e #>> '{}' = ANY(targets)
);
END IF;
IF jsonb_typeof(val) != 'string' THEN RETURN FALSE; END IF;
RETURN val #>> '{}' = ANY(targets);
END;
$$;
@ -186,7 +203,7 @@ BEGIN
WHERE jsonb_typeof(e) = 'number' AND (e #>> '{}')::numeric = target
);
END IF;
IF jsonb_typeof(val) != 'number' THEN RETURN FALSE; END IF;
IF jsonb_typeof(val) != 'number' THEN RETURN TRUE; END IF;
RETURN (val #>> '{}')::numeric != target;
END;
$$;
@ -310,7 +327,7 @@ BEGIN
WHERE jsonb_typeof(e) = 'boolean' AND (e #>> '{}')::boolean = target
);
END IF;
IF jsonb_typeof(val) != 'boolean' THEN RETURN FALSE; END IF;
IF jsonb_typeof(val) != 'boolean' THEN RETURN TRUE; END IF;
RETURN (val #>> '{}')::boolean != target;
END;
$$;

15
backend/src/Squidex.Data.EntityFramework/Providers/SqlServer/JsonFunction.cs

@ -110,23 +110,26 @@ public static class JsonFunction
{
TypeText =>
$"""
(CASE WHEN JSON_QUERY({jsonPath}) IS NOT NULL
(CASE WHEN JSON_QUERY({jsonPath}) IS NOT NULL AND LEFT(LTRIM(JSON_QUERY({jsonPath})), 1) = '['
THEN CASE WHEN EXISTS (SELECT 1 FROM OPENJSON(JSON_QUERY({jsonPath})) AS j WHERE j.[type] = 1 AND j.[value] IN ({formattedValue})) THEN 1 ELSE 0 END
ELSE CASE WHEN JSON_VALUE({jsonPath}) IN ({formattedValue}) THEN 1 ELSE 0 END
WHEN JSON_QUERY({jsonPath}) IS NOT NULL THEN 0
ELSE CASE WHEN EXISTS (SELECT 1 FROM OPENJSON({jsonPath}) AS j WHERE j.[type] = 1 AND j.[value] IN ({formattedValue})) THEN 1 ELSE 0 END
END) = 1
""",
TypeNumber =>
$"""
(CASE WHEN JSON_QUERY({jsonPath}) IS NOT NULL
(CASE WHEN JSON_QUERY({jsonPath}) IS NOT NULL AND LEFT(LTRIM(JSON_QUERY({jsonPath})), 1) = '['
THEN CASE WHEN EXISTS (SELECT 1 FROM OPENJSON(JSON_QUERY({jsonPath})) AS j WHERE j.[type] = 2 AND TRY_CAST(j.[value] AS DECIMAL(38, 10)) IN ({formattedValue})) THEN 1 ELSE 0 END
ELSE CASE WHEN TRY_CAST(JSON_VALUE({jsonPath}) AS DECIMAL(38, 10)) IN ({formattedValue}) THEN 1 ELSE 0 END
WHEN JSON_QUERY({jsonPath}) IS NOT NULL THEN 0
ELSE CASE WHEN EXISTS (SELECT 1 FROM OPENJSON({jsonPath}) AS j WHERE j.[type] = 2 AND TRY_CAST(j.[value] AS DECIMAL(38, 10)) IN ({formattedValue})) THEN 1 ELSE 0 END
END) = 1
""",
TypeBoolean =>
$"""
(CASE WHEN JSON_QUERY({jsonPath}) IS NOT NULL
(CASE WHEN JSON_QUERY({jsonPath}) IS NOT NULL AND LEFT(LTRIM(JSON_QUERY({jsonPath})), 1) = '['
THEN CASE WHEN EXISTS (SELECT 1 FROM OPENJSON(JSON_QUERY({jsonPath})) AS j WHERE j.[type] = 3 AND IIF(j.[value] = 'true', 1, IIF(j.[value] = 'false', 0, NULL)) IN ({formattedValue})) THEN 1 ELSE 0 END
ELSE CASE WHEN IIF(JSON_VALUE({jsonPath}) = 'true', 1, IIF(JSON_VALUE({jsonPath}) = 'false', 0, NULL)) IN ({formattedValue}) THEN 1 ELSE 0 END
WHEN JSON_QUERY({jsonPath}) IS NOT NULL THEN 0
ELSE CASE WHEN EXISTS (SELECT 1 FROM OPENJSON({jsonPath}) AS j WHERE j.[type] = 3 AND IIF(j.[value] = 'true', 1, IIF(j.[value] = 'false', 0, NULL)) IN ({formattedValue})) THEN 1 ELSE 0 END
END) = 1
""",
_ => throw new NotSupportedException($"No json function for type={type}, operator={op}."),

178
backend/src/Squidex.Data.EntityFramework/Providers/SqlServer/json_function.sql

@ -60,11 +60,15 @@ RETURNS BIT
AS
BEGIN
DECLARE @query NVARCHAR(MAX) = JSON_QUERY(@col, @path);
IF @query IS NOT NULL
IF @query IS NOT NULL AND LEFT(LTRIM(@query), 1) = '['
RETURN CASE WHEN EXISTS (
SELECT 1 FROM OPENJSON(@query) AS j WHERE j.[type] = 1 AND j.[value] = @target
) THEN 1 ELSE 0 END;
RETURN CASE WHEN JSON_VALUE(@col, @path) = @target THEN 1 ELSE 0 END;
IF @query IS NOT NULL
RETURN 0;
RETURN CASE WHEN EXISTS (
SELECT 1 FROM OPENJSON(@col, @path) AS j WHERE j.[type] = 1 AND j.[value] = @target
) THEN 1 ELSE 0 END;
END;;
DROP FUNCTION IF EXISTS dbo.json_text_notequals;;
@ -73,11 +77,21 @@ RETURNS BIT
AS
BEGIN
DECLARE @query NVARCHAR(MAX) = JSON_QUERY(@col, @path);
IF @query IS NOT NULL
IF @query IS NOT NULL AND LEFT(LTRIM(@query), 1) = '['
RETURN CASE WHEN NOT EXISTS (
SELECT 1 FROM OPENJSON(@query) AS j WHERE j.[type] = 1 AND j.[value] = @target
) THEN 1 ELSE 0 END;
RETURN CASE WHEN JSON_VALUE(@col, @path) != @target THEN 1 ELSE 0 END;
IF @query IS NOT NULL
RETURN 1;
RETURN CASE
WHEN EXISTS (
SELECT 1 FROM OPENJSON(@col, @path) AS j WHERE j.[type] = 1 AND j.[value] = @target
) THEN 0
WHEN EXISTS (
SELECT 1 FROM OPENJSON(@col, @path)
) THEN 1
ELSE 0
END;
END;;
DROP FUNCTION IF EXISTS dbo.json_text_lessthan;;
@ -86,11 +100,15 @@ RETURNS BIT
AS
BEGIN
DECLARE @query NVARCHAR(MAX) = JSON_QUERY(@col, @path);
IF @query IS NOT NULL
IF @query IS NOT NULL AND LEFT(LTRIM(@query), 1) = '['
RETURN CASE WHEN EXISTS (
SELECT 1 FROM OPENJSON(@query) AS j WHERE j.[type] = 1 AND j.[value] < @target
) THEN 1 ELSE 0 END;
RETURN CASE WHEN JSON_VALUE(@col, @path) < @target THEN 1 ELSE 0 END;
IF @query IS NOT NULL
RETURN 0;
RETURN CASE WHEN EXISTS (
SELECT 1 FROM OPENJSON(@col, @path) AS j WHERE j.[type] = 1 AND j.[value] < @target
) THEN 1 ELSE 0 END;
END;;
DROP FUNCTION IF EXISTS dbo.json_text_lessthanorequal;;
@ -99,11 +117,15 @@ RETURNS BIT
AS
BEGIN
DECLARE @query NVARCHAR(MAX) = JSON_QUERY(@col, @path);
IF @query IS NOT NULL
IF @query IS NOT NULL AND LEFT(LTRIM(@query), 1) = '['
RETURN CASE WHEN EXISTS (
SELECT 1 FROM OPENJSON(@query) AS j WHERE j.[type] = 1 AND j.[value] <= @target
) THEN 1 ELSE 0 END;
RETURN CASE WHEN JSON_VALUE(@col, @path) <= @target THEN 1 ELSE 0 END;
IF @query IS NOT NULL
RETURN 0;
RETURN CASE WHEN EXISTS (
SELECT 1 FROM OPENJSON(@col, @path) AS j WHERE j.[type] = 1 AND j.[value] <= @target
) THEN 1 ELSE 0 END;
END;;
DROP FUNCTION IF EXISTS dbo.json_text_greaterthan;;
@ -112,11 +134,15 @@ RETURNS BIT
AS
BEGIN
DECLARE @query NVARCHAR(MAX) = JSON_QUERY(@col, @path);
IF @query IS NOT NULL
IF @query IS NOT NULL AND LEFT(LTRIM(@query), 1) = '['
RETURN CASE WHEN EXISTS (
SELECT 1 FROM OPENJSON(@query) AS j WHERE j.[type] = 1 AND j.[value] > @target
) THEN 1 ELSE 0 END;
RETURN CASE WHEN JSON_VALUE(@col, @path) > @target THEN 1 ELSE 0 END;
IF @query IS NOT NULL
RETURN 0;
RETURN CASE WHEN EXISTS (
SELECT 1 FROM OPENJSON(@col, @path) AS j WHERE j.[type] = 1 AND j.[value] > @target
) THEN 1 ELSE 0 END;
END;;
DROP FUNCTION IF EXISTS dbo.json_text_greaterthanorequal;;
@ -125,11 +151,15 @@ RETURNS BIT
AS
BEGIN
DECLARE @query NVARCHAR(MAX) = JSON_QUERY(@col, @path);
IF @query IS NOT NULL
IF @query IS NOT NULL AND LEFT(LTRIM(@query), 1) = '['
RETURN CASE WHEN EXISTS (
SELECT 1 FROM OPENJSON(@query) AS j WHERE j.[type] = 1 AND j.[value] >= @target
) THEN 1 ELSE 0 END;
RETURN CASE WHEN JSON_VALUE(@col, @path) >= @target THEN 1 ELSE 0 END;
IF @query IS NOT NULL
RETURN 0;
RETURN CASE WHEN EXISTS (
SELECT 1 FROM OPENJSON(@col, @path) AS j WHERE j.[type] = 1 AND j.[value] >= @target
) THEN 1 ELSE 0 END;
END;;
DROP FUNCTION IF EXISTS dbo.json_text_contains;;
@ -138,11 +168,15 @@ RETURNS BIT
AS
BEGIN
DECLARE @query NVARCHAR(MAX) = JSON_QUERY(@col, @path);
IF @query IS NOT NULL
IF @query IS NOT NULL AND LEFT(LTRIM(@query), 1) = '['
RETURN CASE WHEN EXISTS (
SELECT 1 FROM OPENJSON(@query) AS j WHERE j.[type] = 1 AND j.[value] LIKE '%' + @target + '%'
) THEN 1 ELSE 0 END;
RETURN CASE WHEN JSON_VALUE(@col, @path) LIKE '%' + @target + '%' THEN 1 ELSE 0 END;
IF @query IS NOT NULL
RETURN 0;
RETURN CASE WHEN EXISTS (
SELECT 1 FROM OPENJSON(@col, @path) AS j WHERE j.[type] = 1 AND j.[value] LIKE '%' + @target + '%'
) THEN 1 ELSE 0 END;
END;;
DROP FUNCTION IF EXISTS dbo.json_text_startswith;;
@ -151,11 +185,15 @@ RETURNS BIT
AS
BEGIN
DECLARE @query NVARCHAR(MAX) = JSON_QUERY(@col, @path);
IF @query IS NOT NULL
IF @query IS NOT NULL AND LEFT(LTRIM(@query), 1) = '['
RETURN CASE WHEN EXISTS (
SELECT 1 FROM OPENJSON(@query) AS j WHERE j.[type] = 1 AND j.[value] LIKE @target + '%'
) THEN 1 ELSE 0 END;
RETURN CASE WHEN JSON_VALUE(@col, @path) LIKE @target + '%' THEN 1 ELSE 0 END;
IF @query IS NOT NULL
RETURN 0;
RETURN CASE WHEN EXISTS (
SELECT 1 FROM OPENJSON(@col, @path) AS j WHERE j.[type] = 1 AND j.[value] LIKE @target + '%'
) THEN 1 ELSE 0 END;
END;;
DROP FUNCTION IF EXISTS dbo.json_text_endswith;;
@ -164,11 +202,15 @@ RETURNS BIT
AS
BEGIN
DECLARE @query NVARCHAR(MAX) = JSON_QUERY(@col, @path);
IF @query IS NOT NULL
IF @query IS NOT NULL AND LEFT(LTRIM(@query), 1) = '['
RETURN CASE WHEN EXISTS (
SELECT 1 FROM OPENJSON(@query) AS j WHERE j.[type] = 1 AND j.[value] LIKE '%' + @target
) THEN 1 ELSE 0 END;
RETURN CASE WHEN JSON_VALUE(@col, @path) LIKE '%' + @target THEN 1 ELSE 0 END;
IF @query IS NOT NULL
RETURN 0;
RETURN CASE WHEN EXISTS (
SELECT 1 FROM OPENJSON(@col, @path) AS j WHERE j.[type] = 1 AND j.[value] LIKE '%' + @target
) THEN 1 ELSE 0 END;
END;;
DROP FUNCTION IF EXISTS dbo.json_text_matchs;;
@ -177,11 +219,15 @@ RETURNS BIT
AS
BEGIN
DECLARE @query NVARCHAR(MAX) = JSON_QUERY(@col, @path);
IF @query IS NOT NULL
IF @query IS NOT NULL AND LEFT(LTRIM(@query), 1) = '['
RETURN CASE WHEN EXISTS (
SELECT 1 FROM OPENJSON(@query) AS j WHERE j.[type] = 1 AND j.[value] LIKE @target
) THEN 1 ELSE 0 END;
RETURN CASE WHEN JSON_VALUE(@col, @path) LIKE @target THEN 1 ELSE 0 END;
IF @query IS NOT NULL
RETURN 0;
RETURN CASE WHEN EXISTS (
SELECT 1 FROM OPENJSON(@col, @path) AS j WHERE j.[type] = 1 AND j.[value] LIKE @target
) THEN 1 ELSE 0 END;
END;;
@ -194,13 +240,19 @@ RETURNS BIT
AS
BEGIN
DECLARE @query NVARCHAR(MAX) = JSON_QUERY(@col, @path);
IF @query IS NOT NULL
IF @query IS NOT NULL AND LEFT(LTRIM(@query), 1) = '['
RETURN CASE WHEN EXISTS (
SELECT 1 FROM OPENJSON(@query) AS j
WHERE j.[type] = 2
AND TRY_CAST(j.[value] AS DECIMAL(38, 10)) = @target
) THEN 1 ELSE 0 END;
RETURN CASE WHEN TRY_CAST(JSON_VALUE(@col, @path) AS DECIMAL(38, 10)) = @target THEN 1 ELSE 0 END;
IF @query IS NOT NULL
RETURN 0;
RETURN CASE WHEN EXISTS (
SELECT 1 FROM OPENJSON(@col, @path) AS j
WHERE j.[type] = 2
AND TRY_CAST(j.[value] AS DECIMAL(38, 10)) = @target
) THEN 1 ELSE 0 END;
END;;
DROP FUNCTION IF EXISTS dbo.json_number_notequals;;
@ -209,13 +261,25 @@ RETURNS BIT
AS
BEGIN
DECLARE @query NVARCHAR(MAX) = JSON_QUERY(@col, @path);
IF @query IS NOT NULL
IF @query IS NOT NULL AND LEFT(LTRIM(@query), 1) = '['
RETURN CASE WHEN NOT EXISTS (
SELECT 1 FROM OPENJSON(@query) AS j
WHERE j.[type] = 2
AND TRY_CAST(j.[value] AS DECIMAL(38, 10)) = @target
) THEN 1 ELSE 0 END;
RETURN CASE WHEN TRY_CAST(JSON_VALUE(@col, @path) AS DECIMAL(38, 10)) != @target THEN 1 ELSE 0 END;
IF @query IS NOT NULL
RETURN 1;
RETURN CASE
WHEN EXISTS (
SELECT 1 FROM OPENJSON(@col, @path) AS j
WHERE j.[type] = 2
AND TRY_CAST(j.[value] AS DECIMAL(38, 10)) = @target
) THEN 0
WHEN EXISTS (
SELECT 1 FROM OPENJSON(@col, @path)
) THEN 1
ELSE 0
END;
END;;
DROP FUNCTION IF EXISTS dbo.json_number_lessthan;;
@ -224,13 +288,19 @@ RETURNS BIT
AS
BEGIN
DECLARE @query NVARCHAR(MAX) = JSON_QUERY(@col, @path);
IF @query IS NOT NULL
IF @query IS NOT NULL AND LEFT(LTRIM(@query), 1) = '['
RETURN CASE WHEN EXISTS (
SELECT 1 FROM OPENJSON(@query) AS j
WHERE j.[type] = 2
AND TRY_CAST(j.[value] AS DECIMAL(38, 10)) < @target
) THEN 1 ELSE 0 END;
RETURN CASE WHEN TRY_CAST(JSON_VALUE(@col, @path) AS DECIMAL(38, 10)) < @target THEN 1 ELSE 0 END;
IF @query IS NOT NULL
RETURN 0;
RETURN CASE WHEN EXISTS (
SELECT 1 FROM OPENJSON(@col, @path) AS j
WHERE j.[type] = 2
AND TRY_CAST(j.[value] AS DECIMAL(38, 10)) < @target
) THEN 1 ELSE 0 END;
END;;
DROP FUNCTION IF EXISTS dbo.json_number_lessthanorequal;;
@ -239,13 +309,19 @@ RETURNS BIT
AS
BEGIN
DECLARE @query NVARCHAR(MAX) = JSON_QUERY(@col, @path);
IF @query IS NOT NULL
IF @query IS NOT NULL AND LEFT(LTRIM(@query), 1) = '['
RETURN CASE WHEN EXISTS (
SELECT 1 FROM OPENJSON(@query) AS j
WHERE j.[type] = 2
AND TRY_CAST(j.[value] AS DECIMAL(38, 10)) <= @target
) THEN 1 ELSE 0 END;
RETURN CASE WHEN TRY_CAST(JSON_VALUE(@col, @path) AS DECIMAL(38, 10)) <= @target THEN 1 ELSE 0 END;
IF @query IS NOT NULL
RETURN 0;
RETURN CASE WHEN EXISTS (
SELECT 1 FROM OPENJSON(@col, @path) AS j
WHERE j.[type] = 2
AND TRY_CAST(j.[value] AS DECIMAL(38, 10)) <= @target
) THEN 1 ELSE 0 END;
END;;
DROP FUNCTION IF EXISTS dbo.json_number_greaterthan;;
@ -254,13 +330,19 @@ RETURNS BIT
AS
BEGIN
DECLARE @query NVARCHAR(MAX) = JSON_QUERY(@col, @path);
IF @query IS NOT NULL
IF @query IS NOT NULL AND LEFT(LTRIM(@query), 1) = '['
RETURN CASE WHEN EXISTS (
SELECT 1 FROM OPENJSON(@query) AS j
WHERE j.[type] = 2
AND TRY_CAST(j.[value] AS DECIMAL(38, 10)) > @target
) THEN 1 ELSE 0 END;
RETURN CASE WHEN TRY_CAST(JSON_VALUE(@col, @path) AS DECIMAL(38, 10)) > @target THEN 1 ELSE 0 END;
IF @query IS NOT NULL
RETURN 0;
RETURN CASE WHEN EXISTS (
SELECT 1 FROM OPENJSON(@col, @path) AS j
WHERE j.[type] = 2
AND TRY_CAST(j.[value] AS DECIMAL(38, 10)) > @target
) THEN 1 ELSE 0 END;
END;;
DROP FUNCTION IF EXISTS dbo.json_number_greaterthanorequal;;
@ -269,13 +351,19 @@ RETURNS BIT
AS
BEGIN
DECLARE @query NVARCHAR(MAX) = JSON_QUERY(@col, @path);
IF @query IS NOT NULL
IF @query IS NOT NULL AND LEFT(LTRIM(@query), 1) = '['
RETURN CASE WHEN EXISTS (
SELECT 1 FROM OPENJSON(@query) AS j
WHERE j.[type] = 2
AND TRY_CAST(j.[value] AS DECIMAL(38, 10)) >= @target
) THEN 1 ELSE 0 END;
RETURN CASE WHEN TRY_CAST(JSON_VALUE(@col, @path) AS DECIMAL(38, 10)) >= @target THEN 1 ELSE 0 END;
IF @query IS NOT NULL
RETURN 0;
RETURN CASE WHEN EXISTS (
SELECT 1 FROM OPENJSON(@col, @path) AS j
WHERE j.[type] = 2
AND TRY_CAST(j.[value] AS DECIMAL(38, 10)) >= @target
) THEN 1 ELSE 0 END;
END;;
@ -288,13 +376,19 @@ RETURNS BIT
AS
BEGIN
DECLARE @query NVARCHAR(MAX) = JSON_QUERY(@col, @path);
IF @query IS NOT NULL
IF @query IS NOT NULL AND LEFT(LTRIM(@query), 1) = '['
RETURN CASE WHEN EXISTS (
SELECT 1 FROM OPENJSON(@query) AS j
WHERE j.[type] = 3
AND IIF(j.[value] = 'true', 1, IIF(j.[value] = 'false', 0, NULL)) = @target
) THEN 1 ELSE 0 END;
RETURN CASE WHEN IIF(JSON_VALUE(@col, @path) = 'true', 1, IIF(JSON_VALUE(@col, @path) = 'false', 0, NULL)) = @target THEN 1 ELSE 0 END;
IF @query IS NOT NULL
RETURN 0;
RETURN CASE WHEN EXISTS (
SELECT 1 FROM OPENJSON(@col, @path) AS j
WHERE j.[type] = 3
AND IIF(j.[value] = 'true', 1, IIF(j.[value] = 'false', 0, NULL)) = @target
) THEN 1 ELSE 0 END;
END;;
DROP FUNCTION IF EXISTS dbo.json_boolean_notequals;;
@ -303,11 +397,23 @@ RETURNS BIT
AS
BEGIN
DECLARE @query NVARCHAR(MAX) = JSON_QUERY(@col, @path);
IF @query IS NOT NULL
IF @query IS NOT NULL AND LEFT(LTRIM(@query), 1) = '['
RETURN CASE WHEN NOT EXISTS (
SELECT 1 FROM OPENJSON(@query) AS j
WHERE j.[type] = 3
AND IIF(j.[value] = 'true', 1, IIF(j.[value] = 'false', 0, NULL)) = @target
) THEN 1 ELSE 0 END;
RETURN CASE WHEN IIF(JSON_VALUE(@col, @path) = 'true', 1, IIF(JSON_VALUE(@col, @path) = 'false', 0, NULL)) != @target THEN 1 ELSE 0 END;
IF @query IS NOT NULL
RETURN 1;
RETURN CASE
WHEN EXISTS (
SELECT 1 FROM OPENJSON(@col, @path) AS j
WHERE j.[type] = 3
AND IIF(j.[value] = 'true', 1, IIF(j.[value] = 'false', 0, NULL)) = @target
) THEN 0
WHEN EXISTS (
SELECT 1 FROM OPENJSON(@col, @path)
) THEN 1
ELSE 0
END;
END;;

88
backend/tests/Squidex.Data.Tests/EntityFramework/Infrastructure/Queries/EFQueryTests.cs

@ -626,6 +626,17 @@ public abstract class EFQueryTests<TContext>(ISqlFixture<TContext> fixture)
Assert.Equal([8], actual.Order().ToArray());
}
[Fact]
public async Task Should_filter_by_number_not_equal_in_mixed_json_with_type_strictness()
{
var actual = await QueryAsync(new ClrQuery
{
Filter = ClrFilter.Ne("Json.mixed", 8),
});
Assert.Equal(AllExept(8), actual.Order().ToArray());
}
[Fact]
public async Task Should_filter_by_number_greater_than_in_mixed_json()
{
@ -1033,6 +1044,28 @@ public abstract class EFQueryTests<TContext>(ISqlFixture<TContext> fixture)
Assert.Equal(Range(1, 10), actual.Order().ToArray());
}
[Fact]
public async Task Should_filter_by_string_equal_in_mixed_json_with_type_strictness()
{
var actual = await QueryAsync(new ClrQuery
{
Filter = ClrFilter.Eq("Json.mixed", "8"),
});
Assert.Empty(actual);
}
[Fact]
public async Task Should_filter_by_string_not_equal_in_mixed_json_with_type_strictness()
{
var actual = await QueryAsync(new ClrQuery
{
Filter = ClrFilter.Ne("Json.mixed", "8"),
});
Assert.Equal(Range(1, 20), actual.Order().ToArray());
}
[Fact]
public async Task Should_filter_by_string_contains_in_mixed_json()
{
@ -1044,6 +1077,17 @@ public abstract class EFQueryTests<TContext>(ISqlFixture<TContext> fixture)
Assert.Equal([7], actual.Order().ToArray());
}
[Fact]
public async Task Should_filter_by_string_contains_in_mixed_json_with_type_strictness()
{
var actual = await QueryAsync(new ClrQuery
{
Filter = ClrFilter.Contains("Json.mixed", "true"),
});
Assert.Empty(actual);
}
[Fact]
public async Task Should_filter_by_string_starts_with_in_mixed_json()
{
@ -1154,6 +1198,17 @@ public abstract class EFQueryTests<TContext>(ISqlFixture<TContext> fixture)
Assert.Equal(Range(1, 20), actual.Order().ToArray());
}
[Fact]
public async Task Should_filter_by_string_equal_in_json_mixed_array_with_type_strictness()
{
var actual = await QueryAsync(new ClrQuery
{
Filter = ClrFilter.Eq("Json.mixedArray", "7"),
});
Assert.Empty(actual);
}
[Fact]
public async Task Should_filter_by_string_contains_in_json_mixed_array()
{
@ -1165,6 +1220,17 @@ public abstract class EFQueryTests<TContext>(ISqlFixture<TContext> fixture)
Assert.Equal([7, 17], actual.Order().ToArray());
}
[Fact]
public async Task Should_filter_by_string_contains_in_json_mixed_array_with_type_strictness()
{
var actual = await QueryAsync(new ClrQuery
{
Filter = ClrFilter.Contains("Json.mixedArray", "true"),
});
Assert.Empty(actual);
}
[Fact]
public async Task Should_filter_by_string_starts_with_in_json_mixed_array()
{
@ -1187,6 +1253,17 @@ public abstract class EFQueryTests<TContext>(ISqlFixture<TContext> fixture)
Assert.Equal([5, 7], actual.Order().ToArray());
}
[Fact]
public async Task Should_filter_by_string_in_json_mixed_array_with_type_strictness()
{
var actual = await QueryAsync(new ClrQuery
{
Filter = ClrFilter.In("Json.mixedArray", new List<string> { "7", "true" }),
});
Assert.Empty(actual);
}
[Fact]
public async Task Should_filter_by_boolean_true()
{
@ -1363,6 +1440,17 @@ public abstract class EFQueryTests<TContext>(ISqlFixture<TContext> fixture)
Assert.Empty(actual);
}
[Fact]
public async Task Should_filter_by_boolean_not_equal_true_in_mixed_json_with_type_strictness()
{
var actual = await QueryAsync(new ClrQuery
{
Filter = ClrFilter.Ne("Json.mixed", true),
});
Assert.Equal(AllExept(3, 9, 15), actual.Order().ToArray());
}
[Fact]
public async Task Should_filter_by_boolean_true_in_json_boolean_array()
{

1
frontend/src/app/shared/components/comments/comments.component.html

@ -1,6 +1,7 @@
<div class="comments-header">
<form [formGroup]="commentForm.form" (ngSubmit)="comment()">
<sqx-autocomplete
#input
autoFocus="true"
autoSelectFirst="false"
displayProperty="contributorEmail"

1
frontend/src/app/shared/components/comments/comments.component.ts

@ -70,7 +70,6 @@ export class CommentsComponent implements OnInit {
this.messageBus.of(AnnotationCreateAfterNavigate)
.subscribe(message => {
this.reference = message;
this.input.focus();
}));
}

Loading…
Cancel
Save