prostgles-server 4.2.157 → 4.2.159

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (159) hide show
  1. package/dist/Auth/AuthHandler.js +2 -2
  2. package/dist/Auth/AuthHandler.js.map +1 -1
  3. package/dist/Auth/AuthTypes.d.ts +4 -8
  4. package/dist/Auth/AuthTypes.d.ts.map +1 -1
  5. package/dist/Auth/setAuthProviders.d.ts +1 -1
  6. package/dist/Auth/setAuthProviders.d.ts.map +1 -1
  7. package/dist/Auth/setAuthProviders.js +6 -7
  8. package/dist/Auth/setAuthProviders.js.map +1 -1
  9. package/dist/Auth/setEmailProvider.d.ts +1 -1
  10. package/dist/Auth/setEmailProvider.d.ts.map +1 -1
  11. package/dist/Auth/setEmailProvider.js +22 -2
  12. package/dist/Auth/setEmailProvider.js.map +1 -1
  13. package/dist/Auth/setupAuthRoutes.js +1 -1
  14. package/dist/Auth/setupAuthRoutes.js.map +1 -1
  15. package/dist/Prostgles.d.ts +1 -0
  16. package/dist/Prostgles.d.ts.map +1 -1
  17. package/dist/Prostgles.js +6 -0
  18. package/dist/Prostgles.js.map +1 -1
  19. package/dist/initProstgles.d.ts.map +1 -1
  20. package/dist/initProstgles.js +2 -6
  21. package/dist/initProstgles.js.map +1 -1
  22. package/package.json +1 -1
  23. package/lib/Auth/AuthHandler.ts +0 -436
  24. package/lib/Auth/AuthTypes.ts +0 -285
  25. package/lib/Auth/getSafeReturnURL.ts +0 -35
  26. package/lib/Auth/sendEmail.ts +0 -83
  27. package/lib/Auth/setAuthProviders.ts +0 -129
  28. package/lib/Auth/setEmailProvider.ts +0 -63
  29. package/lib/Auth/setupAuthRoutes.ts +0 -161
  30. package/lib/DBEventsManager.ts +0 -178
  31. package/lib/DBSchemaBuilder.ts +0 -225
  32. package/lib/DboBuilder/DboBuilder.ts +0 -319
  33. package/lib/DboBuilder/DboBuilderTypes.ts +0 -361
  34. package/lib/DboBuilder/QueryBuilder/Functions.ts +0 -1153
  35. package/lib/DboBuilder/QueryBuilder/QueryBuilder.ts +0 -288
  36. package/lib/DboBuilder/QueryBuilder/getJoinQuery.ts +0 -263
  37. package/lib/DboBuilder/QueryBuilder/getNewQuery.ts +0 -271
  38. package/lib/DboBuilder/QueryBuilder/getSelectQuery.ts +0 -136
  39. package/lib/DboBuilder/QueryBuilder/prepareHaving.ts +0 -22
  40. package/lib/DboBuilder/QueryStreamer.ts +0 -250
  41. package/lib/DboBuilder/TableHandler/DataValidator.ts +0 -428
  42. package/lib/DboBuilder/TableHandler/TableHandler.ts +0 -205
  43. package/lib/DboBuilder/TableHandler/delete.ts +0 -115
  44. package/lib/DboBuilder/TableHandler/insert.ts +0 -183
  45. package/lib/DboBuilder/TableHandler/insertTest.ts +0 -78
  46. package/lib/DboBuilder/TableHandler/onDeleteFromFileTable.ts +0 -62
  47. package/lib/DboBuilder/TableHandler/runInsertUpdateQuery.ts +0 -134
  48. package/lib/DboBuilder/TableHandler/update.ts +0 -126
  49. package/lib/DboBuilder/TableHandler/updateBatch.ts +0 -49
  50. package/lib/DboBuilder/TableHandler/updateFile.ts +0 -48
  51. package/lib/DboBuilder/TableHandler/upsert.ts +0 -34
  52. package/lib/DboBuilder/ViewHandler/ViewHandler.ts +0 -393
  53. package/lib/DboBuilder/ViewHandler/count.ts +0 -38
  54. package/lib/DboBuilder/ViewHandler/find.ts +0 -153
  55. package/lib/DboBuilder/ViewHandler/getExistsCondition.ts +0 -73
  56. package/lib/DboBuilder/ViewHandler/getExistsFilters.ts +0 -74
  57. package/lib/DboBuilder/ViewHandler/getInfo.ts +0 -32
  58. package/lib/DboBuilder/ViewHandler/getTableJoinQuery.ts +0 -84
  59. package/lib/DboBuilder/ViewHandler/parseComplexFilter.ts +0 -96
  60. package/lib/DboBuilder/ViewHandler/parseFieldFilter.ts +0 -105
  61. package/lib/DboBuilder/ViewHandler/parseJoinPath.ts +0 -208
  62. package/lib/DboBuilder/ViewHandler/prepareSortItems.ts +0 -163
  63. package/lib/DboBuilder/ViewHandler/prepareWhere.ts +0 -90
  64. package/lib/DboBuilder/ViewHandler/size.ts +0 -37
  65. package/lib/DboBuilder/ViewHandler/subscribe.ts +0 -118
  66. package/lib/DboBuilder/ViewHandler/validateViewRules.ts +0 -70
  67. package/lib/DboBuilder/dboBuilderUtils.ts +0 -222
  68. package/lib/DboBuilder/getColumns.ts +0 -114
  69. package/lib/DboBuilder/getCondition.ts +0 -201
  70. package/lib/DboBuilder/getSubscribeRelatedTables.ts +0 -190
  71. package/lib/DboBuilder/getTablesForSchemaPostgresSQL.ts +0 -426
  72. package/lib/DboBuilder/insertNestedRecords.ts +0 -355
  73. package/lib/DboBuilder/parseUpdateRules.ts +0 -187
  74. package/lib/DboBuilder/prepareShortestJoinPaths.ts +0 -186
  75. package/lib/DboBuilder/runSQL.ts +0 -182
  76. package/lib/DboBuilder/runTransaction.ts +0 -50
  77. package/lib/DboBuilder/sqlErrCodeToMsg.ts +0 -254
  78. package/lib/DboBuilder/uploadFile.ts +0 -69
  79. package/lib/Event_Trigger_Tags.ts +0 -118
  80. package/lib/FileManager/FileManager.ts +0 -358
  81. package/lib/FileManager/getValidatedFileType.ts +0 -69
  82. package/lib/FileManager/initFileManager.ts +0 -187
  83. package/lib/FileManager/upload.ts +0 -62
  84. package/lib/FileManager/uploadStream.ts +0 -79
  85. package/lib/Filtering.ts +0 -463
  86. package/lib/JSONBValidation/validate_jsonb_schema_sql.ts +0 -502
  87. package/lib/JSONBValidation/validation.ts +0 -143
  88. package/lib/Logging.ts +0 -127
  89. package/lib/PostgresNotifListenManager.ts +0 -143
  90. package/lib/Prostgles.ts +0 -479
  91. package/lib/ProstglesTypes.ts +0 -196
  92. package/lib/PubSubManager/PubSubManager.ts +0 -609
  93. package/lib/PubSubManager/addSub.ts +0 -138
  94. package/lib/PubSubManager/addSync.ts +0 -141
  95. package/lib/PubSubManager/getCreatePubSubManagerError.ts +0 -72
  96. package/lib/PubSubManager/getPubSubManagerInitQuery.ts +0 -662
  97. package/lib/PubSubManager/initPubSubManager.ts +0 -79
  98. package/lib/PubSubManager/notifListener.ts +0 -173
  99. package/lib/PubSubManager/orphanTriggerCheck.ts +0 -70
  100. package/lib/PubSubManager/pushSubData.ts +0 -55
  101. package/lib/PublishParser/PublishParser.ts +0 -162
  102. package/lib/PublishParser/getFileTableRules.ts +0 -124
  103. package/lib/PublishParser/getSchemaFromPublish.ts +0 -141
  104. package/lib/PublishParser/getTableRulesWithoutFileTable.ts +0 -177
  105. package/lib/PublishParser/publishTypesAndUtils.ts +0 -399
  106. package/lib/RestApi.ts +0 -127
  107. package/lib/SchemaWatch/SchemaWatch.ts +0 -90
  108. package/lib/SchemaWatch/createSchemaWatchEventTrigger.ts +0 -3
  109. package/lib/SchemaWatch/getValidatedWatchSchemaType.ts +0 -45
  110. package/lib/SchemaWatch/getWatchSchemaTagList.ts +0 -27
  111. package/lib/SyncReplication.ts +0 -557
  112. package/lib/TableConfig/TableConfig.ts +0 -468
  113. package/lib/TableConfig/getColumnDefinitionQuery.ts +0 -111
  114. package/lib/TableConfig/getConstraintDefinitionQueries.ts +0 -95
  115. package/lib/TableConfig/getFutureTableSchema.ts +0 -64
  116. package/lib/TableConfig/getPGIndexes.ts +0 -53
  117. package/lib/TableConfig/getTableColumnQueries.ts +0 -129
  118. package/lib/TableConfig/initTableConfig.ts +0 -326
  119. package/lib/index.ts +0 -13
  120. package/lib/initProstgles.ts +0 -322
  121. package/lib/onSocketConnected.ts +0 -102
  122. package/lib/runClientRequest.ts +0 -129
  123. package/lib/shortestPath.ts +0 -122
  124. package/lib/typeTests/DBoGenerated.d.ts +0 -320
  125. package/lib/typeTests/dboTypeCheck.ts +0 -81
  126. package/lib/utils.ts +0 -15
  127. package/tests/client/hooks.spec.ts +0 -205
  128. package/tests/client/index.ts +0 -139
  129. package/tests/client/package-lock.json +0 -637
  130. package/tests/client/package.json +0 -26
  131. package/tests/client/renderReactHook.ts +0 -177
  132. package/tests/client/tsconfig.json +0 -15
  133. package/tests/client/useProstgles.spec.ts +0 -120
  134. package/tests/clientFileTests.spec.ts +0 -102
  135. package/tests/clientOnlyQueries.spec.ts +0 -667
  136. package/tests/clientRestApi.spec.ts +0 -82
  137. package/tests/config_test/DBoGenerated.d.ts +0 -407
  138. package/tests/config_test/index.html +0 -109
  139. package/tests/config_test/index.js +0 -86
  140. package/tests/config_test/index.js.map +0 -1
  141. package/tests/config_test/index.ts +0 -91
  142. package/tests/config_test/init.sql +0 -48
  143. package/tests/config_test/package.json +0 -29
  144. package/tests/config_test/tsconfig.json +0 -23
  145. package/tests/config_testDBoGenerated.d.ts +0 -407
  146. package/tests/isomorphicQueries.spec.ts +0 -1493
  147. package/tests/server/DBoGenerated.d.ts +0 -537
  148. package/tests/server/index.html +0 -73
  149. package/tests/server/index.ts +0 -289
  150. package/tests/server/init.sql +0 -224
  151. package/tests/server/package-lock.json +0 -2164
  152. package/tests/server/package.json +0 -25
  153. package/tests/server/publishTypeCheck.ts +0 -136
  154. package/tests/server/server.ts +0 -35
  155. package/tests/server/testPublish.ts +0 -147
  156. package/tests/server/testTableConfig.ts +0 -156
  157. package/tests/server/tsconfig.json +0 -22
  158. package/tests/serverOnlyQueries.spec.ts +0 -32
  159. package/tests/test.sh +0 -20
@@ -1,502 +0,0 @@
1
- import { DATA_TYPES } from "prostgles-types";
2
- import { PubSubManager } from "../PubSubManager/PubSubManager";
3
-
4
-
5
- const raiseException = (err: string) => `
6
- IF (context->'silent')::BOOLEAN = TRUE THEN
7
- RETURN FALSE;
8
- ELSE
9
- RAISE EXCEPTION ${err} USING HINT = path, COLUMN = colname, TABLE = tablename, CONSTRAINT = 'validate_jsonb_schema: ' || jsonb_pretty(jsonb_schema::JSONB);
10
- END IF;
11
- `
12
-
13
- export const VALIDATE_SCHEMA_FUNCNAME = "validate_jsonb_schema" as const;
14
- export const JSONB_DATA_TYPES = [
15
- ...DATA_TYPES,
16
- "Lookup","Lookup[]"
17
- ] as const;
18
-
19
- export const validate_jsonb_schema_sql = `
20
-
21
- /*
22
- * ${PubSubManager.EXCLUDE_QUERY_FROM_SCHEMA_WATCH_ID}
23
- */
24
-
25
- CREATE OR REPLACE FUNCTION ${VALIDATE_SCHEMA_FUNCNAME}(
26
- jsonb_schema TEXT,
27
- data JSONB,
28
- context JSONB DEFAULT '{}'::JSONB, /* { table: string; column: string; silent: boolean } */
29
- checked_path TEXT[] DEFAULT ARRAY[]::TEXT[]
30
- ) RETURNS boolean AS
31
- $f$
32
- DECLARE
33
- sub_schema RECORD;
34
- array_element RECORD;
35
- obj_key_val RECORD;
36
- schema JSONB;
37
- path text;
38
- allowed_types text[] = '{${JSONB_DATA_TYPES.join(",")}}';
39
- typeStr TEXT = NULL;
40
- optional boolean;
41
- nullable boolean;
42
- colname TEXT = COALESCE(context->>'column', '');
43
- tablename TEXT = COALESCE(context->>'table', '');
44
- oneof JSONB;
45
- arrayof JSONB;
46
- lookup_data_def_schema TEXT = $d$
47
- {
48
- "type": { "enum": ["data", "data-def"] },
49
- "table": "string",
50
- "column": "string",
51
- "lookup": { "type": "any", "optional": true },
52
- "isArray": { "type": "boolean", "optional": true },
53
- "filter": { "optional": true, "type": "any" },
54
- "isFullRow": { "optional": true, "type": {
55
- "displayColumns": { "optional": true, "type": "string[]" }
56
- }},
57
- "searchColumns": { "optional": true, "type": "string[]" },
58
- "showInRowCard": { "optional": true, "type": "any" }
59
- }
60
-
61
- $d$;
62
- lookup_schema_schema TEXT = $d$
63
- {
64
- "type": { "enum": ["schema"] },
65
- "object": { "enum": ["table", "column"] },
66
- "isArray": { "type": "boolean", "optional": true },
67
- "lookup": { "type": "any", "optional": true },
68
- "filter": { "optional": true, "type": "any" }
69
- }
70
- $d$;
71
-
72
- extra_keys TEXT[];
73
-
74
- /* Used for oneOf schema errors */
75
- v_state TEXT;
76
- v_msg TEXT;
77
- v_detail TEXT;
78
- v_hint TEXT;
79
- v_context TEXT;
80
- v_one_of_errors TEXT;
81
-
82
- BEGIN
83
- path = concat_ws(', ',
84
- 'Path: ' || array_to_string(checked_path, '.'),
85
- 'Data: ' || data::TEXT,
86
- 'JSONBSchema: ' || schema::TEXT
87
- );
88
-
89
- IF length(jsonb_schema) = 0 THEN
90
- ${raiseException(`'Empty schema. %', path`)}
91
- END IF;
92
-
93
- /* Sometimes text comes double quoted from jsonb, e.g.: '"string"' */
94
- jsonb_schema = CASE WHEN jsonb_schema::text ilike '"%"' THEN LEFT(RIGHT(jsonb_schema::text, -1), -1) ELSE jsonb_schema END;
95
-
96
- /* 'string' */
97
- IF ARRAY[jsonb_schema] <@ allowed_types THEN
98
- schema = jsonb_build_object('type', jsonb_schema);
99
- /* { "type": ... } */
100
- ELSIF BTRIM(replace(jsonb_schema,E'\n','')) ILIKE '{%' THEN
101
- schema = jsonb_schema::JSONB;
102
- ELSE
103
- ${raiseException(`$$Invalid schema. Expecting 'typename' or { "type": "typename" } but received: %, %$$, jsonb_schema, path`)}
104
- END IF;
105
-
106
-
107
- nullable = COALESCE((schema->>'nullable')::BOOLEAN, FALSE);
108
- IF data IS NULL OR jsonb_typeof(data) = 'null' THEN
109
- IF NOT nullable THEN
110
- ${raiseException(`'Is not nullable. %', path`)}
111
- ELSE
112
- RETURN true;
113
- END IF;
114
- END IF;
115
-
116
- IF schema ? 'enum' THEN
117
- IF
118
- jsonb_typeof(schema->'enum') != 'array' OR
119
- jsonb_array_length(schema->'enum') < 1
120
- THEN
121
- ${raiseException(`'Invalid schema enum (%) .Must be a non empty array %', schema->'enum', path`)}
122
- END IF;
123
-
124
- IF NOT jsonb_build_array(data) <@ (schema->'enum') THEN
125
- ${raiseException(`'Data not in allowed enum list (%), %', schema->'enum', path`)}
126
- END IF;
127
-
128
- ELSIF schema ? 'lookup' THEN
129
-
130
- /* TODO: Finish validating data-def */
131
- IF (schema->'lookup'->>'type' = 'data-def') THEN
132
- RETURN TRUE;
133
- END IF;
134
-
135
- /* Validate lookup schema */
136
- IF NOT ${VALIDATE_SCHEMA_FUNCNAME}(
137
- '{ "oneOfType": [' || concat_ws(',',lookup_data_def_schema, lookup_schema_schema) || '] }',
138
- schema->'lookup',
139
- context,
140
- checked_path || '.schema'::TEXT
141
- ) THEN
142
-
143
- RETURN FALSE;
144
- END IF;
145
-
146
- RETURN ${VALIDATE_SCHEMA_FUNCNAME}(
147
- CASE WHEN schema->'lookup'->>'type' = 'data-def' THEN
148
- lookup_data_def_schema
149
- WHEN schema->'lookup'->>'type' = 'schema' THEN
150
- (
151
- CASE WHEN schema->'lookup'->>'object' = 'table' THEN
152
- 'string' || (CASE WHEN (schema->'lookup'->'isArray')::BOOLEAN THEN '[]' ELSE '' END)
153
- ELSE
154
- '{ "type": { "table": "string", "column": "string' || (CASE WHEN (schema->'lookup'->'isArray')::BOOLEAN THEN '[]' ELSE '' END) || '" } }'
155
- END
156
- )
157
- ELSE
158
- (CASE WHEN (schema->'lookup'->'isArray')::BOOLEAN THEN 'any[]' ELSE 'any' END)
159
- END,
160
- data,
161
- context,
162
- checked_path
163
- );
164
-
165
- ELSIF schema ? 'type' THEN
166
-
167
- IF jsonb_typeof(schema->'type') = 'string' THEN
168
- typeStr = schema->>'type';
169
- IF NOT ARRAY[typeStr] <@ allowed_types THEN
170
- ${raiseException(`'Bad schema type "%", allowed types: %. %',typeStr, allowed_types, path`)}
171
- END IF;
172
-
173
- /** Primitive array */
174
- IF typeStr LIKE '%[]' THEN
175
-
176
- typeStr = left(typeStr, -2);
177
-
178
- IF jsonb_typeof(data) != 'array' THEN
179
- ${raiseException(`'Types not matching. Expecting an array. %', path`)}
180
- END IF;
181
-
182
- FOR array_element IN
183
- SELECT value, row_number() OVER() -1 as idx
184
- FROM jsonb_array_elements(data)
185
- LOOP
186
- IF NOT ${VALIDATE_SCHEMA_FUNCNAME}(
187
- CASE WHEN schema->'allowedValues' IS NOT NULL THEN
188
- jsonb_build_object('type', typeStr, 'allowedValues', schema->'allowedValues')::TEXT
189
- ELSE typeStr END,
190
- array_element.value,
191
- context,
192
- checked_path || array_element.idx::TEXT
193
- ) THEN
194
-
195
- RETURN FALSE;
196
- END IF;
197
- END LOOP;
198
-
199
- RETURN TRUE;
200
-
201
- /** Primitive */
202
- ELSE
203
-
204
- IF (
205
- typeStr = 'number' AND jsonb_typeof(data) != typeStr OR
206
- (typeStr = 'integer' AND (jsonb_typeof(data) != 'number' OR ceil(data::NUMERIC) != floor(data::NUMERIC))) OR
207
- typeStr = 'boolean' AND jsonb_typeof(data) != typeStr OR
208
- typeStr = 'string' AND jsonb_typeof(data) != typeStr OR
209
- typeStr = 'any' AND jsonb_typeof(data) = 'null'
210
- ) THEN
211
- ${raiseException(`'Data type not matching. Expected: %, Actual: %, %', typeStr, jsonb_typeof(data), path`)}
212
- END IF;
213
-
214
- IF schema ? 'allowedValues' AND NOT(jsonb_build_array(data) <@ (schema->'allowedValues')) THEN
215
- IF (
216
- SELECT COUNT(distinct jsonb_typeof(value))
217
- FROM jsonb_array_elements(schema->'allowedValues')
218
- ) > 1 THEN
219
- ${raiseException(`'Invalid schema. schema.allowedValues (%) contains more than one data type . %', schema->>'allowedValues', path`)}
220
- END IF;
221
-
222
- IF EXISTS(
223
- SELECT 1
224
- FROM jsonb_array_elements(schema->'allowedValues')
225
- WHERE jsonb_typeof(value) != jsonb_typeof(data)
226
- ) THEN
227
- ${raiseException(`'Invalid schema. schema.allowedValues (%) contains contains values not matchine the schema.type %', schema->>'allowedValues', path`)}
228
- END IF;
229
-
230
- ${raiseException(`'Data not in allowedValues (%). %', schema->>'allowedValues', path`)}
231
-
232
- END IF;
233
-
234
- END IF;
235
-
236
- /* Object */
237
- ELSIF jsonb_typeof(schema->'type') = 'object' THEN
238
-
239
- IF jsonb_typeof(data) != 'object' THEN
240
- ${raiseException(`E'Expecting an object: \n %', path`)}
241
- END IF;
242
-
243
- extra_keys = ARRAY(SELECT k FROM (
244
- SELECT jsonb_object_keys(data) as k
245
- EXCEPT
246
- SELECT jsonb_object_keys(schema->'type') as k
247
- ) t);
248
-
249
- IF array_length(extra_keys, 1) > 0 THEN
250
- ${raiseException(`E'Object contains % invalid keys: [ % ] \n %', array_length(extra_keys, 1)::TEXT, array_to_string(extra_keys, ', '), path`)}
251
- END IF;
252
-
253
- FOR sub_schema IN
254
- SELECT key, value
255
- FROM jsonb_each(schema->'type')
256
- LOOP
257
-
258
- optional = COALESCE((sub_schema.value->>'optional')::BOOLEAN, FALSE);
259
- IF NOT (data ? sub_schema.key) THEN
260
- IF NOT optional THEN
261
- ${raiseException(`'Types not matching. Required property ("%") is missing. %', sub_schema.key , path`)}
262
- END IF;
263
-
264
- ELSIF NOT ${VALIDATE_SCHEMA_FUNCNAME}(
265
- -- sub_schema.value::TEXT,
266
- CASE WHEN jsonb_typeof(sub_schema.value) = 'string' THEN TRIM(both '"' from sub_schema.value::TEXT) ELSE sub_schema.value::TEXT END,
267
- data->sub_schema.key,
268
- context,
269
- checked_path || sub_schema.key
270
- ) THEN
271
- RETURN false;
272
- END IF;
273
-
274
- END LOOP;
275
-
276
- RETURN TRUE;
277
- ELSE
278
- ${raiseException(`'Unexpected schema.type ( % ), %',jsonb_typeof(schema->'type'), path`)}
279
- END IF;
280
-
281
- /* oneOfType: [{ key_name: { type: "string" } }] */
282
- ELSIF (schema ? 'oneOf' OR schema ? 'oneOfType') THEN
283
-
284
- oneof = COALESCE(schema->'oneOf', schema->'oneOfType');
285
-
286
- IF jsonb_typeof(oneof) != 'array' THEN
287
- ${raiseException(`'Unexpected oneOf schema. Expecting an array of objects but received: % , %', oneof::TEXT, path`)}
288
- END IF;
289
-
290
- FOR sub_schema IN
291
- SELECT CASE WHEN schema ? 'oneOfType' THEN jsonb_build_object('type', value) ELSE value END as value,
292
- row_number() over() - 1 as idx
293
- FROM jsonb_array_elements(oneof)
294
- LOOP
295
-
296
- BEGIN
297
-
298
- IF ${VALIDATE_SCHEMA_FUNCNAME}(
299
- sub_schema.value::TEXT,
300
- data,
301
- context,
302
- checked_path
303
- ) THEN
304
- RETURN true;
305
- END IF;
306
-
307
- /* Ignore exceptions in case the last schema will match */
308
- EXCEPTION WHEN others THEN
309
-
310
- GET STACKED DIAGNOSTICS
311
- v_state = returned_sqlstate,
312
- v_msg = message_text,
313
- v_detail = pg_exception_detail,
314
- v_hint = pg_exception_hint,
315
- v_context = pg_exception_context;
316
-
317
- /* Ignore duplicate errors */
318
- IF v_one_of_errors IS NULL OR v_one_of_errors NOT ilike '%' || v_msg || '%' THEN
319
- v_one_of_errors = concat_ws(
320
- E'\n\n',
321
- v_one_of_errors,
322
- concat_ws(
323
- ', ',
324
- 'Schema index ' || sub_schema.idx::TEXT || ' error:',
325
- 'state: ' || v_state,
326
- 'message: ' || v_msg,
327
- 'detail: ' || v_detail,
328
- 'hint: ' || v_hint
329
- -- 'context: ' || v_context
330
- )
331
- );
332
- END IF;
333
- END;
334
-
335
- END LOOP;
336
-
337
- ${raiseException(`E'No oneOf schemas matching:\n % ), %', v_one_of_errors, path`)}
338
-
339
- /* arrayOfType: { key_name: { type: "string" } } */
340
- ELSIF (schema ? 'arrayOf' OR schema ? 'arrayOfType') THEN
341
-
342
- arrayof = COALESCE(schema->'arrayOf', schema->'arrayOfType');
343
-
344
- IF jsonb_typeof(data) != 'array' THEN
345
- ${raiseException(`'% is not an array.', path`)}
346
- END IF;
347
-
348
- FOR array_element IN
349
- SELECT value, row_number() OVER() -1 as idx
350
- FROM jsonb_array_elements(data)
351
- LOOP
352
- IF NOT ${VALIDATE_SCHEMA_FUNCNAME}(
353
- ( CASE WHEN schema ? 'arrayOf'
354
- THEN
355
- schema->'arrayOf'
356
- ELSE
357
- (schema - 'arrayOfType' || jsonb_build_object('type', schema->'arrayOfType'))
358
- END
359
- )::TEXT,
360
- array_element.value,
361
- context,
362
- checked_path || array_element.idx::TEXT
363
- ) THEN
364
- RETURN false;
365
- END IF;
366
- END LOOP;
367
-
368
- /* record: { keysEnum?: string[], values?: FieldType } */
369
- ELSIF schema ? 'record' THEN
370
- IF
371
- jsonb_typeof(schema->'record') != 'object' OR
372
- NOT (schema->'record') ? 'keysEnum'
373
- AND NOT (schema->'record') ? 'values'
374
- THEN
375
- ${raiseException(`'Invalid/empty record schema. Expecting a non empty record of: { keysEnum?: string[]; values?: FieldType } : %, %', schema, path`)}
376
- END IF;
377
-
378
- IF jsonb_typeof(data) != 'object' THEN
379
- ${raiseException(`'% is not an object.', path`)}
380
- END IF;
381
-
382
- FOR obj_key_val IN
383
- SELECT jsonb_build_object('key', key, 'value', value) as obj
384
- FROM jsonb_each(data)
385
- LOOP
386
- RETURN (CASE WHEN NOT (schema->'record') ? 'keysEnum' THEN TRUE ELSE ${VALIDATE_SCHEMA_FUNCNAME}(
387
- jsonb_build_object('enum', schema->'record'->'keysEnum')::TEXT,
388
- (obj_key_val.obj)->'key',
389
- context,
390
- checked_path || ARRAY[(obj_key_val.obj)->>'key']
391
- ) END)
392
- AND
393
- (CASE WHEN NOT (schema->'record') ? 'values' THEN TRUE ELSE ${VALIDATE_SCHEMA_FUNCNAME}(
394
- schema->'record'->>'values',
395
- (obj_key_val.obj)->'value',
396
- context,
397
- checked_path || ARRAY[(obj_key_val.obj)->>'key']
398
- ) END);
399
- END LOOP;
400
-
401
- ELSE
402
- ${raiseException(`'Unexpected schema: %, %', schema, path`)}
403
- END IF;
404
-
405
- RETURN true;
406
- END;
407
- $f$ LANGUAGE 'plpgsql' IMMUTABLE;
408
-
409
- COMMENT ON FUNCTION ${VALIDATE_SCHEMA_FUNCNAME} /* ${PubSubManager.EXCLUDE_QUERY_FROM_SCHEMA_WATCH_ID} */
410
- IS $$prostgles-server internal function used in column CHECK conditions to validate jsonb data against a column schema specified in tableConfig.
411
- Example usage:
412
- validate_jsonb_schema(
413
- '{ "type": { "a": "number[]" } }',
414
- '{ "a": [2] }'
415
- )
416
- $$;
417
-
418
-
419
- /* TESTS */
420
-
421
- SELECT ${VALIDATE_SCHEMA_FUNCNAME}(
422
- '{ "enum": ["a", "b", 2] }',
423
- '"a"'::JSONB
424
- );
425
-
426
-
427
- SELECT ${VALIDATE_SCHEMA_FUNCNAME}(
428
- '{ "record": { "keysEnum": ["a", "b"] , "values": { "enum": [1, 2] } } }',
429
- '{"a": 1, "b": 2 }'::JSONB
430
- );
431
-
432
- SELECT ${VALIDATE_SCHEMA_FUNCNAME}(
433
- '{ "record": { "keysEnum": ["a", "b"] , "values": { "enum": [1, 2] } } }',
434
- '{"a": 1 }'::JSONB
435
- );
436
-
437
- SELECT ${VALIDATE_SCHEMA_FUNCNAME}(
438
- '{ "record": { "keysEnum": ["a", "b"] , "values": { "enum": [1, 2] } } }',
439
- '{ }'::JSONB
440
- );
441
-
442
- SELECT ${VALIDATE_SCHEMA_FUNCNAME}(
443
- '{ "record": { "keysEnum": ["a", "b"] } }',
444
- '{"a": 1, "b": 2 }'::JSONB
445
- );
446
- SELECT ${VALIDATE_SCHEMA_FUNCNAME}(
447
- '{ "enum": ["a", "b", 2] }',
448
- '2'::JSONB
449
- );
450
-
451
- SELECT ${VALIDATE_SCHEMA_FUNCNAME}(
452
- '{
453
- "oneOfType": [
454
- { "a": "string" } ,
455
- {
456
- "a": {
457
- "type": "boolean",
458
- "allowedValues": [false],
459
- "optional": true
460
- }
461
- }
462
- ]
463
- }',
464
- '{ "a": false }'
465
- );
466
-
467
- SELECT ${VALIDATE_SCHEMA_FUNCNAME}(
468
- '{ "arrayOfType": { "a": "string", "narr": { "arrayOfType": { "a": { "type": "string", "optional": false, "nullable": true } } } } }',
469
- '[{ "a": "ddd", "narr": [{ "a": null }] }]'::JSONB
470
- );
471
-
472
- SELECT ${VALIDATE_SCHEMA_FUNCNAME}(
473
- '{ "type": { "a": { "type": "integer[]", "allowedValues": [2] } } }'::TEXT,
474
- '{ "a": [2, 2] }'
475
- );
476
-
477
- SELECT ${VALIDATE_SCHEMA_FUNCNAME}(
478
- '{ "type": { "a": { "type": "string[]", "allowedValues": ["2"] } } }'::TEXT,
479
- '{ "a": ["2"] }'
480
- );
481
-
482
- SELECT ${VALIDATE_SCHEMA_FUNCNAME}('{ "type": "any"}', '{}');
483
-
484
- SELECT ${VALIDATE_SCHEMA_FUNCNAME}('{ "type": { "a": { "enum": ["a"] } } }', '{ "a": "a"}');
485
-
486
- SELECT ${VALIDATE_SCHEMA_FUNCNAME}('{ "arrayOfType": { "a": { "enum": ["a"] } } }', '[{ "a": "a"}]');
487
-
488
-
489
- SELECT ${VALIDATE_SCHEMA_FUNCNAME}('{ "lookup": { "type": "data", "table": "tblName", "column": "colName" } }', '{}');
490
- SELECT ${VALIDATE_SCHEMA_FUNCNAME}('{ "lookup": { "type": "data", "table": "tblName", "column": "colName", "isArray": true } }', '[{}]');
491
- SELECT ${VALIDATE_SCHEMA_FUNCNAME}('{ "lookup": { "type": "schema", "object": "table" } }', '"tblName"'::JSONB);
492
- SELECT ${VALIDATE_SCHEMA_FUNCNAME}('{ "lookup": { "type": "schema", "object": "table", "isArray": true } }', '["tblName"]');
493
- SELECT ${VALIDATE_SCHEMA_FUNCNAME}('{ "lookup": { "type": "schema", "object": "column" } }', '{ "table": "tblName", "column": "colName" }');
494
- SELECT ${VALIDATE_SCHEMA_FUNCNAME}('{ "lookup": { "type": "schema", "object": "column", "isArray": true } }', '{ "table": "tblName", "column": ["colName"] }');
495
-
496
- SELECT ${VALIDATE_SCHEMA_FUNCNAME}('{ "type": "time"}', '"22:22"');
497
- SELECT ${VALIDATE_SCHEMA_FUNCNAME}('{ "type": "Date"}', '"2222-22-22"');
498
-
499
-
500
- SELECT ${VALIDATE_SCHEMA_FUNCNAME}('{ "oneOf": ["number"]}','2');
501
- `;
502
-
@@ -1,143 +0,0 @@
1
- import { getKeys, isEmpty, isObject, JSONB, TableSchema } from "prostgles-types";
2
- import { postgresToTsType } from "../DboBuilder/DboBuilder";
3
- import { asValue } from "../PubSubManager/PubSubManager";
4
-
5
-
6
-
7
- const getFieldTypeObj = (rawFieldType: JSONB.FieldType): JSONB.FieldTypeObj => {
8
- if(typeof rawFieldType === "string") return { type: rawFieldType };
9
-
10
- return rawFieldType;
11
- }
12
-
13
- export function validate<T>(obj: T, key: keyof T, rawFieldType: JSONB.FieldType): boolean {
14
- let err = `The provided value for ${JSON.stringify(key)} is of invalid type. Expecting `;
15
- const val = obj[key];
16
- const fieldType = getFieldTypeObj(rawFieldType);
17
- if ("type" in fieldType && fieldType.type) {
18
- if (typeof fieldType.type !== "string") {
19
- getKeys(fieldType.type).forEach(subKey => {
20
- validate(val, subKey as any, (fieldType.type as JSONB.ObjectType["type"])[subKey]!)
21
- });
22
- }
23
- err += fieldType.type;
24
- if (fieldType.type === "boolean" && typeof val !== fieldType.type) throw new Error(err)
25
- if (fieldType.type === "string" && typeof val !== fieldType.type) throw new Error(err)
26
- if (fieldType.type === "number" && !Number.isFinite(val)) throw new Error(err)
27
- if (fieldType.type === "integer" && !Number.isInteger(val)) throw new Error(err);
28
-
29
- } else if (fieldType.enum) {
30
- err += `on of: ${fieldType.enum}`;
31
- if (!fieldType.enum.includes(val)) throw new Error(err)
32
- }
33
- return true
34
- }
35
-
36
- export function validateSchema<S extends JSONB.ObjectType["type"]>(schema: S, obj: JSONB.GetObjectType<S>, objName?: string, optional = false) {
37
- if ((!schema || isEmpty(schema)) && !optional) throw new Error(`Expecting ${objName} to be defined`);
38
- getKeys(schema).forEach(k => validate(obj as any, k, schema[k]!));
39
- }
40
-
41
-
42
- type ColOpts = { nullable?: boolean };
43
-
44
-
45
- export function getJSONBSchemaTSTypes(schema: JSONB.JSONBSchema, colOpts: ColOpts, outerLeading = "", tables: TableSchema[]): string {
46
-
47
- const getFieldType = (rawFieldType: JSONB.FieldType, isOneOf = false, innerLeading = "", depth = 0): string => {
48
- const fieldType = getFieldTypeObj(rawFieldType);
49
- const nullType = (fieldType.nullable ? `null | ` : "");
50
-
51
- /** Primitives */
52
- if (typeof fieldType?.type === "string") {
53
- const correctType = fieldType.type
54
- .replace("integer", "number")
55
- .replace("time", "string")
56
- .replace("timestamp", "string")
57
- .replace("Date", "string");
58
-
59
- if (fieldType.allowedValues && fieldType.type.endsWith("[]")) {
60
- return nullType + ` (${fieldType.allowedValues.map(v => JSON.stringify(v)).join(" | ")})[]`
61
- }
62
- return nullType + correctType;
63
-
64
- /** Object */
65
- } else if (isObject(fieldType.type)) {
66
- const addSemicolonIfMissing = (v: string) => v.trim().endsWith(";")? v : (v.trim() + ";");
67
- const { type } = fieldType;
68
- const spacing = isOneOf ? " " : " ";
69
- let objDef = ` {${spacing}` + getKeys(type).map(key => {
70
- const fieldType = getFieldTypeObj(type[key]!);
71
- const escapedKey = isValidIdentifier(key) ? key : JSON.stringify(key);
72
- return `${spacing}${escapedKey}${fieldType.optional ? "?" : ""}: ` + addSemicolonIfMissing(getFieldType(fieldType, true, undefined, depth + 1));
73
- }).join(" ") + `${spacing}}`;
74
- if(!isOneOf){
75
- objDef = addSemicolonIfMissing(objDef);
76
- }
77
-
78
- /** Keep single line */
79
- if (isOneOf){
80
- objDef = objDef.split("\n").join("");
81
- }
82
- return nullType + objDef;
83
-
84
- } else if (fieldType?.enum) {
85
- return nullType + fieldType.enum.map(v => asValue(v)).join(" | ");
86
-
87
- } else if (fieldType?.oneOf || fieldType?.oneOfType) {
88
- const oneOf = fieldType?.oneOf || fieldType?.oneOfType.map(type => ({ type }));
89
- return (fieldType.nullable ? `\n${innerLeading} | null` : "") + oneOf.map(v => `\n${innerLeading} | ` + getFieldType(v, true, undefined, depth + 1)).join("");
90
-
91
- } else if (fieldType?.arrayOf || fieldType?.arrayOfType) {
92
- const arrayOf = fieldType?.arrayOf || { type: fieldType?.arrayOfType };
93
- return `${fieldType.nullable ? `null | ` : ""} ( ${getFieldType(arrayOf, true, undefined, depth + 1)} )[]`;
94
-
95
- } else if (fieldType?.record) {
96
- const { keysEnum, values, partial } = fieldType.record;
97
- // TODO: ensure props with undefined values are not allowed in the TS type (strict union)
98
- const getRecord = (v: string) => partial? `Partial<Record<${v}>>` : `Record<${v}>`;
99
- return `${fieldType.nullable ? `null |` : ""} ${getRecord(`${keysEnum?.map(v => asValue(v)).join(" | ") ?? "string"}, ${!values? "any" : getFieldType(values, true, undefined, depth + 1)}`)}`
100
-
101
- } else if(fieldType?.lookup){
102
-
103
- const l = fieldType.lookup;
104
- if(l.type === "data-def"){
105
- return `${fieldType.nullable ? `null |` : ""} ${
106
- getFieldType({
107
- type: {
108
- table: "string",
109
- column: "string",
110
- filter: { record: {}, optional: true },
111
- isArray: { type: "boolean", optional: true },
112
- searchColumns: { type: "string[]", optional: true },
113
- isFullRow: { optional: true, type: {
114
- displayColumns:{ type: "string[]", optional: true }
115
- }},
116
- showInRowCard: { optional: true, record: {} }
117
- }
118
- })
119
- }`;
120
- }
121
-
122
- const isSChema = l.type === "schema";
123
- let type = isSChema? (l.object === "table"? "string" : `{ "table": string; "column": string; }`) : "";
124
- if(!isSChema){
125
- const cols = tables.find(t => t.name === l.table)?.columns
126
- if(!l.isFullRow){
127
- type = postgresToTsType(cols?.find(c => c.name === l.column)?.udt_name ?? "text");
128
- } else {
129
- type = !cols? "any" : `{ ${cols.map(c => `${JSON.stringify(c.name)}: ${c.is_nullable? "null | " : "" } ${postgresToTsType(c.udt_name)}; `).join(" ")} }`
130
- }
131
- }
132
- return `${fieldType.nullable ? `null | ` : ""}${type}${l.isArray? "[]" : ""}`;
133
-
134
- } else throw "Unexpected getSchemaTSTypes: " + JSON.stringify({ fieldType, schema }, null, 2)
135
- }
136
-
137
- return getFieldType({ ...schema as any, nullable: colOpts.nullable }, undefined, outerLeading);
138
- }
139
-
140
- const isValidIdentifier = (str: string) => {
141
- const identifierRegex = /^[A-Za-z$_][A-Za-z0-9$_]*$/;
142
- return identifierRegex.test(str);
143
- }