prostgles-server 4.2.4 → 4.2.6

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 (160) hide show
  1. package/README.md +1 -1
  2. package/dist/AuthHandler.js +1 -1
  3. package/dist/AuthHandler.js.map +1 -1
  4. package/dist/DBEventsManager.js.map +1 -1
  5. package/dist/DBSchemaBuilder.d.ts +11 -6
  6. package/dist/DBSchemaBuilder.d.ts.map +1 -1
  7. package/dist/DBSchemaBuilder.js +8 -0
  8. package/dist/DBSchemaBuilder.js.map +1 -1
  9. package/dist/DboBuilder/DboBuilder.d.ts.map +1 -1
  10. package/dist/DboBuilder/DboBuilder.js +1 -0
  11. package/dist/DboBuilder/DboBuilder.js.map +1 -1
  12. package/dist/DboBuilder/DboBuilderTypes.d.ts +6 -1
  13. package/dist/DboBuilder/DboBuilderTypes.d.ts.map +1 -1
  14. package/dist/DboBuilder/DboBuilderTypes.js.map +1 -1
  15. package/dist/DboBuilder/QueryBuilder/Functions.js +4 -4
  16. package/dist/DboBuilder/QueryBuilder/Functions.js.map +1 -1
  17. package/dist/DboBuilder/QueryBuilder/QueryBuilder.js +1 -1
  18. package/dist/DboBuilder/QueryBuilder/QueryBuilder.js.map +1 -1
  19. package/dist/DboBuilder/QueryBuilder/getJoinQuery.js.map +1 -1
  20. package/dist/DboBuilder/QueryBuilder/getNewQuery.d.ts +1 -1
  21. package/dist/DboBuilder/QueryBuilder/getNewQuery.js.map +1 -1
  22. package/dist/DboBuilder/QueryBuilder/getSelectQuery.js.map +1 -1
  23. package/dist/DboBuilder/QueryStreamer.js.map +1 -1
  24. package/dist/DboBuilder/TableHandler/DataValidator.d.ts +63 -0
  25. package/dist/DboBuilder/TableHandler/DataValidator.d.ts.map +1 -0
  26. package/dist/DboBuilder/TableHandler/DataValidator.js +259 -0
  27. package/dist/DboBuilder/TableHandler/DataValidator.js.map +1 -0
  28. package/dist/DboBuilder/TableHandler/TableHandler.d.ts +11 -11
  29. package/dist/DboBuilder/TableHandler/TableHandler.d.ts.map +1 -1
  30. package/dist/DboBuilder/TableHandler/TableHandler.js +4 -23
  31. package/dist/DboBuilder/TableHandler/TableHandler.js.map +1 -1
  32. package/dist/DboBuilder/TableHandler/delete.js.map +1 -1
  33. package/dist/DboBuilder/TableHandler/insert.d.ts.map +1 -1
  34. package/dist/DboBuilder/TableHandler/insert.js +40 -9
  35. package/dist/DboBuilder/TableHandler/insert.js.map +1 -1
  36. package/dist/DboBuilder/TableHandler/insertTest.js.map +1 -1
  37. package/dist/DboBuilder/TableHandler/onDeleteFromFileTable.js.map +1 -1
  38. package/dist/DboBuilder/TableHandler/runInsertUpdateQuery.d.ts +2 -1
  39. package/dist/DboBuilder/TableHandler/runInsertUpdateQuery.d.ts.map +1 -1
  40. package/dist/DboBuilder/TableHandler/runInsertUpdateQuery.js +5 -4
  41. package/dist/DboBuilder/TableHandler/runInsertUpdateQuery.js.map +1 -1
  42. package/dist/DboBuilder/TableHandler/update.d.ts +1 -1
  43. package/dist/DboBuilder/TableHandler/update.d.ts.map +1 -1
  44. package/dist/DboBuilder/TableHandler/update.js +22 -29
  45. package/dist/DboBuilder/TableHandler/update.js.map +1 -1
  46. package/dist/DboBuilder/TableHandler/updateBatch.js +1 -1
  47. package/dist/DboBuilder/TableHandler/updateBatch.js.map +1 -1
  48. package/dist/DboBuilder/TableHandler/updateFile.d.ts.map +1 -1
  49. package/dist/DboBuilder/TableHandler/updateFile.js +1 -1
  50. package/dist/DboBuilder/TableHandler/updateFile.js.map +1 -1
  51. package/dist/DboBuilder/ViewHandler/ViewHandler.d.ts +4 -12
  52. package/dist/DboBuilder/ViewHandler/ViewHandler.d.ts.map +1 -1
  53. package/dist/DboBuilder/ViewHandler/ViewHandler.js +5 -46
  54. package/dist/DboBuilder/ViewHandler/ViewHandler.js.map +1 -1
  55. package/dist/DboBuilder/ViewHandler/getExistsCondition.js.map +1 -1
  56. package/dist/DboBuilder/ViewHandler/getExistsFilters.js.map +1 -1
  57. package/dist/DboBuilder/ViewHandler/getTableJoinQuery.js.map +1 -1
  58. package/dist/DboBuilder/ViewHandler/parseFieldFilter.js.map +1 -1
  59. package/dist/DboBuilder/ViewHandler/parseJoinPath.js.map +1 -1
  60. package/dist/DboBuilder/ViewHandler/prepareSortItems.js.map +1 -1
  61. package/dist/DboBuilder/ViewHandler/prepareWhere.js.map +1 -1
  62. package/dist/DboBuilder/ViewHandler/validateViewRules.js.map +1 -1
  63. package/dist/DboBuilder/dboBuilderUtils.d.ts +4 -0
  64. package/dist/DboBuilder/dboBuilderUtils.d.ts.map +1 -1
  65. package/dist/DboBuilder/dboBuilderUtils.js +4 -0
  66. package/dist/DboBuilder/dboBuilderUtils.js.map +1 -1
  67. package/dist/DboBuilder/find.js.map +1 -1
  68. package/dist/DboBuilder/getColumns.d.ts.map +1 -1
  69. package/dist/DboBuilder/getColumns.js +5 -6
  70. package/dist/DboBuilder/getColumns.js.map +1 -1
  71. package/dist/DboBuilder/getCondition.js.map +1 -1
  72. package/dist/DboBuilder/getSubscribeRelatedTables.js +1 -1
  73. package/dist/DboBuilder/getSubscribeRelatedTables.js.map +1 -1
  74. package/dist/DboBuilder/getTablesForSchemaPostgresSQL.js.map +1 -1
  75. package/dist/DboBuilder/insertNestedRecords.d.ts +35 -0
  76. package/dist/DboBuilder/insertNestedRecords.d.ts.map +1 -0
  77. package/dist/DboBuilder/insertNestedRecords.js +270 -0
  78. package/dist/DboBuilder/insertNestedRecords.js.map +1 -0
  79. package/dist/DboBuilder/parseMediaOrNestedInsert.d.ts +29 -0
  80. package/dist/DboBuilder/parseMediaOrNestedInsert.d.ts.map +1 -0
  81. package/dist/DboBuilder/parseMediaOrNestedInsert.js +271 -0
  82. package/dist/DboBuilder/parseMediaOrNestedInsert.js.map +1 -0
  83. package/dist/DboBuilder/parseUpdateRules.d.ts +3 -3
  84. package/dist/DboBuilder/parseUpdateRules.d.ts.map +1 -1
  85. package/dist/DboBuilder/parseUpdateRules.js +21 -13
  86. package/dist/DboBuilder/parseUpdateRules.js.map +1 -1
  87. package/dist/DboBuilder/prepareShortestJoinPaths.js.map +1 -1
  88. package/dist/DboBuilder/runSQL.js.map +1 -1
  89. package/dist/DboBuilder/subscribe.js.map +1 -1
  90. package/dist/DboBuilder/uploadFile.js.map +1 -1
  91. package/dist/FileManager/FileManager.js.map +1 -1
  92. package/dist/FileManager/getValidatedFileType.js.map +1 -1
  93. package/dist/FileManager/initFileManager.js.map +1 -1
  94. package/dist/FileManager/upload.js.map +1 -1
  95. package/dist/FileManager/uploadStream.js.map +1 -1
  96. package/dist/Filtering.js.map +1 -1
  97. package/dist/JSONBValidation/validation.js.map +1 -1
  98. package/dist/PostgresNotifListenManager.js.map +1 -1
  99. package/dist/Prostgles.js.map +1 -1
  100. package/dist/PubSubManager/PubSubManager.js.map +1 -1
  101. package/dist/PubSubManager/addSub.js.map +1 -1
  102. package/dist/PubSubManager/addSync.js.map +1 -1
  103. package/dist/PubSubManager/initPubSubManager.js.map +1 -1
  104. package/dist/PubSubManager/notifListener.js.map +1 -1
  105. package/dist/PubSubManager/pushSubData.js.map +1 -1
  106. package/dist/PublishParser/PublishParser.d.ts +1 -1
  107. package/dist/PublishParser/PublishParser.d.ts.map +1 -1
  108. package/dist/PublishParser/PublishParser.js.map +1 -1
  109. package/dist/PublishParser/getFileTableRules.js.map +1 -1
  110. package/dist/PublishParser/getSchemaFromPublish.js.map +1 -1
  111. package/dist/PublishParser/getTableRulesWithoutFileTable.js.map +1 -1
  112. package/dist/PublishParser/publishTypesAndUtils.d.ts +6 -5
  113. package/dist/PublishParser/publishTypesAndUtils.d.ts.map +1 -1
  114. package/dist/RestApi.js.map +1 -1
  115. package/dist/SchemaWatch.js.map +1 -1
  116. package/dist/SyncReplication.js.map +1 -1
  117. package/dist/TableConfig/TableConfig.d.ts +5 -5
  118. package/dist/TableConfig/TableConfig.d.ts.map +1 -1
  119. package/dist/TableConfig/TableConfig.js.map +1 -1
  120. package/dist/TableConfig/getColumnDefinitionQuery.js.map +1 -1
  121. package/dist/TableConfig/getConstraintDefinitionQueries.js.map +1 -1
  122. package/dist/TableConfig/getFutureTableSchema.js.map +1 -1
  123. package/dist/TableConfig/getTableColumnQueries.js.map +1 -1
  124. package/dist/TableConfig/initTableConfig.js.map +1 -1
  125. package/dist/initProstgles.js.map +1 -1
  126. package/dist/runClientRequest.js.map +1 -1
  127. package/dist/shortestPath.js.map +1 -1
  128. package/dist/utils.js.map +1 -1
  129. package/lib/AuthHandler.ts +3 -3
  130. package/lib/DBSchemaBuilder.ts +25 -10
  131. package/lib/DboBuilder/DboBuilder.ts +1 -0
  132. package/lib/DboBuilder/DboBuilderTypes.ts +17 -1
  133. package/lib/DboBuilder/QueryBuilder/QueryBuilder.ts +1 -1
  134. package/lib/DboBuilder/TableHandler/DataValidator.ts +425 -0
  135. package/lib/DboBuilder/TableHandler/TableHandler.ts +17 -36
  136. package/lib/DboBuilder/TableHandler/insert.ts +45 -13
  137. package/lib/DboBuilder/TableHandler/runInsertUpdateQuery.ts +8 -5
  138. package/lib/DboBuilder/TableHandler/update.ts +25 -37
  139. package/lib/DboBuilder/TableHandler/updateBatch.ts +4 -4
  140. package/lib/DboBuilder/TableHandler/updateFile.ts +4 -3
  141. package/lib/DboBuilder/ViewHandler/ViewHandler.ts +3 -54
  142. package/lib/DboBuilder/dboBuilderUtils.ts +4 -1
  143. package/lib/DboBuilder/getColumns.ts +6 -7
  144. package/lib/DboBuilder/{insertDataParse.ts → insertNestedRecords.ts} +58 -49
  145. package/lib/DboBuilder/parseUpdateRules.ts +22 -22
  146. package/lib/Prostgles.ts +1 -1
  147. package/lib/PublishParser/PublishParser.ts +1 -1
  148. package/lib/PublishParser/publishTypesAndUtils.ts +6 -5
  149. package/lib/TableConfig/TableConfig.ts +7 -6
  150. package/lib/TableConfig/initTableConfig.ts +1 -1
  151. package/lib/initProstgles.ts +1 -1
  152. package/package.json +3 -3
  153. package/tests/client/package-lock.json +23 -23
  154. package/tests/client/package.json +2 -2
  155. package/tests/client/tsconfig.json +1 -1
  156. package/tests/isomorphic_queries.ts +16 -10
  157. package/tests/server/package-lock.json +12 -12
  158. package/tests/server/package.json +1 -1
  159. package/tests/server_only_queries.ts +3 -1
  160. package/lib/DboBuilder/ViewHandler/ColSet.ts +0 -121
@@ -1,10 +1,12 @@
1
1
  import { AnyObject, InsertParams, isObject } from "prostgles-types";
2
2
  import { LocalParams, parseError, withUserRLS } from "../DboBuilder";
3
- import { TableRule } from "../../PublishParser/PublishParser";
4
- import { insertDataParse } from "../insertDataParse";
3
+ import { TableRule, ValidateRowBasic } from "../../PublishParser/PublishParser";
4
+ import { insertNestedRecords } from "../insertNestedRecords";
5
5
  import { insertTest } from "./insertTest";
6
6
  import { TableHandler } from "./TableHandler";
7
7
  import { runInsertUpdateQuery } from "./runInsertUpdateQuery";
8
+ import { prepareNewData } from "./DataValidator";
9
+ import { DBOFullyTyped } from "../../DBSchemaBuilder";
8
10
 
9
11
  export async function insert(this: TableHandler, rowOrRows: AnyObject | AnyObject[] = {}, insertParams?: InsertParams, param3_unused?: undefined, tableRules?: TableRule, localParams?: LocalParams): Promise<any | any[] | boolean> {
10
12
 
@@ -38,11 +40,26 @@ export async function insert(this: TableHandler, rowOrRows: AnyObject | AnyObjec
38
40
  }
39
41
  validateInsertParams(insertParams);
40
42
 
43
+ const isMultiInsert = Array.isArray(rowOrRows);
44
+ const preValidatedRows = await Promise.all((isMultiInsert? rowOrRows : [rowOrRows]).map(async nonValidated => {
45
+ const { preValidate, validate } = tableRules?.insert ?? {};
46
+ const { tableConfigurator } = this.dboBuilder.prostgles;
47
+ if(!tableConfigurator) throw "tableConfigurator missing";
48
+ let row = await tableConfigurator.getPreInsertRow(this, { dbx: this.getFinalDbo(localParams), validate, localParams, row: nonValidated })
49
+ if (preValidate) {
50
+ if(!localParams) throw "localParams missing for insert preValidate";
51
+ row = await preValidate({ row, dbx: (this.tx?.dbTX || this.dboBuilder.dbo) as any, localParams });
52
+ }
53
+
54
+ return row;
55
+ }));
56
+ const preValidatedrowOrRows = isMultiInsert? preValidatedRows : preValidatedRows[0]!;
57
+
41
58
  /**
42
59
  * If media it will: upload file and continue insert
43
60
  * If nested insert it will: make separate inserts and not continue main insert
44
61
  */
45
- const mediaOrNestedInsert = await insertDataParse.bind(this)(rowOrRows, insertParams, param3_unused, tableRules, localParams);
62
+ const mediaOrNestedInsert = await insertNestedRecords.bind(this)({ data: preValidatedrowOrRows, param2: insertParams, tableRules, localParams });
46
63
  const { data, insertResult } = mediaOrNestedInsert;
47
64
  if ("insertResult" in mediaOrNestedInsert) {
48
65
  return insertResult;
@@ -55,25 +72,38 @@ export async function insert(this: TableHandler, rowOrRows: AnyObject | AnyObjec
55
72
  const row = { ..._row };
56
73
 
57
74
  if (!isObject(row)) {
58
- console.trace(row)
59
- throw "\ninvalid insert data provided -> " + JSON.stringify(row);
75
+ throw "\nInvalid insert data provided. Expected an object but received: " + JSON.stringify(row);
60
76
  }
61
77
 
62
- const { data: validatedRow, allowedCols } = this.validateNewData({ row, forcedData, allowedFields: fields, tableRules, fixIssues });
78
+ const { data: validatedRow, allowedCols } = await prepareNewData({
79
+ row,
80
+ forcedData,
81
+ allowedFields: fields,
82
+ tableRules,
83
+ fixIssues,
84
+ tableConfigurator: this.dboBuilder.prostgles.tableConfigurator,
85
+ tableHandler: this,
86
+ });
63
87
  return { validatedRow, allowedCols };
64
88
  }));
65
89
  const validatedRows = validatedData.map(d => d.validatedRow);
66
- const allowedCols = Array.from( new Set(validatedData.flatMap(d => d.allowedCols)));
67
- const dbTx = finalDBtx || this.dboBuilder.dbo
68
- const query = await this.colSet.getInsertQuery(validatedRows, allowedCols, dbTx, validate, localParams);
69
-
90
+ const allowedCols = Array.from(new Set(validatedData.flatMap(d => d.allowedCols)));
91
+ const dbTx = finalDBtx || this.dboBuilder.dbo;
92
+ const validationOptions = { validate: validate as ValidateRowBasic, localParams };
93
+ // const query = await this.colSet.getInsertQuery(validatedRows, allowedCols, dbTx, validate, localParams);
94
+ const query = (await this.dataValidator.parse({ command: "insert", rows: validatedRows, allowedCols, dbTx, validationOptions })).getQuery();
70
95
  const { onConflict } = insertParams ?? {};
71
96
  let conflict_query = "";
72
97
  if (onConflict === "DoNothing") {
73
98
  conflict_query = " ON CONFLICT DO NOTHING ";
74
99
  } else if(onConflict === "DoUpdate"){
75
- if(!pkeyNames.length) throw "Cannot do DoUpdate on a table without a primary key";
100
+ if(!pkeyNames.length) {
101
+ throw "Cannot do DoUpdate on a table without a primary key";
102
+ }
76
103
  const nonPkeyCols = allowedCols.filter(c => !pkeyNames.includes(c));
104
+ if(!nonPkeyCols.length){
105
+ throw "Cannot on conflict DoUpdate on a table with only primary key columns";
106
+ }
77
107
  conflict_query = ` ON CONFLICT (${pkeyNames.join(", ")}) DO UPDATE SET ${nonPkeyCols.map(k => `${k} = EXCLUDED.${k}`).join(", ")}`;
78
108
  }
79
109
  return query + conflict_query;
@@ -100,14 +130,16 @@ export async function insert(this: TableHandler, rowOrRows: AnyObject | AnyObjec
100
130
  }
101
131
 
102
132
  return runInsertUpdateQuery({
103
- rule, localParams,
133
+ rule,
134
+ localParams,
104
135
  queryWithoutUserRLS,
105
136
  tableHandler: this,
106
137
  returningFields,
107
- data: rowOrRows,
138
+ data: preValidatedrowOrRows,
108
139
  fields,
109
140
  params: insertParams,
110
141
  type: "insert",
142
+ isMultiInsert,
111
143
  });
112
144
 
113
145
  } catch (e) {
@@ -2,6 +2,7 @@ import { AnyObject, asName, FieldFilter, InsertParams, UpdateParams } from "pros
2
2
  import { LocalParams, getClientErrorFromPGError, withUserRLS } from "../DboBuilder";
3
3
  import { InsertRule, UpdateRule } from "../../PublishParser/PublishParser";
4
4
  import { getSelectItemQuery, TableHandler } from "./TableHandler";
5
+ import { DBOFullyTyped } from "../../DBSchemaBuilder";
5
6
 
6
7
  type RunInsertUpdateQueryArgs = {
7
8
  tableHandler: TableHandler;
@@ -14,6 +15,7 @@ type RunInsertUpdateQueryArgs = {
14
15
  params: InsertParams | undefined
15
16
  rule: InsertRule | undefined;
16
17
  data: AnyObject | AnyObject[];
18
+ isMultiInsert: boolean;
17
19
  nestedInsertsResultsObj?: undefined;
18
20
  } | {
19
21
  type: "update";
@@ -23,7 +25,8 @@ type RunInsertUpdateQueryArgs = {
23
25
  data: undefined;
24
26
  });
25
27
 
26
- export const runInsertUpdateQuery = async ({ tableHandler, queryWithoutUserRLS, rule, localParams, fields, returningFields, params, data, type, nestedInsertsResultsObj }: RunInsertUpdateQueryArgs) => {
28
+ export const runInsertUpdateQuery = async (args: RunInsertUpdateQueryArgs) => {
29
+ const { tableHandler, queryWithoutUserRLS, rule, localParams, fields, returningFields, params, nestedInsertsResultsObj } = args;
27
30
  const { name } = tableHandler;
28
31
 
29
32
  const returningSelectItems = await tableHandler.prepareReturning(params?.returning, tableHandler.parseFieldFilter(returningFields))
@@ -104,13 +107,13 @@ export const runInsertUpdateQuery = async ({ tableHandler, queryWithoutUserRLS,
104
107
 
105
108
  const rows = result.modified ?? [];
106
109
  for await (const row of rows){
107
- await postValidate({ row: row ?? {}, dbx: finalDBtx, localParams })
110
+ await postValidate({ row: row ?? {}, dbx: finalDBtx as any, localParams })
108
111
  }
109
112
  }
110
113
 
111
114
  let returnMany = false;
112
- if(type === "update"){
113
- const { multi = true } = params || {};
115
+ if(args.type === "update"){
116
+ const { multi = true } = args.params || {};
114
117
  if(!multi && result.row_count && +result.row_count > 1){
115
118
  throw `More than 1 row modified: ${result.row_count} rows affected`;
116
119
  }
@@ -120,7 +123,7 @@ export const runInsertUpdateQuery = async ({ tableHandler, queryWithoutUserRLS,
120
123
  }
121
124
 
122
125
  } else {
123
- returnMany = Array.isArray(data)
126
+ returnMany = args.isMultiInsert
124
127
  }
125
128
 
126
129
  if(!hasReturning) return undefined;
@@ -1,10 +1,11 @@
1
- import { AnyObject, unpatchText, UpdateParams } from "prostgles-types";
2
- import { Filter, isPlainObject, LocalParams, parseError, withUserRLS } from "../DboBuilder";
1
+ import { AnyObject, UpdateParams } from "prostgles-types";
3
2
  import { TableRule } from "../../PublishParser/PublishParser";
4
- import { getInsertTableRules, getReferenceColumnInserts } from "../insertDataParse";
3
+ import { Filter, LocalParams, parseError, withUserRLS } from "../DboBuilder";
4
+ import { getInsertTableRules, getReferenceColumnInserts } from "../insertNestedRecords";
5
5
  import { runInsertUpdateQuery } from "./runInsertUpdateQuery";
6
6
  import { TableHandler } from "./TableHandler";
7
7
  import { updateFile } from "./updateFile";
8
+ import { prepareNewData } from "./DataValidator";
8
9
 
9
10
  export async function update(this: TableHandler, filter: Filter, _newData: AnyObject, params?: UpdateParams, tableRules?: TableRule, localParams?: LocalParams): Promise<AnyObject | void> {
10
11
  const ACTION = "update";
@@ -23,11 +24,15 @@ export async function update(this: TableHandler, filter: Filter, _newData: AnyOb
23
24
  ({ newData } = await updateFile.bind(this)({ newData, filter, localParams, tableRules }));
24
25
  }
25
26
 
26
- const parsedRules = await this.parseUpdateRules(filter, newData, params, tableRules, localParams)
27
+ const parsedRules = await this.parseUpdateRules(filter, params, tableRules, localParams)
27
28
  if (localParams?.testRule) {
28
29
  return parsedRules;
29
30
  }
30
31
 
32
+ if (!newData || !Object.keys(newData).length) {
33
+ throw "no update data provided\nEXPECTING db.table.update(filter, updateData, options)";
34
+ }
35
+
31
36
  const { fields, validateRow, forcedData, returningFields, forcedFilter, filterFields } = parsedRules;
32
37
  const { onConflict, fixIssues = false } = params || {};
33
38
  const { returnQuery = false } = localParams ?? {};
@@ -39,38 +44,16 @@ export async function update(this: TableHandler, filter: Filter, _newData: AnyOb
39
44
  if (bad_params && bad_params.length) throw "Invalid params: " + bad_params.join(", ") + " \n Expecting: " + good_params.join(", ");
40
45
  }
41
46
 
42
- const { data, allowedCols } = this.validateNewData({ row: newData, forcedData, allowedFields: fields, tableRules, fixIssues });
43
-
44
- /* Patch data */
45
- const patchedTextData: {
46
- fieldName: string;
47
- from: number;
48
- to: number;
49
- text: string;
50
- md5: string
51
- }[] = [];
52
- this.columns.map(c => {
53
- const d = data[c.name];
54
- if (c.data_type === "text" && d && isPlainObject(d) && !["from", "to"].find(key => typeof d[key] !== "number")) {
55
- const unrecProps = Object.keys(d).filter(k => !["from", "to", "text", "md5"].includes(k));
56
- if (unrecProps.length) throw "Unrecognised params in textPatch field: " + unrecProps.join(", ");
57
- patchedTextData.push({ ...d, fieldName: c.name } as (typeof patchedTextData)[number]);
58
- }
47
+ const { data, allowedCols } = await prepareNewData({
48
+ row: newData,
49
+ forcedData,
50
+ allowedFields: fields,
51
+ tableRules,
52
+ fixIssues,
53
+ tableConfigurator: this.dboBuilder.prostgles.tableConfigurator,
54
+ tableHandler: this,
59
55
  });
60
56
 
61
- if (patchedTextData?.length) {
62
- if (tableRules && !tableRules.select) throw "Select needs to be permitted to patch data";
63
- const rows = await this.find(filter, { select: patchedTextData.reduce((a, v) => ({ ...a, [v.fieldName]: 1 }), {}) }, undefined, tableRules);
64
-
65
- if (rows.length !== 1) {
66
- throw "Cannot patch data within a filter that affects more/less than 1 row";
67
- }
68
- patchedTextData.map(p => {
69
- data[p.fieldName] = unpatchText(rows[0][p.fieldName], p);
70
- });
71
- }
72
-
73
- const nData = { ...data };
74
57
  const updateFilter = await this.prepareWhere({
75
58
  filter,
76
59
  forcedFilter,
@@ -78,8 +61,12 @@ export async function update(this: TableHandler, filter: Filter, _newData: AnyOb
78
61
  localParams,
79
62
  tableRule: tableRules
80
63
  })
81
-
82
- const nestedInserts = getReferenceColumnInserts.bind(this)(nData, true);
64
+
65
+ /**
66
+ * Nested inserts
67
+ */
68
+ const nData = { ...data };
69
+ const nestedInserts = getReferenceColumnInserts(this, nData, true);
83
70
  const nestedInsertsResultsObj: Record<string, any> = {};
84
71
  if(nestedInserts.length){
85
72
  const updateCount = await this.count(updateFilter.filter);
@@ -105,7 +92,8 @@ export async function update(this: TableHandler, filter: Filter, _newData: AnyOb
105
92
  }));
106
93
  }
107
94
 
108
- let query = await this.colSet.getUpdateQuery(nData, allowedCols, this.getFinalDbo(localParams), validateRow, localParams)
95
+ // let query = await this.colSet.getUpdateQuery(nData, allowedCols, this.getFinalDbo(localParams), validateRow, localParams)
96
+ let query = (await this.dataValidator.parse({ command: "update", rows: [nData], allowedCols, dbTx: this.getFinalDbo(localParams), validationOptions: { validate: validateRow, localParams }})).getQuery()
109
97
  query += "\n" + updateFilter.where;
110
98
  if (onConflict === "DoNothing") query += " ON CONFLICT DO NOTHING ";
111
99
  if(onConflict === "DoUpdate"){
@@ -12,18 +12,18 @@ export async function updateBatch(this: TableHandler, updates: [Filter, AnyObjec
12
12
  throw `updateBatch not allowed for tables with checkFilter or postValidate rules`
13
13
  }
14
14
  const updateQueries: string[] = await Promise.all(
15
- updates.map(async ([filter, data]) => {
15
+ updates.map(async ([filter, data]) => {
16
16
  const query = (await this.update(
17
17
  filter,
18
18
  data,
19
- { ...(params || {}), returning: undefined },
19
+ { ...(params ?? {}), returning: undefined },
20
20
  tableRules,
21
- { ...(localParams || {}), returnQuery: "noRLS" }
21
+ { ...(localParams ?? {}), returnQuery: "noRLS" }
22
22
  )) as unknown as string;
23
23
 
24
24
  return query;
25
25
  })
26
- );
26
+ );
27
27
  const queries = [
28
28
  withUserRLS(localParams, ""),
29
29
  ...updateQueries
@@ -1,9 +1,10 @@
1
1
  import { AnyObject, getKeys, isObject } from "prostgles-types";
2
2
  import { LocalParams, Media } from "../DboBuilder";
3
- import { TableRule, ValidateRow } from "../../PublishParser/PublishParser";
3
+ import { TableRule, ValidateRow, ValidateRowBasic } from "../../PublishParser/PublishParser";
4
4
  import { omitKeys } from "../../PubSubManager/PubSubManager";
5
5
  import { isFile, uploadFile } from "../uploadFile";
6
6
  import { TableHandler } from "./TableHandler";
7
+ import { DBOFullyTyped } from "../../DBSchemaBuilder";
7
8
 
8
9
  type Args = {
9
10
  newData: AnyObject;
@@ -32,8 +33,8 @@ export const updateFile = async function(this: TableHandler, { filter, newData,
32
33
  const fileManager = this.dboBuilder.prostgles.fileManager
33
34
  if(!fileManager) throw new Error("fileManager missing");
34
35
  if(rule?.validate && !localParams) throw new Error("localParams missing");
35
- const validate: ValidateRow | undefined = rule?.validate? async (row) => {
36
- return rule.validate!({ update: row, filter, dbx: this.tx?.dbTX || this.dboBuilder.dbo, localParams: localParams! })
36
+ const validate: ValidateRowBasic | undefined = rule?.validate? async (row) => {
37
+ return rule.validate!({ update: row, filter, dbx: (this.tx?.dbTX || this.dboBuilder.dbo) as any, localParams: localParams! })
37
38
  } : undefined;
38
39
 
39
40
  const existingFile: Media | undefined = await (localParams?.tx?.dbTX?.[this.name] as TableHandler || this).findOne({ id: existingMediaId });
@@ -25,7 +25,6 @@ import { asNameAlias } from "../QueryBuilder/QueryBuilder";
25
25
  import { find } from "../find";
26
26
  import { getColumns } from "../getColumns";
27
27
  import { LocalFuncs, subscribe } from "../subscribe";
28
- import { ColSet } from "./ColSet";
29
28
  import { getInfo } from "./getInfo";
30
29
  import { parseFieldFilter } from "./parseFieldFilter";
31
30
  import { prepareWhere } from "./prepareWhere";
@@ -46,7 +45,6 @@ export class ViewHandler {
46
45
  columnsForTypes: ColumnInfo[];
47
46
  column_names: string[];
48
47
  tableOrViewInfo: TableSchema;// TableOrViewInfo;
49
- colSet: ColSet;
50
48
  tsColumnDefs: string[] = [];
51
49
  joins: Join[];
52
50
  joinGraph?: Graph;
@@ -74,16 +72,13 @@ export class ViewHandler {
74
72
  this.name = tableOrViewInfo.escaped_identifier;
75
73
  this.escapedName = tableOrViewInfo.escaped_identifier;
76
74
  this.columns = tableOrViewInfo.columns;
77
-
78
75
  /* cols are sorted by name to reduce .d.ts schema rewrites */
79
76
  this.columnsForTypes = tableOrViewInfo.columns.slice(0).sort((a, b) => a.name.localeCompare(b.name));
80
77
 
81
78
  this.column_names = tableOrViewInfo.columns.map(c => c.name);
82
79
 
83
80
  this.dboBuilder = dboBuilder;
84
- this.joins = this.dboBuilder.joins ?? [];
85
-
86
- this.colSet = new ColSet(this.columns, this.name);
81
+ this.joins = this.dboBuilder.joins ?? [];
87
82
  this.columnsForTypes.map(({ name, udt_name, is_nullable }) => {
88
83
  this.tsColumnDefs.push(`${escapeTSNames(name)}?: ${postgresToTsType(udt_name) as string} ${is_nullable ? " | null " : ""};`);
89
84
  });
@@ -456,54 +451,8 @@ export class ViewHandler {
456
451
  return result;
457
452
  }
458
453
 
459
- /**
460
- * Prepare and validate field object:
461
- * @example ({ item_id: 1 }, { user_id: 32 }) => { item_id: 1, user_id: 32 }
462
- * OR
463
- * ({ a: 1 }, { b: 32 }, ["c", "d"]) => throw "a field is not allowed"
464
- * @param {Object} obj - initial data
465
- * @param {Object} forcedData - set/override property
466
- * @param {string[]} allowed_cols - allowed columns (excluding forcedData) from table rules
467
- */
468
- prepareFieldValues(obj: AnyObject = {}, forcedData: AnyObject = {}, allowed_cols: FieldFilter | undefined, removeDisallowedColumns = false): AnyObject {
469
- const column_names = this.column_names.slice(0);
470
- if (!column_names?.length) {
471
- throw "table column_names mising";
472
- }
473
- let _allowed_cols = column_names.slice(0);
474
- const _obj = { ...obj };
475
-
476
- if (allowed_cols) {
477
- _allowed_cols = this.parseFieldFilter(allowed_cols, false);
478
- }
479
- let final_filter = { ..._obj };
480
- const filter_keys: Array<keyof typeof final_filter> = Object.keys(final_filter);
481
-
482
- if (removeDisallowedColumns && filter_keys.length) {
483
- final_filter = {};
484
- filter_keys
485
- .filter(col => _allowed_cols.includes(col))
486
- .map(col => {
487
- final_filter[col] = _obj[col];
488
- });
489
- }
490
-
491
- /* If has keys check against allowed_cols */
492
- if (final_filter && Object.keys(final_filter).length && _allowed_cols) {
493
- validateObj(final_filter, _allowed_cols)
494
- }
495
-
496
- if (forcedData && Object.keys(forcedData).length) {
497
- final_filter = { ...final_filter, ...forcedData };
498
- }
499
-
500
- validateObj(final_filter, column_names.slice(0));
501
- return final_filter;
502
- }
503
-
504
-
505
454
  parseFieldFilter(fieldParams: FieldFilter = "*", allow_empty = true, allowed_cols?: string[]): string[] {
506
- return parseFieldFilter(fieldParams, allow_empty, allowed_cols || this.column_names.slice(0))
455
+ return parseFieldFilter(fieldParams, allow_empty, allowed_cols ?? this.column_names.slice(0))
507
456
  }
508
457
 
509
458
  }
@@ -512,7 +461,7 @@ export class ViewHandler {
512
461
  /**
513
462
  * Throw error if illegal keys found in object
514
463
  */
515
- function validateObj<T extends Record<string, any>>(obj: T, allowedKeys: string[]): T {
464
+ export const validateObj = <T extends Record<string, any>>(obj: T, allowedKeys: string[]): T => {
516
465
  if (obj && Object.keys(obj).length) {
517
466
  const invalid_keys = Object.keys(obj).filter(k => !allowedKeys.includes(k));
518
467
  if (invalid_keys.length) {
@@ -154,7 +154,10 @@ export const getConstraints = async (db: DB, schema: ProstglesInitOptions["schem
154
154
  `, { schemaNames });
155
155
  }
156
156
 
157
-
157
+ /**
158
+ * @deprecated
159
+ * use isObject
160
+ */
158
161
  export function isPlainObject(o: any): o is Record<string, any> {
159
162
  return Object(o) === o && Object.getPrototypeOf(o) === Object.prototype;
160
163
  }
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  AnyObject, PG_COLUMN_UDT_DATA_TYPE,
3
- ValidatedColumnInfo, _PG_geometric
3
+ ValidatedColumnInfo, _PG_geometric, isObject
4
4
  } from "prostgles-types";
5
5
  import { isPlainObject, LocalParams, parseError, postgresToTsType } from "./DboBuilder";
6
6
  import { TableRule } from "../PublishParser/PublishParser";
@@ -29,19 +29,18 @@ export async function getColumns(
29
29
 
30
30
  if (params && tableRules && isTableHandler(this)) {
31
31
  if (
32
- !isPlainObject(params) ||
33
- (params.data && !isPlainObject(params.data)) ||
34
- !isPlainObject(params.filter) ||
32
+ !isObject(params) ||
33
+ !isObject(params.filter) ||
35
34
  params.rule !== "update"
36
35
  ) {
37
- throw "params must be { rule: 'update', filter: object, data?: object } but got: " + JSON.stringify(params);
36
+ throw "params must be { rule: 'update', filter: object } but received: " + JSON.stringify(params);
38
37
  }
39
38
 
40
39
  if (!tableRules?.update) {
41
40
  dynamicUpdateFields = [];
42
41
  } else {
43
- const { data, filter } = params;
44
- const updateRules = await this.parseUpdateRules(filter, data, undefined, tableRules, localParams);
42
+ const { filter } = params;
43
+ const updateRules = await this.parseUpdateRules(filter, undefined, tableRules, localParams);
45
44
  dynamicUpdateFields = updateRules.fields;
46
45
  }
47
46
  }
@@ -1,36 +1,43 @@
1
- import { AnyObject, getKeys, InsertParams, isDefined, isObject, PG_COLUMN_UDT_DATA_TYPE } from "prostgles-types";
1
+ import { AnyObject, getKeys, InsertParams, isDefined, isObject } from "prostgles-types";
2
2
  import { LocalParams, TableHandlers } from "./DboBuilder";
3
3
  import { TableRule } from "../PublishParser/PublishParser";
4
4
  import { omitKeys } from "../PubSubManager/PubSubManager";
5
5
  import { TableHandler } from "./TableHandler/TableHandler";
6
6
 
7
+ type InsertNestedRecordsArgs = {
8
+ data: (AnyObject | AnyObject[]);
9
+ param2?: InsertParams;
10
+ tableRules?: TableRule;
11
+ localParams?: LocalParams;
12
+ };
13
+
7
14
  /**
8
15
  * Referenced inserts within a single transaction
9
16
  */
10
- export async function insertDataParse(
17
+ export async function insertNestedRecords(
11
18
  this: TableHandler,
12
- data: (AnyObject | AnyObject[]),
13
- param2?: InsertParams,
14
- param3_unused?: undefined,
15
- tableRules?: TableRule,
16
- _localParams?: LocalParams
19
+ {
20
+ data,
21
+ param2,
22
+ tableRules,
23
+ localParams = {},
24
+ }: InsertNestedRecordsArgs
17
25
  ): Promise<{
18
26
  data?: AnyObject | AnyObject[];
19
27
  insertResult?: AnyObject | AnyObject[];
20
- }> {
21
- const localParams = _localParams || {};
28
+ }> {
22
29
  const MEDIA_COL_NAMES = ["data", "name"];
23
30
 
24
- const isMultiInsert = Array.isArray(data);
25
- const getExtraKeys = (d: AnyObject) => getKeys(d).filter(k => {
31
+ const getExtraKeys = (row: AnyObject) => getKeys(row).filter(fieldName => {
26
32
  /* If media then use file insert columns */
27
33
  if (this.is_media) {
28
- return !this.column_names.concat(MEDIA_COL_NAMES).includes(k)
29
- } else if (!this.columns.find(c => c.name === k)) {
30
- if (!isObject(d[k]) && !Array.isArray(d[k])) {
31
- throw new Error("Invalid/Dissalowed field in data: " + k)
32
- } else if (!this.dboBuilder.dbo[k]) {
33
- throw new Error("Invalid/Dissalowed nested insert table name in data: " + k)
34
+ return !this.column_names.concat(MEDIA_COL_NAMES).includes(fieldName)
35
+ } else if (!this.columns.find(c => c.name === fieldName)) {
36
+ if (!isObject(row[fieldName]) && !Array.isArray(row[fieldName])) {
37
+ throw new Error("Invalid/Dissalowed field in data: " + fieldName)
38
+ } else if (!this.dboBuilder.dbo[fieldName]) {
39
+ return false;
40
+ // throw new Error("Invalid/Dissalowed nested insert table name in data: " + fieldName)
34
41
  }
35
42
  return true;
36
43
  }
@@ -46,7 +53,8 @@ export async function insertDataParse(
46
53
  * If true then will do the full insert within this function
47
54
  * Nested insert is not allowed for the file table
48
55
  * */
49
- const hasNestedInserts = this.is_media ? false : (isMultiInsert ? data : [data]).some(d => getExtraKeys(d).length || getReferenceColumnInserts.bind(this)(d).length);
56
+ const isMultiInsert = Array.isArray(data);
57
+ const hasNestedInserts = this.is_media ? false : (isMultiInsert ? data : [data]).some(d => getExtraKeys(d).length || getReferenceColumnInserts(this, d).length);
50
58
 
51
59
  /**
52
60
  * Make sure nested insert uses a transaction
@@ -59,36 +67,34 @@ export async function insertDataParse(
59
67
  (dbTX[this.name] as TableHandler).insert(
60
68
  data,
61
69
  param2,
62
- param3_unused,
70
+ undefined,
63
71
  tableRules,
64
72
  { tx: { dbTX, t: _t }, ...localParams }
65
73
  )
66
74
  )
67
75
  }
68
76
  }
77
+
69
78
 
70
- const { preValidate, validate } = tableRules?.insert ?? {};
71
-
72
- const _data = await Promise.all((isMultiInsert ? data : [data]).map(async _row => {
73
- const { tableConfigurator } = this.dboBuilder.prostgles;
74
- if(!tableConfigurator) throw "tableConfigurator missing";
75
- let row = await tableConfigurator.getPreInsertRow(this, { dbx: this.getFinalDbo(localParams), preValidate, validate, localParams, row: _row })
76
- if (preValidate) {
77
- row = await preValidate({ row, dbx: this.tx?.dbTX || this.dboBuilder.dbo, localParams });
78
- }
79
-
80
- const extraKeys = getExtraKeys(row);
81
- const colInserts = getReferenceColumnInserts.bind(this)(row);
79
+ const _data = await Promise.all((isMultiInsert ? data : [data]).map(async row => {
80
+ // const { preValidate, validate } = tableRules?.insert ?? {};
81
+ // const { tableConfigurator } = this.dboBuilder.prostgles;
82
+ // if(!tableConfigurator) throw "tableConfigurator missing";
83
+ // let row = await tableConfigurator.getPreInsertRow(this, { dbx: this.getFinalDbo(localParams), validate, localParams, row: _row })
84
+ // if (preValidate) {
85
+ // row = await preValidate({ row, dbx: this.tx?.dbTX || this.dboBuilder.dbo, localParams });
86
+ // }
82
87
 
83
88
  /* Potentially a nested join */
84
89
  if (hasNestedInserts) {
85
-
90
+ const extraKeys = getExtraKeys(row);
91
+ const colInserts = getReferenceColumnInserts(this, row);
92
+
86
93
  /* Ensure we're using the same transaction */
87
94
  const _this = this.tx ? this : dbTX![this.name] as TableHandler;
88
95
 
89
96
  const omitedKeys = extraKeys.concat(colInserts.map(c => c.col));
90
97
 
91
- // let rootData = isMultiInsert? data.map(d => omitKeys(d, omitedKeys)) : omitKeys(data, omitedKeys);
92
98
  const rootData: AnyObject = omitKeys(row, omitedKeys);
93
99
 
94
100
  let insertedChildren: AnyObject[];
@@ -204,7 +210,6 @@ export async function insertDataParse(
204
210
  colsRefT1.map(col => {
205
211
  tbl2Row[col.name] = fullRootResult[col.references![0]!.fcols[0]!];
206
212
  })
207
- // console.log({ rootResult, tbl2Row, t3Child, colsRefT3, colsRefT1, t: this.t?.ctx?.start });
208
213
 
209
214
  await childInsert(tbl2Row, tbl2!);//.then(() => {});
210
215
  }));
@@ -286,17 +291,21 @@ const referencedInsert = async (tableHandler: TableHandler, dbTX: TableHandlers
286
291
  .map(m => (dbTX![targetTable] as TableHandler)
287
292
  .insert(m, { returning: "*" }, undefined, childRules, localParams)
288
293
  .catch(e => {
289
- console.trace({ childInsertErr: e })
290
- return Promise.reject(e);
291
- // return Promise.reject({ childInsertErr: e });
294
+ return Promise.reject(e);
292
295
  })
293
296
  )
294
297
  );
295
298
 
296
299
  }
297
300
 
301
+ type ReferenceColumnInsert<ExpectSingleInsert> = {
302
+ tableName: string;
303
+ col: string;
304
+ fcol: string;
305
+ singleInsert: boolean;
306
+ data: ExpectSingleInsert extends true? AnyObject : (AnyObject | AnyObject[]);
307
+ }
298
308
 
299
- // const ALLOWED_COL_TYPES: PG_COLUMN_UDT_DATA_TYPE[] = ["int2", "int4", "int8", "numeric", "uuid", "text", "varchar", "char"];
300
309
  /**
301
310
  * Insert through the reference column. e.g.:
302
311
  * {
@@ -304,16 +313,15 @@ const referencedInsert = async (tableHandler: TableHandler, dbTX: TableHandlers
304
313
  * fkey_column: { ...referenced_table_data }
305
314
  * }
306
315
  */
307
- export const getReferenceColumnInserts = function(this: TableHandler, parentRow: AnyObject, expectSingleInsert = false){
308
- return getKeys(parentRow)
309
- .map(k => {
310
- if(parentRow[k] && isObject(parentRow[k])){
311
- const insertedRefCol = this.columns.find(c => c.name === k);
312
- if(insertedRefCol?.references?.length){
313
- return {
314
- insertedRefCol,
315
- insertedRefColRef: insertedRefCol.references!
316
- }
316
+ export const getReferenceColumnInserts = <ExpectSingleInsert extends boolean>(tableHandler: TableHandler, parentRow: AnyObject, expectSingleInsert?: ExpectSingleInsert): ReferenceColumnInsert<ExpectSingleInsert>[] => {
317
+ return Object.entries(parentRow)
318
+ .map(([insertedFieldName, insertedFieldValue]) => {
319
+ if(insertedFieldValue && isObject(insertedFieldValue)){
320
+ const insertedRefCol = tableHandler.columns.find(c => c.name === insertedFieldName && c.references?.length);
321
+ if(!insertedRefCol) return undefined;
322
+ return {
323
+ insertedRefCol,
324
+ insertedRefColRef: insertedRefCol.references!
317
325
  }
318
326
  }
319
327
 
@@ -335,12 +343,13 @@ export const getReferenceColumnInserts = function(this: TableHandler, parentRow:
335
343
  if(expectSingleInsert && !singleInsert){
336
344
  throw "Expected singleInsert";
337
345
  }
338
- return {
346
+ const res = {
339
347
  tableName: insertedRefCol.references![0]!.ftable!,
340
348
  col: insertedRefCol.name,
341
349
  fcol: insertedRefCol.references![0]!.fcols[0]!,
342
350
  singleInsert,
343
351
  data: parentRow[insertedRefCol.name],
344
352
  }
353
+ return res;
345
354
  }).filter(isDefined);
346
355
  }