bigal 12.1.4 → 13.0.0-beta1

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 (213) hide show
  1. package/.devcontainer/devcontainer.json +16 -0
  2. package/.husky/pre-commit +4 -0
  3. package/.prettierrc.cjs +34 -0
  4. package/CHANGELOG.md +9 -0
  5. package/dist/index.cjs +2626 -0
  6. package/dist/index.d.cts +892 -0
  7. package/dist/index.d.mts +892 -0
  8. package/dist/index.d.ts +892 -0
  9. package/dist/index.mjs +2605 -0
  10. package/eslint.config.mjs +25 -0
  11. package/package.json +46 -37
  12. package/tsconfig.build.json +7 -0
  13. package/Entity.d.ts +0 -16
  14. package/Entity.js +0 -13
  15. package/Entity.js.map +0 -1
  16. package/IReadonlyRepository.d.ts +0 -36
  17. package/IReadonlyRepository.js +0 -3
  18. package/IReadonlyRepository.js.map +0 -1
  19. package/IRepository.d.ts +0 -99
  20. package/IRepository.js +0 -3
  21. package/IRepository.js.map +0 -1
  22. package/ReadonlyRepository.d.ts +0 -69
  23. package/ReadonlyRepository.js +0 -687
  24. package/ReadonlyRepository.js.map +0 -1
  25. package/Repository.d.ts +0 -69
  26. package/Repository.js +0 -171
  27. package/Repository.js.map +0 -1
  28. package/SqlHelper.d.ts +0 -144
  29. package/SqlHelper.js +0 -1081
  30. package/SqlHelper.js.map +0 -1
  31. package/decorators/ColumnBaseOptions.d.ts +0 -10
  32. package/decorators/ColumnBaseOptions.js +0 -3
  33. package/decorators/ColumnBaseOptions.js.map +0 -1
  34. package/decorators/ColumnCollectionOptions.d.ts +0 -15
  35. package/decorators/ColumnCollectionOptions.js +0 -3
  36. package/decorators/ColumnCollectionOptions.js.map +0 -1
  37. package/decorators/ColumnModelOptions.d.ts +0 -7
  38. package/decorators/ColumnModelOptions.js +0 -3
  39. package/decorators/ColumnModelOptions.js.map +0 -1
  40. package/decorators/ColumnTypeOptions.d.ts +0 -21
  41. package/decorators/ColumnTypeOptions.js +0 -3
  42. package/decorators/ColumnTypeOptions.js.map +0 -1
  43. package/decorators/TableOptions.d.ts +0 -14
  44. package/decorators/TableOptions.js +0 -3
  45. package/decorators/TableOptions.js.map +0 -1
  46. package/decorators/column.d.ts +0 -9
  47. package/decorators/column.js +0 -93
  48. package/decorators/column.js.map +0 -1
  49. package/decorators/createDateColumn.d.ts +0 -6
  50. package/decorators/createDateColumn.js +0 -50
  51. package/decorators/createDateColumn.js.map +0 -1
  52. package/decorators/index.d.ts +0 -6
  53. package/decorators/index.js +0 -23
  54. package/decorators/index.js.map +0 -1
  55. package/decorators/primaryColumn.d.ts +0 -8
  56. package/decorators/primaryColumn.js +0 -66
  57. package/decorators/primaryColumn.js.map +0 -1
  58. package/decorators/table.d.ts +0 -5
  59. package/decorators/table.js +0 -40
  60. package/decorators/table.js.map +0 -1
  61. package/decorators/updateDateColumn.d.ts +0 -6
  62. package/decorators/updateDateColumn.js +0 -51
  63. package/decorators/updateDateColumn.js.map +0 -1
  64. package/decorators/versionColumn.d.ts +0 -6
  65. package/decorators/versionColumn.js +0 -51
  66. package/decorators/versionColumn.js.map +0 -1
  67. package/errors/QueryError.d.ts +0 -8
  68. package/errors/QueryError.js +0 -13
  69. package/errors/QueryError.js.map +0 -1
  70. package/errors/index.d.ts +0 -1
  71. package/errors/index.js +0 -18
  72. package/errors/index.js.map +0 -1
  73. package/index.d.ts +0 -35
  74. package/index.js +0 -220
  75. package/index.js.map +0 -1
  76. package/metadata/ColumnBaseMetadata.d.ts +0 -93
  77. package/metadata/ColumnBaseMetadata.js +0 -19
  78. package/metadata/ColumnBaseMetadata.js.map +0 -1
  79. package/metadata/ColumnCollectionMetadata.d.ts +0 -36
  80. package/metadata/ColumnCollectionMetadata.js +0 -63
  81. package/metadata/ColumnCollectionMetadata.js.map +0 -1
  82. package/metadata/ColumnMetadata.d.ts +0 -4
  83. package/metadata/ColumnMetadata.js +0 -3
  84. package/metadata/ColumnMetadata.js.map +0 -1
  85. package/metadata/ColumnModelMetadata.d.ts +0 -18
  86. package/metadata/ColumnModelMetadata.js +0 -43
  87. package/metadata/ColumnModelMetadata.js.map +0 -1
  88. package/metadata/ColumnModifierMetadata.d.ts +0 -46
  89. package/metadata/ColumnModifierMetadata.js +0 -3
  90. package/metadata/ColumnModifierMetadata.js.map +0 -1
  91. package/metadata/ColumnTypeMetadata.d.ts +0 -43
  92. package/metadata/ColumnTypeMetadata.js +0 -26
  93. package/metadata/ColumnTypeMetadata.js.map +0 -1
  94. package/metadata/MetadataStorage.d.ts +0 -13
  95. package/metadata/MetadataStorage.js +0 -19
  96. package/metadata/MetadataStorage.js.map +0 -1
  97. package/metadata/ModelMetadata.d.ts +0 -36
  98. package/metadata/ModelMetadata.js +0 -81
  99. package/metadata/ModelMetadata.js.map +0 -1
  100. package/metadata/index.d.ts +0 -10
  101. package/metadata/index.js +0 -33
  102. package/metadata/index.js.map +0 -1
  103. package/query/Comparer.d.ts +0 -1
  104. package/query/Comparer.js +0 -3
  105. package/query/Comparer.js.map +0 -1
  106. package/query/CountArgs.d.ts +0 -7
  107. package/query/CountArgs.js +0 -3
  108. package/query/CountArgs.js.map +0 -1
  109. package/query/CountResult.d.ts +0 -5
  110. package/query/CountResult.js +0 -3
  111. package/query/CountResult.js.map +0 -1
  112. package/query/CreateOptions.d.ts +0 -9
  113. package/query/CreateOptions.js +0 -3
  114. package/query/CreateOptions.js.map +0 -1
  115. package/query/CreateUpdateOptions.d.ts +0 -4
  116. package/query/CreateUpdateOptions.js +0 -3
  117. package/query/CreateUpdateOptions.js.map +0 -1
  118. package/query/DeleteOptions.d.ts +0 -12
  119. package/query/DeleteOptions.js +0 -3
  120. package/query/DeleteOptions.js.map +0 -1
  121. package/query/DestroyResult.d.ts +0 -5
  122. package/query/DestroyResult.js +0 -3
  123. package/query/DestroyResult.js.map +0 -1
  124. package/query/DoNotReturnRecords.d.ts +0 -3
  125. package/query/DoNotReturnRecords.js +0 -3
  126. package/query/DoNotReturnRecords.js.map +0 -1
  127. package/query/FindArgs.d.ts +0 -6
  128. package/query/FindArgs.js +0 -3
  129. package/query/FindArgs.js.map +0 -1
  130. package/query/FindOneArgs.d.ts +0 -11
  131. package/query/FindOneArgs.js +0 -3
  132. package/query/FindOneArgs.js.map +0 -1
  133. package/query/FindOneResult.d.ts +0 -12
  134. package/query/FindOneResult.js +0 -3
  135. package/query/FindOneResult.js.map +0 -1
  136. package/query/FindResult.d.ts +0 -15
  137. package/query/FindResult.js +0 -3
  138. package/query/FindResult.js.map +0 -1
  139. package/query/OnConflictOptions.d.ts +0 -25
  140. package/query/OnConflictOptions.js +0 -3
  141. package/query/OnConflictOptions.js.map +0 -1
  142. package/query/PaginateOptions.d.ts +0 -4
  143. package/query/PaginateOptions.js +0 -3
  144. package/query/PaginateOptions.js.map +0 -1
  145. package/query/PopulateArgs.d.ts +0 -13
  146. package/query/PopulateArgs.js +0 -3
  147. package/query/PopulateArgs.js.map +0 -1
  148. package/query/ReturnSelect.d.ts +0 -5
  149. package/query/ReturnSelect.js +0 -3
  150. package/query/ReturnSelect.js.map +0 -1
  151. package/query/Sort.d.ts +0 -15
  152. package/query/Sort.js +0 -3
  153. package/query/Sort.js.map +0 -1
  154. package/query/WhereQuery.d.ts +0 -21
  155. package/query/WhereQuery.js +0 -3
  156. package/query/WhereQuery.js.map +0 -1
  157. package/query/index.d.ts +0 -15
  158. package/query/index.js +0 -32
  159. package/query/index.js.map +0 -1
  160. package/types/ClassLike.d.ts +0 -8
  161. package/types/ClassLike.js +0 -3
  162. package/types/ClassLike.js.map +0 -1
  163. package/types/CreateUpdateParams.d.ts +0 -9
  164. package/types/CreateUpdateParams.js +0 -3
  165. package/types/CreateUpdateParams.js.map +0 -1
  166. package/types/EntityPrimitiveOrId.d.ts +0 -2
  167. package/types/EntityPrimitiveOrId.js +0 -3
  168. package/types/EntityPrimitiveOrId.js.map +0 -1
  169. package/types/ExcludeEntityCollections.d.ts +0 -5
  170. package/types/ExcludeEntityCollections.js +0 -3
  171. package/types/ExcludeEntityCollections.js.map +0 -1
  172. package/types/ExcludeFunctions.d.ts +0 -4
  173. package/types/ExcludeFunctions.js +0 -3
  174. package/types/ExcludeFunctions.js.map +0 -1
  175. package/types/GetValueType.d.ts +0 -1
  176. package/types/GetValueType.js +0 -3
  177. package/types/GetValueType.js.map +0 -1
  178. package/types/IncludeFunctions.d.ts +0 -4
  179. package/types/IncludeFunctions.js +0 -3
  180. package/types/IncludeFunctions.js.map +0 -1
  181. package/types/IsValueOfType.d.ts +0 -1
  182. package/types/IsValueOfType.js +0 -3
  183. package/types/IsValueOfType.js.map +0 -1
  184. package/types/OmitEntityCollections.d.ts +0 -7
  185. package/types/OmitEntityCollections.js +0 -3
  186. package/types/OmitEntityCollections.js.map +0 -1
  187. package/types/OmitFunctions.d.ts +0 -7
  188. package/types/OmitFunctions.js +0 -3
  189. package/types/OmitFunctions.js.map +0 -1
  190. package/types/PickAsType.d.ts +0 -3
  191. package/types/PickAsType.js +0 -3
  192. package/types/PickAsType.js.map +0 -1
  193. package/types/PickByValueType.d.ts +0 -5
  194. package/types/PickByValueType.js +0 -3
  195. package/types/PickByValueType.js.map +0 -1
  196. package/types/PickFunctions.d.ts +0 -4
  197. package/types/PickFunctions.js +0 -3
  198. package/types/PickFunctions.js.map +0 -1
  199. package/types/Populated.d.ts +0 -9
  200. package/types/Populated.js +0 -3
  201. package/types/Populated.js.map +0 -1
  202. package/types/QueryResult.d.ts +0 -9
  203. package/types/QueryResult.js +0 -3
  204. package/types/QueryResult.js.map +0 -1
  205. package/types/QueryResultOptionalPopulated.d.ts +0 -9
  206. package/types/QueryResultOptionalPopulated.js +0 -3
  207. package/types/QueryResultOptionalPopulated.js.map +0 -1
  208. package/types/QueryResultPopulated.d.ts +0 -9
  209. package/types/QueryResultPopulated.js +0 -3
  210. package/types/QueryResultPopulated.js.map +0 -1
  211. package/types/index.d.ts +0 -17
  212. package/types/index.js +0 -34
  213. package/types/index.js.map +0 -1
package/SqlHelper.js DELETED
@@ -1,1081 +0,0 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || function (mod) {
19
- if (mod && mod.__esModule) return mod;
20
- var result = {};
21
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
- __setModuleDefault(result, mod);
23
- return result;
24
- };
25
- Object.defineProperty(exports, "__esModule", { value: true });
26
- exports.buildOrderStatement = exports.buildWhereStatement = exports.getColumnsToSelect = exports.getDeleteQueryAndParams = exports.getUpdateQueryAndParams = exports.getInsertQueryAndParams = exports.getCountQueryAndParams = exports.getSelectQueryAndParams = void 0;
27
- const _ = __importStar(require("lodash"));
28
- const errors_1 = require("./errors");
29
- /* eslint-disable @typescript-eslint/no-use-before-define */
30
- /**
31
- * Gets the select syntax for the specified model and filters
32
- * @param {object} args - Arguments
33
- * @param {object} args.repositoriesByModelNameLowered - All model schemas organized by model name
34
- * @param {object} args.model - Model schema
35
- * @param {string[]} [args.select] - Array of model property names to return from the query.
36
- * @param {object} [args.where] - Object representing the where query
37
- * @param {string[]|object[]} [args.sorts] - Property name(s) to sort by
38
- * @param {number} [args.skip] - Number of records to skip
39
- * @param {number} [args.limit] - Number of results to return
40
- * @returns {{query: string, params: object[]}}
41
- */
42
- function getSelectQueryAndParams({ repositoriesByModelNameLowered, model, select, where, sorts, skip, limit, }) {
43
- let query = 'SELECT ';
44
- query += getColumnsToSelect({
45
- model,
46
- select,
47
- });
48
- query += ` FROM "${model.tableName}"`;
49
- const { whereStatement, params } = buildWhereStatement({
50
- repositoriesByModelNameLowered,
51
- model,
52
- where,
53
- });
54
- if (whereStatement) {
55
- query += ` ${whereStatement}`;
56
- }
57
- const orderStatement = buildOrderStatement({
58
- model,
59
- sorts,
60
- });
61
- if (orderStatement) {
62
- query += ` ${orderStatement}`;
63
- }
64
- if (limit) {
65
- if (_.isString(limit)) {
66
- // eslint-disable-next-line no-param-reassign
67
- limit = Number(limit);
68
- }
69
- if (!_.isFinite(limit)) {
70
- throw new errors_1.QueryError('Limit should be a number', model, where);
71
- }
72
- query += ` LIMIT ${limit}`;
73
- }
74
- if (skip) {
75
- if (_.isString(skip)) {
76
- // eslint-disable-next-line no-param-reassign
77
- skip = Number(skip);
78
- }
79
- if (!_.isFinite(skip)) {
80
- throw new errors_1.QueryError('Skip should be a number', model, where);
81
- }
82
- query += ` OFFSET ${skip}`;
83
- }
84
- if (process.env.DEBUG_BIGAL?.toLowerCase() === 'true') {
85
- // eslint-disable-next-line no-console
86
- console.log(`BigAl: ${query}`);
87
- }
88
- return {
89
- query,
90
- params,
91
- };
92
- }
93
- exports.getSelectQueryAndParams = getSelectQueryAndParams;
94
- /**
95
- * Gets the count syntax for the specified model and values
96
- * @param {object} args - Arguments
97
- * @param {object} args.repositoriesByModelNameLowered - All model schemas organized by model name
98
- * @param {object} args.model - Model schema
99
- * @param {object} [args.where] - Object representing the where query
100
- * @returns {{query: string, params: object[]}}
101
- */
102
- function getCountQueryAndParams({ repositoriesByModelNameLowered, model, where, }) {
103
- let query = `SELECT count(*) AS "count" FROM "${model.tableName}"`;
104
- const { whereStatement, params } = buildWhereStatement({
105
- repositoriesByModelNameLowered,
106
- model,
107
- where,
108
- });
109
- if (whereStatement) {
110
- query += ` ${whereStatement}`;
111
- }
112
- return {
113
- query,
114
- params,
115
- };
116
- }
117
- exports.getCountQueryAndParams = getCountQueryAndParams;
118
- /**
119
- * Gets the insert syntax for the specified model and values
120
- * @param {object} args - Arguments
121
- * @param {object} args.repositoriesByModelNameLowered - All model schemas organized by model name
122
- * @param {object} args.model - Model schema
123
- * @param {object|object[]} args.values - Values to insert. Insert multiple records by passing an array of values.
124
- * @param {object} [args.onConflict] - Options to handle conflicts due to a unique constraint or exclusion constraint error during insert
125
- * @param {boolean} [args.returnRecords=true] - Determines if inserted records should be returned
126
- * @param {string[]} [args.returnSelect] - Array of model property names to return from the query.
127
- * @returns {{query: string, params: object[]}}
128
- */
129
- function getInsertQueryAndParams({ repositoriesByModelNameLowered, model, values, returnRecords = true, returnSelect, onConflict, }) {
130
- const entitiesToInsert = _.isArray(values) ? values : [values];
131
- const conflictTargetColumns = [];
132
- const columnsToInsert = [];
133
- const columnsToMerge = [];
134
- let hasEmptyMergeColumns = false;
135
- // Set defaulted property values and verify required columns have a value specified
136
- for (const column of model.columns) {
137
- const collectionColumn = column;
138
- if (!collectionColumn.collection) {
139
- const { defaultsTo } = column;
140
- let defaultValue;
141
- if (_.isFunction(defaultsTo)) {
142
- defaultValue = defaultsTo();
143
- }
144
- else if (!_.isUndefined(defaultsTo)) {
145
- defaultValue = defaultsTo;
146
- }
147
- else if (column.createDate) {
148
- defaultValue = new Date();
149
- }
150
- else if (column.updateDate) {
151
- defaultValue = new Date();
152
- }
153
- else if (column.version) {
154
- defaultValue = 1;
155
- }
156
- const hasDefaultValue = !_.isUndefined(defaultValue);
157
- let includePropertyName = false;
158
- for (const entity of entitiesToInsert) {
159
- // If there is a default value for the property and if it is not defined, use the default
160
- if (hasDefaultValue && _.isUndefined(entity[column.propertyName])) {
161
- // @ts-expect-error - string is not assignable to T[string & keyof T] | undefined
162
- entity[column.propertyName] = defaultValue;
163
- }
164
- if (_.isUndefined(entity[column.propertyName])) {
165
- if (column.required) {
166
- throw new errors_1.QueryError(`Create statement for "${model.name}" is missing value for required field: ${column.propertyName}`, model);
167
- }
168
- }
169
- else {
170
- includePropertyName = true;
171
- // Check and enforce max length for applicable types
172
- const { maxLength, type } = column;
173
- if (maxLength && ['string', 'string[]'].includes(type)) {
174
- const entityValues = entity[column.propertyName];
175
- const normalizedValues = (Array.isArray(entityValues) ? entityValues : [entityValues]);
176
- for (const normalizedValue of normalizedValues) {
177
- if (normalizedValue?.length > maxLength) {
178
- throw new errors_1.QueryError(`Create statement for "${model.name}" contains a value that exceeds maxLength on field: ${column.propertyName}`, model);
179
- }
180
- }
181
- }
182
- }
183
- }
184
- if (includePropertyName) {
185
- columnsToInsert.push(column);
186
- }
187
- if (onConflict) {
188
- if ((Array.isArray(onConflict.targets) && onConflict.targets.includes(column.propertyName)) ||
189
- (!Array.isArray(onConflict.targets) && onConflict.targets.columns.includes(column.propertyName))) {
190
- conflictTargetColumns.push(column);
191
- }
192
- if (onConflict.action === 'merge') {
193
- const mergeColumns = Array.isArray(onConflict.merge) ? onConflict.merge : onConflict.merge?.columns;
194
- if (mergeColumns) {
195
- hasEmptyMergeColumns = !mergeColumns.length;
196
- if (mergeColumns.includes(column.propertyName)) {
197
- columnsToMerge.push(column);
198
- }
199
- }
200
- else if (!column.createDate && !column.primary) {
201
- columnsToMerge.push(column);
202
- }
203
- }
204
- }
205
- }
206
- }
207
- const valueCollections = entitiesToInsert.map(() => []);
208
- const params = [];
209
- let query = `INSERT INTO "${model.tableName}" (`;
210
- for (const [columnIndex, column] of columnsToInsert.entries()) {
211
- if (columnIndex > 0) {
212
- query += ',';
213
- }
214
- query += `"${column.name}"`;
215
- for (const [entityIndex, entity] of entitiesToInsert.entries()) {
216
- let value;
217
- const entityValue = entity[column.propertyName];
218
- if (_.isNil(entityValue)) {
219
- value = 'NULL';
220
- }
221
- else {
222
- const isJsonArray = column.type === 'json' && _.isArray(entityValue);
223
- const relatedModelName = column.model;
224
- if (relatedModelName && _.isObject(entityValue)) {
225
- const relatedModelRepository = repositoriesByModelNameLowered[relatedModelName.toLowerCase()];
226
- if (!relatedModelRepository) {
227
- throw new errors_1.QueryError(`Unable to find model schema (${relatedModelName}) specified as model type for "${column.propertyName}" on "${model.name}"`, model);
228
- }
229
- const relatedModelPrimaryKey = relatedModelRepository.model.primaryKeyColumn;
230
- if (!relatedModelPrimaryKey) {
231
- throw new errors_1.QueryError(`Unable to find primary key column for ${relatedModelName} when inserting ${model.name}.${column.propertyName} value.`, model);
232
- }
233
- const primaryKeyValue = entityValue[relatedModelPrimaryKey.propertyName];
234
- if (_.isNil(primaryKeyValue)) {
235
- throw new errors_1.QueryError(`Undefined primary key value for hydrated object value for "${column.propertyName}" on "${model.name}"`, model);
236
- }
237
- params.push(primaryKeyValue);
238
- }
239
- else if (isJsonArray) {
240
- // Inserting an array to a json/jsonb column will result in a message: invalid input syntax for type json
241
- // https://github.com/brianc/node-postgres/issues/442
242
- params.push(JSON.stringify(entityValue));
243
- }
244
- else {
245
- params.push(entityValue);
246
- }
247
- value = `$${params.length}`;
248
- if (isJsonArray) {
249
- value += '::jsonb';
250
- }
251
- }
252
- const valuesForEntityIndex = valueCollections[entityIndex];
253
- if (!valuesForEntityIndex) {
254
- throw new errors_1.QueryError('Error trying to get insert values for entity index', model);
255
- }
256
- valuesForEntityIndex.push(value);
257
- }
258
- }
259
- query += ') VALUES ';
260
- for (const [index, valueCollection] of valueCollections.entries()) {
261
- if (index > 0) {
262
- query += ',';
263
- }
264
- query += `(${valueCollection.join(',')})`;
265
- }
266
- if (onConflict) {
267
- query += ' ON CONFLICT (';
268
- for (const [index, targetColumn] of conflictTargetColumns.entries()) {
269
- if (index > 0) {
270
- query += ',';
271
- }
272
- query += `"${targetColumn.name}"`;
273
- }
274
- query += ') ';
275
- // ON CONFLICT (foo, bar) WHERE baz = 1
276
- if (!Array.isArray(onConflict.targets)) {
277
- const { whereStatement } = buildWhereStatement({
278
- repositoriesByModelNameLowered,
279
- model,
280
- where: onConflict.targets.where,
281
- params,
282
- });
283
- if (whereStatement) {
284
- query += `${whereStatement} `;
285
- }
286
- }
287
- if (onConflict.action === 'ignore' || hasEmptyMergeColumns) {
288
- query += 'DO NOTHING';
289
- }
290
- else {
291
- query += 'DO UPDATE SET ';
292
- for (const [index, column] of columnsToMerge.entries()) {
293
- if (index > 0) {
294
- query += ',';
295
- }
296
- if (column.version) {
297
- query += `"${column.name}"="${column.name}"+1`;
298
- }
299
- else {
300
- query += `"${column.name}"=EXCLUDED."${column.name}"`;
301
- }
302
- }
303
- if (!Array.isArray(onConflict.merge) && onConflict.merge?.where) {
304
- const { whereStatement } = buildWhereStatement({
305
- repositoriesByModelNameLowered,
306
- model,
307
- where: onConflict.merge.where,
308
- params,
309
- });
310
- if (whereStatement) {
311
- query += ` ${whereStatement}`;
312
- }
313
- }
314
- }
315
- }
316
- if (returnRecords) {
317
- query += ' RETURNING ';
318
- query += getColumnsToSelect({
319
- model,
320
- select: returnSelect,
321
- });
322
- }
323
- return {
324
- query,
325
- params,
326
- };
327
- }
328
- exports.getInsertQueryAndParams = getInsertQueryAndParams;
329
- /**
330
- * Gets the update syntax for the specified model and values
331
- * @param {object} args - Arguments
332
- * @param {object} args.repositoriesByModelNameLowered - All model schemas organized by global id
333
- * @param {object} args.model - Model schema
334
- * @param {object} [args.where] - Object representing the where query
335
- * @param {object} args.values - Values to set.
336
- * @param {boolean} [args.returnRecords=true] - Determines if inserted records should be returned
337
- * @param {string[]} [args.returnSelect] - Array of model property names to return from the query.
338
- * @returns {{query: string, params: object[]}}
339
- */
340
- function getUpdateQueryAndParams({ repositoriesByModelNameLowered, model, where, values = {}, returnRecords = true, returnSelect, }) {
341
- for (const column of model.updateDateColumns) {
342
- if (_.isUndefined(values[column.propertyName])) {
343
- // eslint-disable-next-line no-param-reassign, @typescript-eslint/ban-ts-comment
344
- // @ts-expect-error - Date is not assignable to T[string & keyof T]
345
- values[column.propertyName] = new Date();
346
- }
347
- }
348
- const params = [];
349
- let query = `UPDATE "${model.tableName}" SET `;
350
- let isFirstProperty = true;
351
- for (const [propertyName, value] of Object.entries(values)) {
352
- const column = model.columnsByPropertyName[propertyName];
353
- if (column && !column.collection) {
354
- if (!isFirstProperty) {
355
- query += ',';
356
- }
357
- query += `"${column.name}"=`;
358
- if (_.isNil(value)) {
359
- query += 'NULL';
360
- }
361
- else {
362
- const isJsonArray = column.type === 'json' && _.isArray(value);
363
- const relatedModelName = column.model;
364
- // Check and enforce max length for applicable types
365
- const { maxLength, type } = column;
366
- if (maxLength && ['string', 'string[]'].includes(type)) {
367
- const normalizedValues = (Array.isArray(value) ? value : [value]);
368
- for (const normalizedValue of normalizedValues) {
369
- if (normalizedValue?.length > maxLength) {
370
- throw new errors_1.QueryError(`Update statement for "${model.name}" contains a value that exceeds maxLength on field: ${column.propertyName}`, model);
371
- }
372
- }
373
- }
374
- if (relatedModelName && _.isObject(value)) {
375
- const relatedModelRepository = repositoriesByModelNameLowered[relatedModelName.toLowerCase()];
376
- if (!relatedModelRepository) {
377
- throw new errors_1.QueryError(`Unable to find model schema (${relatedModelName}) specified as model type for "${propertyName}" on "${model.name}"`, model);
378
- }
379
- const relatedModelPrimaryKey = relatedModelRepository.model.primaryKeyColumn;
380
- if (!relatedModelPrimaryKey) {
381
- throw new errors_1.QueryError(`Unable to find primary key column for ${relatedModelName} when inserting ${model.name}.${column.propertyName} value.`, model);
382
- }
383
- const primaryKeyValue = value[relatedModelPrimaryKey.propertyName];
384
- if (_.isNil(primaryKeyValue)) {
385
- throw new errors_1.QueryError(`Undefined primary key value for hydrated object value for "${column.propertyName}" on "${model.name}"`, model);
386
- }
387
- params.push(primaryKeyValue);
388
- }
389
- else if (isJsonArray) {
390
- // Inserting an array to a json/jsonb column will result in a message: invalid input syntax for type json
391
- // https://github.com/brianc/node-postgres/issues/442
392
- params.push(JSON.stringify(value));
393
- }
394
- else {
395
- params.push(value);
396
- }
397
- query += `$${params.length}`;
398
- if (isJsonArray) {
399
- query += '::jsonb';
400
- }
401
- }
402
- isFirstProperty = false;
403
- }
404
- }
405
- for (const column of model.versionColumns) {
406
- if (!_.isUndefined(values[column.propertyName])) {
407
- if (!isFirstProperty) {
408
- query += ',';
409
- }
410
- query += `"${column.name}"="${column.name}"+1`;
411
- isFirstProperty = false;
412
- }
413
- }
414
- const { whereStatement } = buildWhereStatement({
415
- repositoriesByModelNameLowered,
416
- model,
417
- where,
418
- params,
419
- });
420
- if (whereStatement) {
421
- query += ` ${whereStatement}`;
422
- }
423
- if (returnRecords) {
424
- query += ' RETURNING ';
425
- query += getColumnsToSelect({
426
- model,
427
- select: returnSelect,
428
- });
429
- }
430
- return {
431
- query,
432
- params,
433
- };
434
- }
435
- exports.getUpdateQueryAndParams = getUpdateQueryAndParams;
436
- /**
437
- * Gets the delete syntax for the specified model and where criteria
438
- * @param {object} args - Arguments
439
- * @param {object} args.repositoriesByModelNameLowered - All model schemas organized by global id
440
- * @param {object} args.model - Model schema
441
- * @param {object} [args.where] - Object representing the where query
442
- * @param {boolean} [args.returnRecords=true] - Determines if inserted records should be returned
443
- * @param {string[]} [args.returnSelect] - Array of model property names to return from the query.
444
- * @returns {{query: string, params: object[]}}
445
- */
446
- function getDeleteQueryAndParams({ repositoriesByModelNameLowered, model, where, returnRecords = true, returnSelect, }) {
447
- let query = `DELETE FROM "${model.tableName}"`;
448
- const { whereStatement, params } = buildWhereStatement({
449
- repositoriesByModelNameLowered,
450
- model,
451
- where,
452
- });
453
- if (whereStatement) {
454
- query += ` ${whereStatement}`;
455
- }
456
- if (returnRecords) {
457
- query += ' RETURNING ';
458
- query += getColumnsToSelect({
459
- model,
460
- select: returnSelect,
461
- });
462
- }
463
- return {
464
- query,
465
- params,
466
- };
467
- }
468
- exports.getDeleteQueryAndParams = getDeleteQueryAndParams;
469
- /**
470
- * Gets SQL representing columns to select
471
- * @param {object} args - Arguments
472
- * @param {object} args.model - Model schema
473
- * @param {string[]} [args.select] - Array of model property names to return from the query.
474
- * @returns {string} SQL columns
475
- * @private
476
- */
477
- function getColumnsToSelect({ model, select, }) {
478
- let selectColumns;
479
- if (select) {
480
- const { primaryKeyColumn } = model;
481
- selectColumns = new Set(select);
482
- // Ensure primary key column is specified
483
- if (primaryKeyColumn) {
484
- selectColumns.add(primaryKeyColumn.propertyName);
485
- }
486
- }
487
- else {
488
- // eslint-disable-next-line no-param-reassign
489
- selectColumns = new Set();
490
- for (const column of model.columns) {
491
- if (!column.collection) {
492
- selectColumns.add(column.propertyName);
493
- }
494
- }
495
- }
496
- let query = '';
497
- for (const [index, propertyName] of Array.from(selectColumns).entries()) {
498
- const column = model.columnsByPropertyName[propertyName];
499
- if (!column) {
500
- throw new errors_1.QueryError(`Unable to find column for property: ${propertyName} on ${model.tableName}`, model);
501
- }
502
- if (index > 0) {
503
- query += ',';
504
- }
505
- if (column.name === propertyName) {
506
- query += `"${propertyName}"`;
507
- }
508
- else {
509
- query += `"${column.name}" AS "${propertyName}"`;
510
- }
511
- }
512
- return query;
513
- }
514
- exports.getColumnsToSelect = getColumnsToSelect;
515
- /**
516
- * Builds the SQL where statement based on the where expression
517
- * @param {object} args - Arguments
518
- * @param {object} args.repositoriesByModelNameLowered - All model schemas organized by global id
519
- * @param {object} args.model - Model schema
520
- * @param {object} [args.where]
521
- * @param {(number|string|object|null)[]} [args.params] - Objects to pass as parameters for the query
522
- * @returns {object} {{whereStatement?: string, params: Array}}
523
- * @private
524
- */
525
- function buildWhereStatement({ repositoriesByModelNameLowered, model, where, params = [], }) {
526
- let whereStatement;
527
- if (_.isObject(where) && Object.keys(where).length) {
528
- whereStatement = buildWhere({
529
- repositoriesByModelNameLowered,
530
- model,
531
- comparer: 'and',
532
- value: where,
533
- params,
534
- });
535
- if (!whereStatement) {
536
- throw new errors_1.QueryError(`WHERE statement is unexpectedly empty.`, model, where);
537
- }
538
- }
539
- if (whereStatement) {
540
- whereStatement = `WHERE ${whereStatement}`;
541
- }
542
- return {
543
- whereStatement,
544
- params,
545
- };
546
- }
547
- exports.buildWhereStatement = buildWhereStatement;
548
- /**
549
- * Builds the SQL order by statement based on the array of sortable expressions
550
- * @param {object} args - Arguments
551
- * @param {object} args.model - Model schema
552
- * @param {string[]|object[]} args.sorts - Property name(s) to sort by
553
- * @returns {string} SQL order by statement
554
- * @private
555
- */
556
- function buildOrderStatement({ model, sorts }) {
557
- if (_.isNil(sorts) || !_.some(sorts)) {
558
- return '';
559
- }
560
- let orderStatement = 'ORDER BY ';
561
- for (const [index, orderProperty] of sorts.entries()) {
562
- if (index > 0) {
563
- orderStatement += ',';
564
- }
565
- const { propertyName, descending } = orderProperty;
566
- const column = model.columnsByPropertyName[propertyName];
567
- if (!column) {
568
- throw new errors_1.QueryError(`Property (${propertyName}) not found in model (${model.name}).`, model);
569
- }
570
- orderStatement += `"${column.name}"`;
571
- if (descending) {
572
- orderStatement += ' DESC';
573
- }
574
- }
575
- return orderStatement;
576
- }
577
- exports.buildOrderStatement = buildOrderStatement;
578
- /**
579
- * Builds a portion of the where statement based on the propertyName
580
- * @param {object} args - Arguments
581
- * @param {object} args.repositoriesByModelNameLowered - All model schemas organized by global id
582
- * @param {object} args.model - Model schema
583
- * @param {string} [args.propertyName] - Name of property to query by
584
- * @param {string} [args.comparer] - Comparison operator
585
- * @param {boolean} [args.isNegated=false] - If it is negated comparison
586
- * @param {object|string|number|boolean} [args.value] - Value to compare. Can also represent a complex where query
587
- * @param {object[]} args.params - Objects to pass as parameters for the query
588
- * @returns {string} - Query text
589
- * @private
590
- */
591
- function buildWhere({ repositoriesByModelNameLowered, model, propertyName, comparer, isNegated = false, value, params = [], }) {
592
- switch (comparer ?? propertyName) {
593
- case '!':
594
- case 'not':
595
- return buildWhere({
596
- repositoriesByModelNameLowered,
597
- model,
598
- propertyName,
599
- isNegated: true,
600
- value,
601
- params,
602
- });
603
- case 'or':
604
- return buildOrOperatorStatement({
605
- repositoriesByModelNameLowered,
606
- model,
607
- isNegated,
608
- value: value,
609
- params,
610
- });
611
- case 'contains':
612
- if (_.isArray(value)) {
613
- const values = value.map((val) => {
614
- if (!_.isString(val)) {
615
- throw new errors_1.QueryError(`Expected all array values to be strings for "contains" constraint. Property (${propertyName ?? ''}) in model (${model.name}).`, model);
616
- }
617
- return `%${val}%`;
618
- });
619
- return buildWhere({
620
- repositoriesByModelNameLowered,
621
- model,
622
- propertyName,
623
- comparer: 'like',
624
- isNegated,
625
- value: values,
626
- params,
627
- });
628
- }
629
- if (_.isString(value)) {
630
- return buildWhere({
631
- repositoriesByModelNameLowered,
632
- model,
633
- propertyName,
634
- comparer: 'like',
635
- isNegated,
636
- value: `%${value}%`,
637
- params,
638
- });
639
- }
640
- throw new errors_1.QueryError(`Expected value to be a string for "contains" constraint. Property (${propertyName ?? ''}) in model (${model.name}).`, model);
641
- case 'startsWith':
642
- if (_.isArray(value)) {
643
- const values = value.map((val) => {
644
- if (!_.isString(val)) {
645
- throw new errors_1.QueryError(`Expected all array values to be strings for "startsWith" constraint. Property (${propertyName ?? ''}) in model (${model.name}).`, model);
646
- }
647
- return `${val}%`;
648
- });
649
- return buildWhere({
650
- repositoriesByModelNameLowered,
651
- model,
652
- propertyName,
653
- comparer: 'like',
654
- isNegated,
655
- value: values,
656
- params,
657
- });
658
- }
659
- if (_.isString(value)) {
660
- return buildWhere({
661
- repositoriesByModelNameLowered,
662
- model,
663
- propertyName,
664
- comparer: 'like',
665
- isNegated,
666
- value: `${value}%`,
667
- params,
668
- });
669
- }
670
- throw new errors_1.QueryError(`Expected value to be a string for "startsWith" constraint. Property (${propertyName ?? ''}) in model (${model.name}).`, model);
671
- case 'endsWith':
672
- if (_.isArray(value)) {
673
- const values = value.map((val) => {
674
- if (!_.isString(val)) {
675
- throw new errors_1.QueryError(`Expected all array values to be strings for "endsWith" constraint. Property (${propertyName ?? ''}) in model (${model.name}).`, model);
676
- }
677
- return `%${val}`;
678
- });
679
- return buildWhere({
680
- repositoriesByModelNameLowered,
681
- model,
682
- propertyName,
683
- comparer: 'like',
684
- isNegated,
685
- value: values,
686
- params,
687
- });
688
- }
689
- if (_.isString(value)) {
690
- return buildWhere({
691
- repositoriesByModelNameLowered,
692
- model,
693
- propertyName,
694
- comparer: 'like',
695
- isNegated,
696
- value: `%${value}`,
697
- params,
698
- });
699
- }
700
- throw new errors_1.QueryError(`Expected value to be a string for "endsWith" constraint. Property (${propertyName ?? ''}) in model (${model.name}).`, model);
701
- case 'like':
702
- return buildLikeOperatorStatement({
703
- model,
704
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
705
- propertyName: propertyName,
706
- isNegated,
707
- value: value,
708
- params,
709
- });
710
- default: {
711
- if (_.isUndefined(value)) {
712
- throw new errors_1.QueryError(`Attempting to query with an undefined value. ${propertyName ?? ''} on ${model.name}`, model);
713
- }
714
- if (propertyName) {
715
- const column = model.columnsByPropertyName[propertyName];
716
- if (column && _.isObject(value)) {
717
- if (column.primary) {
718
- const primaryKeyValue = value[column.propertyName];
719
- if (!_.isNil(primaryKeyValue)) {
720
- // Treat `value` as a hydrated object
721
- return buildWhere({
722
- repositoriesByModelNameLowered,
723
- model,
724
- propertyName,
725
- comparer,
726
- isNegated,
727
- value: primaryKeyValue,
728
- params,
729
- });
730
- }
731
- }
732
- else if (column.model) {
733
- const relatedModelRepository = repositoriesByModelNameLowered[column.model.toLowerCase()];
734
- if (!relatedModelRepository) {
735
- throw new errors_1.QueryError(`Unable to find model schema (${column.model}) specified in where clause for "${column.propertyName}"`, model);
736
- }
737
- const relatedModelPrimaryKey = relatedModelRepository.model.primaryKeyColumn;
738
- if (!relatedModelPrimaryKey) {
739
- throw new errors_1.QueryError(`Unable to find primary key column for ${column.model} specified in where clause for ${model.name}.${column.propertyName}`, model);
740
- }
741
- const primaryKeyValue = value[relatedModelPrimaryKey.propertyName];
742
- if (!_.isNil(primaryKeyValue)) {
743
- // Treat `value` as a hydrated object
744
- return buildWhere({
745
- repositoriesByModelNameLowered,
746
- model,
747
- propertyName,
748
- comparer,
749
- isNegated,
750
- value: primaryKeyValue,
751
- params,
752
- });
753
- }
754
- }
755
- }
756
- }
757
- if (_.isArray(value)) {
758
- if (!value.length) {
759
- const columnTypeFromPropertyName = propertyName ? model.columnsByPropertyName[propertyName] : null;
760
- const columnTypeFromComparer = comparer ? model.columnsByPropertyName[comparer] : null;
761
- const arrayColumn = columnTypeFromPropertyName ?? columnTypeFromComparer;
762
- if (arrayColumn) {
763
- const arrayColumnType = arrayColumn.type ? arrayColumn.type.toLowerCase() : '';
764
- if (arrayColumnType === 'array' || arrayColumnType === 'string[]' || arrayColumnType === 'integer[]' || arrayColumnType === 'float[]' || arrayColumnType === 'boolean[]') {
765
- return `"${arrayColumn.name}"${isNegated ? '<>' : '='}'{}'`;
766
- }
767
- }
768
- if (isNegated) {
769
- return '1=1';
770
- }
771
- return '1<>1';
772
- }
773
- const orConstraints = [];
774
- const valueWithoutNull = [];
775
- for (const item of value) {
776
- if (_.isNull(item)) {
777
- orConstraints.push(buildWhere({
778
- repositoriesByModelNameLowered,
779
- model,
780
- propertyName,
781
- isNegated,
782
- value: null,
783
- params,
784
- }));
785
- }
786
- else if (item === '') {
787
- orConstraints.push(buildWhere({
788
- repositoriesByModelNameLowered,
789
- model,
790
- propertyName,
791
- isNegated,
792
- value: '',
793
- params,
794
- }));
795
- }
796
- else {
797
- valueWithoutNull.push(item);
798
- }
799
- }
800
- if (valueWithoutNull.length === 1) {
801
- orConstraints.push(buildWhere({
802
- repositoriesByModelNameLowered,
803
- model,
804
- propertyName,
805
- isNegated,
806
- value: valueWithoutNull[0],
807
- params,
808
- }));
809
- }
810
- else if (valueWithoutNull.length) {
811
- const columnTypeFromPropertyName = propertyName ? model.columnsByPropertyName[propertyName] : null;
812
- const columnTypeFromComparer = comparer ? model.columnsByPropertyName[comparer] : null;
813
- const columnType = columnTypeFromPropertyName ?? columnTypeFromComparer;
814
- if (columnType) {
815
- let columnTypeLowered = columnType.type ? columnType.type.toLowerCase() : '';
816
- if (columnTypeLowered === 'array' || columnTypeLowered === 'string[]' || columnTypeLowered === 'integer[]' || columnTypeLowered === 'float[]' || columnTypeLowered === 'boolean[]') {
817
- for (const val of valueWithoutNull) {
818
- orConstraints.push(buildWhere({
819
- repositoriesByModelNameLowered,
820
- model,
821
- propertyName,
822
- isNegated,
823
- value: val,
824
- params,
825
- }));
826
- }
827
- }
828
- else {
829
- // If it's an array of values for a model relationship, try to find the type of the primary key for the related model
830
- if (!columnTypeLowered) {
831
- const columnAsModelType = columnType;
832
- if (columnAsModelType.model) {
833
- const relatedModelRepository = repositoriesByModelNameLowered[columnAsModelType.model.toLowerCase()];
834
- if (!relatedModelRepository) {
835
- throw new errors_1.QueryError(`Unable to find model schema (${columnAsModelType.model}) specified in where clause for "${columnAsModelType.propertyName}"`, model);
836
- }
837
- const relatedModelPrimaryKey = relatedModelRepository.model.primaryKeyColumn;
838
- if (!relatedModelPrimaryKey) {
839
- throw new errors_1.QueryError(`Unable to find primary key column for ${columnAsModelType.model} specified in where clause for ${model.name}.${columnAsModelType.propertyName}`, model);
840
- }
841
- columnTypeLowered = relatedModelPrimaryKey.type ? relatedModelPrimaryKey.type.toLowerCase() : '';
842
- }
843
- }
844
- let castType;
845
- switch (columnTypeLowered) {
846
- case 'int':
847
- case 'integer':
848
- case 'integer[]':
849
- castType = '::INTEGER[]';
850
- break;
851
- case 'float':
852
- case 'float[]':
853
- castType = '::NUMERIC[]';
854
- break;
855
- case 'boolean':
856
- case 'boolean[]':
857
- castType = '::BOOLEAN[]';
858
- break;
859
- default:
860
- castType = '::TEXT[]';
861
- break;
862
- }
863
- params.push(valueWithoutNull);
864
- orConstraints.push(`"${columnType.name}"${isNegated ? '<>ALL' : '=ANY'}($${params.length}${castType})`);
865
- }
866
- }
867
- // TODO: Validate that when columnType is null, it is expected to return existing constraints
868
- }
869
- if (orConstraints.length === 1) {
870
- return orConstraints[0] ?? '';
871
- }
872
- if (isNegated) {
873
- return orConstraints.join(' AND ');
874
- }
875
- if (orConstraints.length) {
876
- return `(${orConstraints.join(' OR ')})`;
877
- }
878
- return '';
879
- }
880
- if (_.isObject(value) && !_.isDate(value)) {
881
- const andValues = [];
882
- for (const [key, where] of Object.entries(value)) {
883
- // eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents
884
- let subQueryComparer;
885
- if (isComparer(key)) {
886
- subQueryComparer = key;
887
- }
888
- else {
889
- // eslint-disable-next-line no-param-reassign
890
- propertyName = key;
891
- }
892
- andValues.push(buildWhere({
893
- repositoriesByModelNameLowered,
894
- model,
895
- propertyName,
896
- comparer: subQueryComparer,
897
- isNegated,
898
- value: where,
899
- params,
900
- }));
901
- }
902
- return andValues.join(' AND ');
903
- }
904
- return buildComparisonOperatorStatement({
905
- model,
906
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
907
- propertyName: propertyName,
908
- comparer,
909
- isNegated,
910
- value: value,
911
- params,
912
- });
913
- }
914
- }
915
- }
916
- function buildOrOperatorStatement({ repositoriesByModelNameLowered, model, isNegated, value, params = [], }) {
917
- const orClauses = [];
918
- for (const constraint of value) {
919
- const orClause = buildWhere({
920
- repositoriesByModelNameLowered,
921
- model,
922
- isNegated,
923
- value: constraint,
924
- params,
925
- });
926
- if (orClause) {
927
- orClauses.push(`(${orClause})`);
928
- }
929
- }
930
- if (orClauses.length === 1) {
931
- return orClauses[0] ?? '';
932
- }
933
- if (isNegated) {
934
- return orClauses.join(' AND ');
935
- }
936
- if (orClauses.length) {
937
- return `(${orClauses.join(' OR ')})`;
938
- }
939
- return '';
940
- }
941
- function buildLikeOperatorStatement({ model, propertyName, isNegated, value, params }) {
942
- if (_.isArray(value)) {
943
- if (!value.length) {
944
- if (isNegated) {
945
- return '1=1';
946
- }
947
- return '1<>1';
948
- }
949
- if (value.length > 1) {
950
- const orConstraints = [];
951
- for (const item of value) {
952
- if (_.isNull(item)) {
953
- orConstraints.push(buildLikeOperatorStatement({
954
- model,
955
- propertyName,
956
- isNegated,
957
- value: null,
958
- params,
959
- }));
960
- }
961
- else if (item === '') {
962
- orConstraints.push(buildLikeOperatorStatement({
963
- model,
964
- propertyName,
965
- isNegated,
966
- value: '',
967
- params,
968
- }));
969
- }
970
- else {
971
- orConstraints.push(buildLikeOperatorStatement({
972
- model,
973
- propertyName,
974
- isNegated,
975
- value: item,
976
- params,
977
- }));
978
- }
979
- }
980
- if (orConstraints.length === 1) {
981
- return orConstraints[0] ?? '';
982
- }
983
- if (isNegated) {
984
- return orConstraints.join(' AND ');
985
- }
986
- if (orConstraints.length) {
987
- return `(${orConstraints.join(' OR ')})`;
988
- }
989
- return '';
990
- }
991
- // eslint-disable-next-line no-param-reassign
992
- value = value[0];
993
- }
994
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
995
- const column = model.columnsByPropertyName[propertyName];
996
- if (!column) {
997
- throw new errors_1.QueryError(`Unable to find property ${propertyName} on model ${model.name}`, model);
998
- }
999
- if (_.isNull(value)) {
1000
- return `"${column.name}" ${isNegated ? 'IS NOT' : 'IS'} NULL`;
1001
- }
1002
- if (_.isString(value)) {
1003
- if (value) {
1004
- // NOTE: This is doing a case-insensitive pattern match
1005
- params.push(value);
1006
- const columnType = column.type?.toLowerCase();
1007
- if (columnType === 'array' || columnType === 'string[]') {
1008
- return `${isNegated ? 'NOT ' : ''}EXISTS(SELECT 1 FROM (SELECT unnest("${column.name}") AS "unnested_${column.name}") __unnested WHERE "unnested_${column.name}" ILIKE $${params.length})`;
1009
- }
1010
- return `"${column.name}"${isNegated ? ' NOT' : ''} ILIKE $${params.length}`;
1011
- }
1012
- return `"${column.name}" ${isNegated ? '!=' : '='} ''`;
1013
- }
1014
- throw new errors_1.QueryError(`Expected value to be a string for "like" constraint. Property (${propertyName}) in model (${model.name}).`, model);
1015
- }
1016
- function buildComparisonOperatorStatement({ model, propertyName, comparer, isNegated, value, params = [] }) {
1017
- const column = model.columnsByPropertyName[propertyName];
1018
- if (!column) {
1019
- throw new errors_1.QueryError(`Unable to find property ${propertyName} on model ${model.name}`, model);
1020
- }
1021
- if (_.isNull(value)) {
1022
- return `"${column.name}" ${isNegated ? 'IS NOT' : 'IS'} NULL`;
1023
- }
1024
- params.push(value);
1025
- const columnType = column.type;
1026
- const supportsLessThanGreaterThan = columnType !== 'array' && columnType !== 'json';
1027
- switch (comparer) {
1028
- case '<':
1029
- if (!supportsLessThanGreaterThan) {
1030
- throw new errors_1.QueryError(`< operator is not supported for ${columnType || 'unknown'} type. ${propertyName || ''} on ${model.name}`, model);
1031
- }
1032
- return `"${column.name}"${isNegated ? '>=' : '<'}$${params.length}`;
1033
- case '<=':
1034
- if (!supportsLessThanGreaterThan) {
1035
- throw new errors_1.QueryError(`<= operator is not supported for ${columnType || 'unknown'} type. ${propertyName || ''} on ${model.name}`, model);
1036
- }
1037
- return `"${column.name}"${isNegated ? '>' : '<='}$${params.length}`;
1038
- case '>':
1039
- if (!supportsLessThanGreaterThan) {
1040
- throw new errors_1.QueryError(`> operator is not supported for ${columnType || 'unknown'} type. ${propertyName || ''} on ${model.name}`, model);
1041
- }
1042
- return `"${column.name}"${isNegated ? '<=' : '>'}$${params.length}`;
1043
- case '>=':
1044
- if (!supportsLessThanGreaterThan) {
1045
- throw new errors_1.QueryError(`>= operator is not supported for ${columnType || 'unknown'} type. ${propertyName || ''} on ${model.name}`, model);
1046
- }
1047
- return `"${column.name}"${isNegated ? '<' : '>='}$${params.length}`;
1048
- default:
1049
- if (columnType && (columnType === 'array' || columnType.endsWith('[]'))) {
1050
- return `$${params.length}${isNegated ? '<>ALL(' : '=ANY('}"${column.name}")`;
1051
- }
1052
- return `"${column.name}"${isNegated ? '<>' : '='}$${params.length}`;
1053
- }
1054
- }
1055
- /**
1056
- * Determines if the specified value is a comparer
1057
- * @param {string} value
1058
- * @returns {boolean}
1059
- * @private
1060
- */
1061
- function isComparer(value) {
1062
- switch (value) {
1063
- case '!':
1064
- case 'not':
1065
- case 'or':
1066
- case 'and':
1067
- case 'contains':
1068
- case 'startsWith':
1069
- case 'endsWith':
1070
- case 'like':
1071
- case '<':
1072
- case '<=':
1073
- case '>':
1074
- case '>=':
1075
- return true;
1076
- default:
1077
- return false;
1078
- }
1079
- }
1080
- /* eslint-enable @typescript-eslint/no-use-before-define */
1081
- //# sourceMappingURL=SqlHelper.js.map