Skip to content

Commit 66b7728

Browse files
committed
added tests and fixed errors and type casts
1 parent e302fe2 commit 66b7728

File tree

2 files changed

+234
-31
lines changed

2 files changed

+234
-31
lines changed

Diff for: postgres-json-schema--0.2.0.sql

+43-31
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,21 @@ CREATE TYPE json_schema_validation_result AS (
44
);
55

66

7-
CREATE OR REPLACE FUNCTION json_schema_validation_result_as_bool (json_schema_validation_result) RETURNS bool AS $$
7+
CREATE OR REPLACE FUNCTION json_schema_validation_result_as_bool (@extschema@.json_schema_validation_result) RETURNS bool AS $$
88
SELECT ($1).error IS NULL;
99
$$ LANGUAGE SQL IMMUTABLE;
1010

11-
CREATE OR REPLACE FUNCTION json_schema_validation_result_array_as_bool (json_schema_validation_result[]) RETURNS bool AS $$
12-
SELECT $1 IS NULL OR true = ALL ($1);
11+
CREATE OR REPLACE FUNCTION json_schema_validation_result_array_as_bool (@extschema@.json_schema_validation_result[]) RETURNS bool AS $$
12+
SELECT $1 IS NULL OR true = ALL ($1::bool[]);
1313
$$ LANGUAGE SQL IMMUTABLE;
1414

1515
CREATE CAST ( json_schema_validation_result AS bool )
1616
WITH FUNCTION @[email protected]_schema_validation_result_as_bool(json_schema_validation_result)
17-
AS IMPLICIT;
17+
AS ASSIGNMENT;
1818

1919
CREATE CAST ( json_schema_validation_result[] AS bool )
2020
WITH FUNCTION @[email protected]_schema_validation_result_array_as_bool(json_schema_validation_result[])
21-
AS IMPLICIT;
21+
AS ASSIGNMENT;
2222

2323

2424

@@ -93,12 +93,24 @@ CREATE OR REPLACE FUNCTION validate_json_schema(schema jsonb, data jsonb, root_s
9393
SELECT @[email protected]_json_schema_validations(schema, data, root_schema, ARRAY []::text[], string_as_number)::bool;
9494
$f$ LANGUAGE SQL IMMUTABLE ;
9595

96-
CREATE OR REPLACE FUNCTION json_schema_check_constraint(schema jsonb, data jsonb, string_as_number bool default true) RETURNS bool AS $$
97-
DECLARE result json_schema_validation_result[];
96+
CREATE OR REPLACE FUNCTION json_schema_check_constraint(
97+
schema jsonb,
98+
data jsonb,
99+
string_as_number bool default false,
100+
table_name text default '',
101+
column_name text default ''
102+
) RETURNS bool AS $$
103+
DECLARE
104+
result json_schema_validation_result[];
98105
BEGIN
99106
result := @[email protected]_json_schema_validations(schema, data, schema, '{}'::text[], string_as_number := string_as_number);
100107
IF (NOT result) THEN
101-
RAISE check_violation USING MESSAGE = 'json_schema_validation_failed', DETAIL = result;
108+
RAISE check_violation USING
109+
MESSAGE = 'json_schema_validation_failed',
110+
DETAIL = to_jsonb(result),
111+
-- HINT = v_value,
112+
TABLE = table_name,
113+
COLUMN = column_name;
102114
END IF;
103115
RETURN true;
104116
END;
@@ -109,7 +121,7 @@ $$ LANGUAGE plpgsql IMMUTABLE ;
109121
CREATE OR REPLACE FUNCTION _validate_json_multiple_schemas(
110122
schemas_array jsonb, data jsonb, root_schema jsonb, schema_path text[], string_as_number bool,
111123
OUT validation_booleans bool[],
112-
OUT all_errors json_schema_validation_result[]
124+
OUT all_errors @extschema@.json_schema_validation_result[]
113125
) AS $f$
114126
WITH schema_validations AS (
115127
SELECT q FROM jsonb_array_elements(schemas_array) sub_schema,
@@ -122,7 +134,7 @@ $f$ LANGUAGE SQL IMMUTABLE ;
122134

123135

124136
CREATE OR REPLACE FUNCTION get_json_schema_validations(schema jsonb, data jsonb, root_schema jsonb, schema_path text[], string_as_number bool)
125-
RETURNS json_schema_validation_result[] AS $f$
137+
RETURNS @extschema@.json_schema_validation_result[] AS $f$
126138
DECLARE
127139
prop text;
128140
item jsonb;
@@ -133,7 +145,7 @@ DECLARE
133145
additionalItems jsonb;
134146
pattern text;
135147
props text[];
136-
result json_schema_validation_result[];
148+
result @extschema@.json_schema_validation_result[];
137149
q_result record;
138150
BEGIN
139151
IF root_schema IS NULL THEN
@@ -160,7 +172,7 @@ BEGIN
160172
ELSE
161173
types = ARRAY[schema->>'type'];
162174
END IF;
163-
IF (SELECT NOT bool_or(@extschema@._validate_json_schema_type(type, data)) FROM unnest(types) type) THEN
175+
IF (SELECT NOT bool_or(@extschema@._validate_json_schema_type(type, data, string_as_number)) FROM unnest(types) type) THEN
164176
RETURN ARRAY [(schema_path, format('%s is not a valid type: %s', jsonb_typeof(data), types))];
165177
END IF;
166178
END IF;
@@ -179,7 +191,7 @@ BEGIN
179191
IF schema ? 'required' AND jsonb_typeof(data) = 'object' THEN
180192
IF NOT ARRAY(SELECT jsonb_object_keys(data)) @>
181193
ARRAY(SELECT jsonb_array_elements_text(schema->'required')) THEN
182-
RETURN ARRAY [(path, format('%s is missing required properties: %s', schema->>'type', ARRAY(
194+
RETURN ARRAY [(schema_path, format('%s is missing required properties: %s', schema->>'type', ARRAY(
183195
SELECT jsonb_array_elements_text(schema->'required')
184196
EXCEPT
185197
SELECT jsonb_object_keys(data)
@@ -215,7 +227,7 @@ BEGIN
215227
IF prefixItems IS NOT NULL THEN
216228
SELECT array_agg(q) INTO result
217229
FROM jsonb_array_elements(prefixItems) WITH ORDINALITY AS t(sub_schema, i),
218-
@[email protected]_json_schema_validations(sub_schema, data->(i::int - 1), root_schema, schema_path || i::text, string_as_number) q1, unnest(q1) q
230+
@[email protected]_json_schema_validations(sub_schema, data->(i::int - 1), root_schema, schema_path || (i - 1)::text, string_as_number) q1, unnest(q1) q
219231
WHERE i <= jsonb_array_length(data);
220232
IF NOT result THEN
221233
RETURN result;
@@ -225,14 +237,14 @@ BEGIN
225237

226238
IF jsonb_typeof(additionalItems) = 'boolean' and NOT (additionalItems)::text::boolean THEN
227239
IF jsonb_array_length(data) > COALESCE(jsonb_array_length(prefixItems), 0) THEN
228-
RETURN ARRAY [(path, format('field only accepts %s items', COALESCE(jsonb_array_length(prefixItems), 0)))];
240+
RETURN ARRAY [(schema_path, format('field only accepts %s items', COALESCE(jsonb_array_length(prefixItems), 0)))];
229241
END IF;
230242
END IF;
231243

232244
IF jsonb_typeof(additionalItems) = 'object' THEN
233245
SELECT array_agg(q) INTO result
234246
FROM jsonb_array_elements(data) WITH ORDINALITY AS t(elem, i),
235-
@[email protected]_json_schema_validations(additionalItems, elem, root_schema, schema_path || i::text, string_as_number) AS q1, unnest(q1) q
247+
@[email protected]_json_schema_validations(additionalItems, elem, root_schema, schema_path || (i - 1)::text, string_as_number) AS q1, unnest(q1) q
236248
WHERE i > coalesce(jsonb_array_length(prefixItems), 0) AND NOT q LIMIT 1;
237249

238250
IF NOT result THEN
@@ -244,59 +256,59 @@ BEGIN
244256

245257
IF schema ? 'minimum' AND jsonb_typeof(data) = 'number' THEN
246258
IF data::text::numeric < (schema->>'minimum')::numeric THEN
247-
RETURN ARRAY [(path, format('value must be >= %s', (schema->>'minimum')))];
259+
RETURN ARRAY [(schema_path, format('value must be >= %s', (schema->>'minimum')))];
248260
END IF;
249261
END IF;
250262

251263
IF schema ? 'maximum' AND jsonb_typeof(data) = 'number' THEN
252264
IF data::text::numeric > (schema->>'maximum')::numeric THEN
253-
RETURN ARRAY [(path, format('value must be <= %s', (schema->>'maximum')))];
265+
RETURN ARRAY [(schema_path, format('value must be <= %s', (schema->>'maximum')))];
254266
END IF;
255267
END IF;
256268

257269
IF schema ? 'exclusiveMinimum' AND jsonb_typeof(data) = 'number' THEN
258270
IF jsonb_typeof(schema->'exclusiveMinimum') = 'number' THEN
259271
IF data::text::numeric <= (schema->>'exclusiveMinimum')::numeric THEN
260-
RETURN ARRAY [(path, format('value must be > %s', (schema->>'exclusiveMinimum')))];
272+
RETURN ARRAY [(schema_path, format('value must be > %s', (schema->>'exclusiveMinimum')))];
261273
END IF;
262274
ELSEIF COALESCE((schema->'exclusiveMinimum')::text::bool, FALSE) THEN
263275
IF data::text::numeric = (schema->>'minimum')::numeric THEN
264-
RETURN ARRAY [(path, format('value must be > %s', (schema->>'minimum')))];
276+
RETURN ARRAY [(schema_path, format('value must be > %s', (schema->>'minimum')))];
265277
END IF;
266278
END IF;
267279
END IF;
268280

269281
IF schema ? 'exclusiveMaximum' AND jsonb_typeof(data) = 'number' THEN
270282
IF jsonb_typeof(schema->'exclusiveMaximum') = 'number' THEN
271283
IF data::text::numeric >= (schema->>'exclusiveMaximum')::numeric THEN
272-
RETURN ARRAY [(path, format('value must be < %s', (schema->>'exclusiveMinimum')))];
284+
RETURN ARRAY [(schema_path, format('value must be < %s', (schema->>'exclusiveMinimum')))];
273285
END IF;
274286
ELSEIF COALESCE((schema->'exclusiveMaximum')::text::bool, FALSE) THEN
275287
IF data::text::numeric = (schema->>'maximum')::numeric THEN
276-
RETURN ARRAY [(path, format('value must be < %s', (schema->>'maximum')))];
288+
RETURN ARRAY [(schema_path, format('value must be < %s', (schema->>'maximum')))];
277289
END IF;
278290
END IF;
279291
END IF;
280292

281293
IF schema ? 'anyOf' THEN
282294
q_result := @extschema@._validate_json_multiple_schemas(schema->'anyOf', data, root_schema, schema_path, string_as_number);
283295
IF NOT (SELECT true = any (q_result.validation_booleans)) THEN
284-
RETURN q_result.all_errors || (schema_path, 'does not match any of the required schemas')::json_schema_validation_result;
296+
RETURN q_result.all_errors || (schema_path, 'does not match any of the required schemas')::@extschema@.json_schema_validation_result;
285297
END IF;
286298
END IF;
287299

288300
IF schema ? 'allOf' THEN
289301
q_result := @extschema@._validate_json_multiple_schemas(schema->'allOf', data, root_schema, schema_path, string_as_number);
290302
IF NOT (SELECT true = all(q_result.validation_booleans)) THEN
291-
RETURN q_result.all_errors || (schema_path, 'does not match all of the required schemas')::json_schema_validation_result;
303+
RETURN q_result.all_errors || (schema_path, 'does not match all of the required schemas')::@extschema@.json_schema_validation_result;
292304
END IF;
293305
END IF;
294306

295307
IF schema ? 'oneOf' THEN
296308
q_result := @extschema@._validate_json_multiple_schemas(schema->'oneOf', data, root_schema, schema_path, string_as_number);
297309
SELECT count(a::bool) INTO idx FROM unnest(q_result.validation_booleans) a WHERE a = true;
298310
IF (idx != 1) THEN
299-
RETURN ARRAY [(schema_path, format('should match exactly one of the schemas, but matches %s', idx))::json_schema_validation_result];
311+
RETURN ARRAY [(schema_path, format('should match exactly one of the schemas, but matches %s', idx))::@extschema@.json_schema_validation_result];
300312
END IF;
301313
END IF;
302314

@@ -319,7 +331,7 @@ BEGIN
319331
END IF;
320332
ELSE
321333
SELECT array_agg(q) INTO result FROM unnest(props) key, @[email protected]_json_schema_validations(schema->'additionalProperties', data->key, root_schema, schema_path || key, string_as_number) q1, unnest(q1) q;
322-
IF NOT (true = all(result)) THEN
334+
IF NOT (true = all(result::bool[])) THEN
323335
RETURN result;
324336
END IF;
325337
END IF;
@@ -338,7 +350,7 @@ BEGIN
338350
END IF;
339351

340352
result := @[email protected]_json_schema_validations(root_schema #> path, data, root_schema, schema_path, string_as_number);
341-
IF NOT (true = all(result)) THEN
353+
IF NOT (true = all(result::bool[])) THEN
342354
RETURN result;
343355
END IF;
344356
END IF;
@@ -402,14 +414,14 @@ BEGIN
402414
IF schema ? 'maxItems' AND jsonb_typeof(data) = 'array' THEN
403415
SELECT count(*) INTO idx FROM jsonb_array_elements(data);
404416
IF idx > (schema->>'maxItems')::numeric THEN
405-
RETURN ARRAY [(schema_path, format('field items count %s exceeds maxItems of %s', idx, schema->'maxItems'))];
417+
RETURN ARRAY [(schema_path, format('items count of %s exceeds maxItems of %s', idx, schema->'maxItems'))];
406418
END IF;
407419
END IF;
408420

409421
IF schema ? 'minItems' AND jsonb_typeof(data) = 'array' THEN
410422
SELECT count(*) INTO idx FROM jsonb_array_elements(data);
411423
IF idx < (schema->>'minItems')::numeric THEN
412-
RETURN ARRAY [(schema_path, format('field items count %s is less than minItems of %s', idx, schema->'minItems'))];
424+
RETURN ARRAY [(schema_path, format('items count of %s is less than minItems of %s', idx, schema->'minItems'))];
413425
END IF;
414426
END IF;
415427

@@ -477,7 +489,7 @@ BEGIN
477489
END IF;
478490
END IF;
479491

480-
RETURN '{}'::json_schema_validation_result[];
492+
RETURN '{}'::@extschema@.json_schema_validation_result[];
481493
END;
482494
$f$ LANGUAGE 'plpgsql' VOLATILE ;
483495

@@ -691,7 +703,7 @@ CREATE OR REPLACE FUNCTION json_schema_resolve_ids_to_paths (
691703
ELSEIF jsonb_typeof(schema) = 'array' THEN
692704
RETURN QUERY SELECT q.*
693705
FROM jsonb_array_elements(schema) WITH ORDINALITY t(elem, idx),
694-
@[email protected]_schema_resolve_ids_to_paths(elem, path || (idx -1)::text, base_uri, base_path) q;
706+
@[email protected]_schema_resolve_ids_to_paths(elem, path || (idx - 1)::text, base_uri, base_path) q;
695707

696708
END IF;
697709
resolved_path := path;

0 commit comments

Comments
 (0)