@autofleet/sadot 0.13.2-beta.7 → 0.13.3-beta-c0a9f0d7.0
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.
- package/.env +4 -0
- package/dist/hooks/hooks.js +0 -3
- package/dist/index.js +1 -4
- package/dist/models/index.d.ts +1 -1
- package/dist/models/index.js +1 -1
- package/dist/scopes/filter.d.ts +1 -2
- package/dist/scopes/filter.js +7 -8
- package/dist/scopes/helpers/filter.helpers.js +9 -11
- package/package.json +1 -1
- package/src/hooks/hooks.ts +91 -94
- package/src/index.ts +1 -4
- package/src/models/index.ts +1 -1
- package/src/scopes/filter.ts +8 -7
- package/src/scopes/helpers/filter.helpers.ts +9 -11
package/.env
ADDED
package/dist/hooks/hooks.js
CHANGED
|
@@ -222,10 +222,7 @@ const formatDates = (fieldDefinitions, instance) => {
|
|
|
222
222
|
throw new errors_2.InvalidValueError(value, name, validationError);
|
|
223
223
|
}
|
|
224
224
|
// eslint-disable-next-line no-param-reassign
|
|
225
|
-
const typeofjoi = typeof joiValue;
|
|
226
|
-
logger_1.default.info('sadot - formatting date', { name, value, joiValue, type: typeof joiValue });
|
|
227
225
|
instance.customFields[name] = joiValue.toISOString();
|
|
228
|
-
new Date().toString;
|
|
229
226
|
}
|
|
230
227
|
}
|
|
231
228
|
});
|
package/dist/index.js
CHANGED
|
@@ -54,10 +54,7 @@ const useCustomFields = async (app, getModel, options) => {
|
|
|
54
54
|
}
|
|
55
55
|
// The order is important
|
|
56
56
|
(0, init_1.addHooks)(models, getModel, { useCustomFieldsEntries });
|
|
57
|
-
await (0, models_1.initTables)(sequelize, options.getUser, { useCustomFieldsEntries })
|
|
58
|
-
logger_1.default.error('sadot - error while initializing custom fields tables', e);
|
|
59
|
-
throw e;
|
|
60
|
-
});
|
|
57
|
+
await (0, models_1.initTables)(sequelize, options.getUser, { useCustomFieldsEntries });
|
|
61
58
|
(0, init_1.addScopes)(models, getModel, { useCustomFieldsEntries });
|
|
62
59
|
(0, init_1.applyCustomAssociation)(models);
|
|
63
60
|
logger_1.default.debug('sadot - custom fields finished initializing with models', models);
|
package/dist/models/index.d.ts
CHANGED
|
@@ -13,6 +13,6 @@ interface InitTablesOptions {
|
|
|
13
13
|
schemaVersion?: string;
|
|
14
14
|
useCustomFieldsEntries?: boolean;
|
|
15
15
|
}
|
|
16
|
-
declare const initTables: (sequelize: Sequelize, getUser: CustomFieldOptions['getUser'], { schemaPrefix, schemaVersion, useCustomFieldsEntries, }
|
|
16
|
+
declare const initTables: (sequelize: Sequelize, getUser: CustomFieldOptions['getUser'], { schemaPrefix, schemaVersion, useCustomFieldsEntries, }?: InitTablesOptions) => Promise<void>;
|
|
17
17
|
declare const initTestModels: (sequelize: Sequelize) => Promise<void>;
|
|
18
18
|
export { CustomFieldValue, CustomFieldDefinition, CustomFieldEntries, CustomValidator, TestModel, AssociatedTestModel, ContextAwareTestModel, ContextTestModel, initTables, initTestModels, };
|
package/dist/models/index.js
CHANGED
|
@@ -27,7 +27,7 @@ const productionModels = [CustomFieldDefinition_1.default, CustomFieldValue_1.de
|
|
|
27
27
|
const testModels = [TestModel_1.default, AssociatedTestModel_1.default, ContextAwareTestModel_1.default, ContextTestModel_1.default];
|
|
28
28
|
const SADOT_MIGRATION_PREFIX = 'sadot-migration';
|
|
29
29
|
const SCHEMA_VERSION = '49c9dd1d-b1cc-445b-a911-fd349d783110';
|
|
30
|
-
const initTables = async (sequelize, getUser, { schemaPrefix = SADOT_MIGRATION_PREFIX, schemaVersion = SCHEMA_VERSION, useCustomFieldsEntries = false, }) => {
|
|
30
|
+
const initTables = async (sequelize, getUser, { schemaPrefix = SADOT_MIGRATION_PREFIX, schemaVersion = SCHEMA_VERSION, useCustomFieldsEntries = false, } = {}) => {
|
|
31
31
|
const CUSTOM_FIELDS_SCHEMA_VERSION = `${schemaPrefix}_${schemaVersion}${useCustomFieldsEntries ? '_withEntries' : ''}`;
|
|
32
32
|
logger_1.default.info('custom-fields: initialize custom-fields tables');
|
|
33
33
|
// Detect models and import them to the orm
|
package/dist/scopes/filter.d.ts
CHANGED
|
@@ -12,7 +12,6 @@ type customFieldsFilterScopeParams = {
|
|
|
12
12
|
* @returns A function that takes conditions and returns the Sequelize options object.
|
|
13
13
|
*/
|
|
14
14
|
export declare const customFieldsFilterScope: (name: string, options?: Pick<CustomFieldOptions, 'useCustomFieldsEntries'>) => ({ replacementsMap: replacements, scopeValue: conditions }: customFieldsFilterScopeParams) => CustomFieldFilterOptions;
|
|
15
|
-
export declare const scopeName: "filterByCustomFields";
|
|
16
15
|
export declare const customFieldsSortScope: (name: string, options?: Pick<CustomFieldOptions, 'useCustomFieldsEntries'>) => ({ replacementsMap, scopeValue: sort }: {
|
|
17
16
|
replacementsMap: any;
|
|
18
17
|
scopeValue: any;
|
|
@@ -24,7 +23,7 @@ export declare const customFieldsSortScope: (name: string, options?: Pick<Custom
|
|
|
24
23
|
attributes: {
|
|
25
24
|
include: (string | import("sequelize/types/utils").Literal)[][];
|
|
26
25
|
};
|
|
27
|
-
order:
|
|
26
|
+
order: any[][];
|
|
28
27
|
replacements: any;
|
|
29
28
|
};
|
|
30
29
|
export {};
|
package/dist/scopes/filter.js
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.customFieldsSortScope = exports.
|
|
3
|
+
exports.customFieldsSortScope = exports.customFieldsFilterScope = void 0;
|
|
4
4
|
/* eslint-disable import/prefer-default-export */
|
|
5
5
|
const sequelize_1 = require("sequelize");
|
|
6
6
|
const sequelize_typescript_1 = require("sequelize-typescript");
|
|
7
7
|
const common_types_1 = require("@autofleet/common-types");
|
|
8
|
-
const helpers_1 = require("../utils/helpers");
|
|
9
8
|
const filter_helpers_1 = require("./helpers/filter.helpers");
|
|
10
9
|
const { CUSTOM_FIELDS_FILTER_SCOPE } = common_types_1.customFields;
|
|
11
10
|
/**
|
|
@@ -46,23 +45,23 @@ const customFieldsFilterScope = (name, options) => ({ replacementsMap: replaceme
|
|
|
46
45
|
};
|
|
47
46
|
};
|
|
48
47
|
exports.customFieldsFilterScope = customFieldsFilterScope;
|
|
49
|
-
exports.scopeName = CUSTOM_FIELDS_FILTER_SCOPE;
|
|
50
48
|
const customFieldsSortScope = (name, options) => ({ replacementsMap, scopeValue: sort }) => {
|
|
51
49
|
if (!sort || sort.length === 0) {
|
|
52
50
|
return {};
|
|
53
51
|
}
|
|
54
52
|
const queryType = options?.useCustomFieldsEntries ? filter_helpers_1.SubQueryType.ENTRIES : filter_helpers_1.SubQueryType.VALUES;
|
|
55
|
-
const randomStr = (0, helpers_1.generateRandomString)();
|
|
56
53
|
const includes = Object.entries(sort).map(([key]) => {
|
|
57
54
|
const replacementKey = Object.keys(replacementsMap).find((randomString) => replacementsMap[randomString] === key);
|
|
55
|
+
const alias = `cf_sort_${key}`; // Explicit unique alias per field
|
|
58
56
|
return ([
|
|
59
|
-
sequelize_typescript_1.Sequelize.literal((0, filter_helpers_1.getSortCustomFieldsSubQuery)(queryType, name, replacementKey)),
|
|
60
|
-
|
|
57
|
+
sequelize_typescript_1.Sequelize.literal(`(${(0, filter_helpers_1.getSortCustomFieldsSubQuery)(queryType, name, replacementKey)})`),
|
|
58
|
+
alias,
|
|
61
59
|
]);
|
|
62
60
|
});
|
|
63
|
-
const orders = Object.entries(sort).map(([, sortObject]) => {
|
|
61
|
+
const orders = Object.entries(sort).map(([key, sortObject]) => {
|
|
64
62
|
const direction = typeof sortObject === 'string' ? sortObject : Object.values(sortObject)[0];
|
|
65
|
-
|
|
63
|
+
const alias = `cf_sort_${key}`;
|
|
64
|
+
return [sequelize_typescript_1.Sequelize.literal(`"${alias}"`), direction || 'ASC'];
|
|
66
65
|
});
|
|
67
66
|
return {
|
|
68
67
|
attributes: {
|
|
@@ -117,17 +117,15 @@ const getSortCustomFieldsSubQuery = (queryType, modelType, replacementKey) => {
|
|
|
117
117
|
`;
|
|
118
118
|
case SubQueryType.ENTRIES:
|
|
119
119
|
return `(
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
)
|
|
130
|
-
`;
|
|
120
|
+
SELECT customFields.value::numeric -- <-- Add numeric casting if sorting numeric values
|
|
121
|
+
FROM custom_field_entries AS ${exports.CE_TABLE_ALIAS},
|
|
122
|
+
jsonb_each_text(custom_fields) AS customFields
|
|
123
|
+
WHERE
|
|
124
|
+
customFields.key = :${replacementKey}${exports.AND_DELIMITER}
|
|
125
|
+
${exports.CE_TABLE_ALIAS}.model_type = '${modelType}'${exports.AND_DELIMITER}
|
|
126
|
+
${exports.CE_TABLE_ALIAS}.model_id = "${modelType}"."id"
|
|
127
|
+
LIMIT 1
|
|
128
|
+
)`;
|
|
131
129
|
default:
|
|
132
130
|
throw new Error('Invalid query type');
|
|
133
131
|
}
|
package/package.json
CHANGED
package/src/hooks/hooks.ts
CHANGED
|
@@ -258,10 +258,7 @@ const formatDates = (fieldDefinitions: CustomFieldDefinition[], instance: any) =
|
|
|
258
258
|
throw new InvalidValueError(value, name, validationError);
|
|
259
259
|
}
|
|
260
260
|
// eslint-disable-next-line no-param-reassign
|
|
261
|
-
const typeofjoi = typeof joiValue;
|
|
262
|
-
logger.info('sadot - formatting date', { name, value, joiValue, type: typeof joiValue });
|
|
263
261
|
instance.customFields[name] = joiValue.toISOString();
|
|
264
|
-
new Date().toString
|
|
265
262
|
}
|
|
266
263
|
}
|
|
267
264
|
});
|
|
@@ -278,72 +275,72 @@ export const beforeCreate = (
|
|
|
278
275
|
instance,
|
|
279
276
|
options,
|
|
280
277
|
): Promise<void> => {
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
278
|
+
logger.debug('sadot - before create hook');
|
|
279
|
+
const { fields } = options;
|
|
280
|
+
const modelType = instance.constructor.name;
|
|
284
281
|
|
|
285
|
-
|
|
282
|
+
const identifiers = applyScopeToInstance(instance, scopeAttributes);
|
|
286
283
|
|
|
287
|
-
|
|
284
|
+
// Step 1: Handle custom fields default values and required fields
|
|
288
285
|
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
286
|
+
const fieldDefinitions = await getFieldDefinitions({
|
|
287
|
+
modelType, modelOptions, identifiers, options,
|
|
288
|
+
});
|
|
292
289
|
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
290
|
+
// Apply default values
|
|
291
|
+
const fieldsWithDefaultValue = fieldDefinitions.filter((def) => ![null, undefined].includes(def.defaultValue));
|
|
292
|
+
if (fieldsWithDefaultValue.length) {
|
|
293
|
+
// eslint-disable-next-line no-param-reassign
|
|
294
|
+
instance.customFields ||= {};
|
|
295
|
+
fieldsWithDefaultValue
|
|
296
|
+
.filter((def) => (instance.customFields?.[def.name] === undefined))
|
|
297
|
+
.forEach(({ name, defaultValue }) => {
|
|
298
|
+
// eslint-disable-next-line no-param-reassign
|
|
299
|
+
instance.customFields[name] = defaultValue;
|
|
300
|
+
});
|
|
301
|
+
}
|
|
305
302
|
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
303
|
+
// Check for required fields
|
|
304
|
+
const requiredFieldsNames = Array.from(
|
|
305
|
+
new Set(fieldDefinitions.filter(({ required }) => required).map(({ name }) => name)),
|
|
306
|
+
);
|
|
307
|
+
const { customFields } = instance;
|
|
308
|
+
const fieldsNames = Object.keys(customFields ?? {});
|
|
309
|
+
const missingFields = requiredFieldsNames.filter((name) => !fieldsNames.includes(name));
|
|
310
|
+
if (missingFields?.length) {
|
|
311
|
+
throw new MissingRequiredCustomFieldError(missingFields);
|
|
312
|
+
}
|
|
316
313
|
|
|
317
|
-
|
|
318
|
-
|
|
314
|
+
// Step 2: Validate the model data (including custom fields)
|
|
315
|
+
await validateModel(instance, options, scopeAttributes, true);
|
|
319
316
|
|
|
320
|
-
|
|
321
|
-
|
|
317
|
+
// format date and datetime fields
|
|
318
|
+
formatDates(fieldDefinitions, instance);
|
|
322
319
|
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
320
|
+
// Step 3: Save custom field values if they exist
|
|
321
|
+
const customFieldsIdx = fields.indexOf('customFields');
|
|
322
|
+
if (customFieldsIdx === -1 || !customFields || !Object.keys(customFields).length) {
|
|
323
|
+
// No custom fields to update
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
329
326
|
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
327
|
+
// Save custom field values
|
|
328
|
+
await updateInstanceValues({
|
|
329
|
+
modelId: instance.id,
|
|
330
|
+
modelType,
|
|
331
|
+
identifiers,
|
|
332
|
+
customFields,
|
|
333
|
+
options: {
|
|
334
|
+
useCustomFieldsEntries: sadotOptions.useCustomFieldsEntries,
|
|
335
|
+
transaction: options.transaction,
|
|
336
|
+
modelOptions,
|
|
337
|
+
},
|
|
338
|
+
});
|
|
342
339
|
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
340
|
+
// Remove customFields from fields array after handling
|
|
341
|
+
// eslint-disable-next-line no-param-reassign
|
|
342
|
+
fields.splice(customFieldsIdx, 1);
|
|
343
|
+
};
|
|
347
344
|
|
|
348
345
|
/**
|
|
349
346
|
* Hook to handle validation and custom fields during update
|
|
@@ -356,48 +353,48 @@ export const beforeUpdate = (
|
|
|
356
353
|
instance,
|
|
357
354
|
options,
|
|
358
355
|
): Promise<void> => {
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
356
|
+
logger.debug('sadot - before update hook');
|
|
357
|
+
const { fields } = options;
|
|
358
|
+
const modelType = instance.constructor.name;
|
|
359
|
+
const identifiers = applyScopeToInstance(instance, scopeAttributes);
|
|
363
360
|
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
361
|
+
const fieldDefinitions = await getFieldDefinitions({
|
|
362
|
+
modelType, modelOptions, identifiers, options,
|
|
363
|
+
});
|
|
367
364
|
|
|
368
|
-
|
|
369
|
-
|
|
365
|
+
// Step 1: Validate the model data (including custom fields)
|
|
366
|
+
await validateModel(instance, options, scopeAttributes, false);
|
|
370
367
|
|
|
371
|
-
|
|
372
|
-
|
|
368
|
+
// format date and datetime fields
|
|
369
|
+
formatDates(fieldDefinitions, instance);
|
|
373
370
|
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
371
|
+
// Step 2: Update custom field values if they exist
|
|
372
|
+
const customFieldsIdx = fields.indexOf('customFields');
|
|
373
|
+
if (customFieldsIdx > -1) {
|
|
374
|
+
const { customFields } = instance;
|
|
378
375
|
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
376
|
+
if (!Object.keys(customFields).length) {
|
|
377
|
+
return;
|
|
378
|
+
}
|
|
382
379
|
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
380
|
+
// Save custom field values
|
|
381
|
+
await updateInstanceValues({
|
|
382
|
+
modelId: instance.id,
|
|
383
|
+
modelType,
|
|
384
|
+
identifiers,
|
|
385
|
+
customFields,
|
|
386
|
+
options: {
|
|
387
|
+
useCustomFieldsEntries: sadotOptions.useCustomFieldsEntries,
|
|
388
|
+
transaction: options.transaction,
|
|
389
|
+
modelOptions,
|
|
390
|
+
},
|
|
391
|
+
});
|
|
395
392
|
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
393
|
+
// Remove customFields from fields array after handling
|
|
394
|
+
// eslint-disable-next-line no-param-reassign
|
|
395
|
+
fields.splice(customFieldsIdx, 1);
|
|
396
|
+
}
|
|
397
|
+
};
|
|
401
398
|
|
|
402
399
|
/**
|
|
403
400
|
* Hook to enable individual hooks for bulk create operations
|
package/src/index.ts
CHANGED
|
@@ -37,10 +37,7 @@ const useCustomFields = async (
|
|
|
37
37
|
}
|
|
38
38
|
// The order is important
|
|
39
39
|
addHooks(models, getModel, { useCustomFieldsEntries });
|
|
40
|
-
await initTables(sequelize, options.getUser, { useCustomFieldsEntries })
|
|
41
|
-
logger.error('sadot - error while initializing custom fields tables', e);
|
|
42
|
-
throw e;
|
|
43
|
-
});
|
|
40
|
+
await initTables(sequelize, options.getUser, { useCustomFieldsEntries });
|
|
44
41
|
addScopes(models, getModel, { useCustomFieldsEntries });
|
|
45
42
|
applyCustomAssociation(models);
|
|
46
43
|
|
package/src/models/index.ts
CHANGED
|
@@ -32,7 +32,7 @@ const initTables = async (
|
|
|
32
32
|
schemaPrefix = SADOT_MIGRATION_PREFIX,
|
|
33
33
|
schemaVersion = SCHEMA_VERSION,
|
|
34
34
|
useCustomFieldsEntries = false,
|
|
35
|
-
}: InitTablesOptions,
|
|
35
|
+
}: InitTablesOptions = {},
|
|
36
36
|
): Promise<void> => {
|
|
37
37
|
const CUSTOM_FIELDS_SCHEMA_VERSION = `${schemaPrefix}_${schemaVersion}${useCustomFieldsEntries ? '_withEntries' : ''}`;
|
|
38
38
|
logger.info('custom-fields: initialize custom-fields tables');
|
package/src/scopes/filter.ts
CHANGED
|
@@ -64,8 +64,6 @@ export const customFieldsFilterScope = (
|
|
|
64
64
|
};
|
|
65
65
|
};
|
|
66
66
|
|
|
67
|
-
export const scopeName = CUSTOM_FIELDS_FILTER_SCOPE;
|
|
68
|
-
|
|
69
67
|
export const customFieldsSortScope = (
|
|
70
68
|
name: string,
|
|
71
69
|
options?: Pick<CustomFieldOptions, 'useCustomFieldsEntries'>,
|
|
@@ -75,21 +73,24 @@ export const customFieldsSortScope = (
|
|
|
75
73
|
}
|
|
76
74
|
|
|
77
75
|
const queryType = options?.useCustomFieldsEntries ? SubQueryType.ENTRIES : SubQueryType.VALUES;
|
|
78
|
-
|
|
76
|
+
|
|
79
77
|
const includes = Object.entries(sort).map(([key]) => {
|
|
80
78
|
const replacementKey = Object.keys(replacementsMap).find(
|
|
81
79
|
(randomString) => replacementsMap[randomString] === key,
|
|
82
80
|
);
|
|
81
|
+
const alias = `cf_sort_${key}`; // Explicit unique alias per field
|
|
83
82
|
return ([
|
|
84
|
-
Sequelize.literal(getSortCustomFieldsSubQuery(queryType, name, replacementKey)),
|
|
85
|
-
|
|
83
|
+
Sequelize.literal(`(${getSortCustomFieldsSubQuery(queryType, name, replacementKey)})`),
|
|
84
|
+
alias,
|
|
86
85
|
]);
|
|
87
86
|
});
|
|
88
87
|
|
|
89
|
-
const orders = Object.entries(sort).map(([, sortObject]) => {
|
|
88
|
+
const orders = Object.entries(sort).map(([key, sortObject]) => {
|
|
90
89
|
const direction = typeof sortObject === 'string' ? sortObject : Object.values(sortObject)[0];
|
|
91
|
-
|
|
90
|
+
const alias = `cf_sort_${key}`;
|
|
91
|
+
return [Sequelize.literal(`"${alias}"`), direction || 'ASC'];
|
|
92
92
|
});
|
|
93
|
+
|
|
93
94
|
return {
|
|
94
95
|
attributes: {
|
|
95
96
|
include: includes,
|
|
@@ -134,17 +134,15 @@ export const getSortCustomFieldsSubQuery = (queryType: SubQueryType, modelType:
|
|
|
134
134
|
`;
|
|
135
135
|
case SubQueryType.ENTRIES:
|
|
136
136
|
return `(
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
)
|
|
147
|
-
`;
|
|
137
|
+
SELECT customFields.value::numeric -- <-- Add numeric casting if sorting numeric values
|
|
138
|
+
FROM custom_field_entries AS ${CE_TABLE_ALIAS},
|
|
139
|
+
jsonb_each_text(custom_fields) AS customFields
|
|
140
|
+
WHERE
|
|
141
|
+
customFields.key = :${replacementKey}${AND_DELIMITER}
|
|
142
|
+
${CE_TABLE_ALIAS}.model_type = '${modelType}'${AND_DELIMITER}
|
|
143
|
+
${CE_TABLE_ALIAS}.model_id = "${modelType}"."id"
|
|
144
|
+
LIMIT 1
|
|
145
|
+
)`;
|
|
148
146
|
default:
|
|
149
147
|
throw new Error('Invalid query type');
|
|
150
148
|
}
|