@autofleet/sadot 0.6.10 → 0.6.11

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.
@@ -21,6 +21,12 @@ const castIfNeeded = (conditionValue) => {
21
21
  return '';
22
22
  };
23
23
  const AND_DELIMETER = ' AND ';
24
+ const OR_DELIMETER = ' OR ';
25
+ const CD_TABLE_ALIAS = 'cd';
26
+ const CD_NAME_COLUMN = `${CD_TABLE_ALIAS}.name`;
27
+ const CV_TABLE_ALIAS = 'cv';
28
+ const CV_VALUE_COLUMN = `(${CV_TABLE_ALIAS}.value)`;
29
+ const castValueToJsonb = (value) => `to_jsonb(${value}::text)`;
24
30
  /**
25
31
  * A Sequelize scope for filtering models by custom fields.
26
32
  * This scope builds a WHERE clause to be applied on the main query.
@@ -40,6 +46,7 @@ const customFieldsFilterScope = (name) => (conditions) => {
40
46
  .map(([key, condition]) => {
41
47
  const replacemetKey = (0, helpers_1.generateRandomString)();
42
48
  replacements[replacemetKey] = `${key}`;
49
+ const columnCondition = `(${CD_NAME_COLUMN} = :${replacemetKey})`;
43
50
  if (Array.isArray(condition)) {
44
51
  if (condition.length === 0) {
45
52
  // if empty array, the condition is ignored
@@ -49,26 +56,29 @@ const customFieldsFilterScope = (name) => (conditions) => {
49
56
  const values = condition.map((v) => {
50
57
  const valRandom = (0, helpers_1.generateRandomString)();
51
58
  replacements[`${valRandom}`] = `${v}`;
52
- return ` :${valRandom} `;
59
+ return castValueToJsonb(`:${valRandom}`);
53
60
  }).join(',');
54
- return `(custom_fields->> :${replacemetKey} ) IN ( ${values} )`;
61
+ return `(${columnCondition} AND ${CV_VALUE_COLUMN} IN ( ${values} ))`;
55
62
  }
56
63
  return condition
57
64
  .map((c) => {
58
65
  const valRep = (0, helpers_1.generateRandomString)();
59
66
  replacements[valRep] = `${c.value}`;
60
- return `(custom_fields->> :${replacemetKey} )${castIfNeeded(c.value)} ${c.operator} :${valRep}`;
67
+ const valueAsJsonb = castValueToJsonb(`:${valRep}`);
68
+ return `(${columnCondition} AND ${CV_VALUE_COLUMN}${castIfNeeded(c.value)} ${c.operator} ${valueAsJsonb})`;
61
69
  }).join(AND_DELIMETER);
62
70
  }
63
71
  if (typeof condition === 'string' || typeof condition === 'number') {
64
72
  const conditionRep = (0, helpers_1.generateRandomString)();
65
73
  replacements[conditionRep] = `${condition}`;
66
- return `(custom_fields->> :${replacemetKey} ) ${castIfNeeded(condition)} = :${conditionRep}`;
74
+ const valueAsJsonb = castValueToJsonb(`:${conditionRep}`);
75
+ return `(${columnCondition} AND ${CV_VALUE_COLUMN}${castIfNeeded(condition)} = ${valueAsJsonb})`;
67
76
  }
68
77
  if (condition?.operator) {
69
78
  const valueRep = (0, helpers_1.generateRandomString)();
70
79
  replacements[valueRep] = `${condition.value}`;
71
- return `(custom_fields->> :${replacemetKey} ) ${castIfNeeded(condition.value)} ${condition.operator} :${valueRep}`;
80
+ const valueAsJsonb = castValueToJsonb(`:${valueRep}`);
81
+ return `( ${columnCondition} AND ${CV_VALUE_COLUMN}${castIfNeeded(condition.value)} ${condition.operator} ${valueAsJsonb})`;
72
82
  }
73
83
  return false;
74
84
  })
@@ -76,14 +86,16 @@ const customFieldsFilterScope = (name) => (conditions) => {
76
86
  if (conditionsStrings.length === 0) {
77
87
  return {};
78
88
  }
79
- const customFieldConditions = conditionsStrings.join(AND_DELIMETER);
80
- const subQuery = `${'SELECT model_id FROM ('
81
- + 'SELECT cv.model_id, jsonb_object_agg(cd.name, cv.value) AS custom_fields '
82
- + 'FROM custom_field_values AS cv '
83
- + 'INNER JOIN custom_field_definitions AS cd ON cv.custom_field_definition_id = cd.id '
84
- + `AND cd.model_type = :${ConditionNameRandomStr} `
85
- + 'GROUP BY cv.model_id'
86
- + ') AS CustomFieldAggregation WHERE '} ${customFieldConditions}`;
89
+ const customFieldConditions = conditionsStrings.join(OR_DELIMETER);
90
+ const subQuery = `
91
+ SELECT cv.model_id
92
+ FROM custom_field_values AS cv
93
+ INNER JOIN custom_field_definitions AS cd ON cv.custom_field_definition_id = cd.id
94
+ AND cd.model_type = :${ConditionNameRandomStr}
95
+ WHERE ${customFieldConditions}
96
+ GROUP BY cv.model_id
97
+ HAVING COUNT(DISTINCT cv.custom_field_definition_id) = ${conditionsStrings.length}
98
+ `.replace(/\n/g, '');
87
99
  return {
88
100
  where: {
89
101
  id: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@autofleet/sadot",
3
- "version": "0.6.10",
3
+ "version": "0.6.11",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "scripts": {
@@ -59,6 +59,9 @@
59
59
  "typescript": "^5.3.3",
60
60
  "typescript-eslint": "^0.0.1-alpha.0"
61
61
  },
62
+ "engines": {
63
+ "node": ">=16.0.0"
64
+ },
62
65
  "author": "Autofleet",
63
66
  "license": "ISC"
64
67
  }
@@ -37,6 +37,13 @@ const castIfNeeded = (conditionValue: string): string => {
37
37
  return '';
38
38
  };
39
39
  const AND_DELIMETER = ' AND ';
40
+ const OR_DELIMETER = ' OR ';
41
+
42
+ const CD_TABLE_ALIAS = 'cd';
43
+ const CD_NAME_COLUMN = `${CD_TABLE_ALIAS}.name`;
44
+ const CV_TABLE_ALIAS = 'cv';
45
+ const CV_VALUE_COLUMN = `(${CV_TABLE_ALIAS}.value)`;
46
+ const castValueToJsonb = (value) => `to_jsonb(${value}::text)`;
40
47
 
41
48
  /**
42
49
  * A Sequelize scope for filtering models by custom fields.
@@ -61,6 +68,7 @@ export const customFieldsFilterScope = (
61
68
  ([key, condition]) => {
62
69
  const replacemetKey = generateRandomString();
63
70
  replacements[replacemetKey] = `${key}`;
71
+ const columnCondition = `(${CD_NAME_COLUMN} = :${replacemetKey})`;
64
72
  if (Array.isArray(condition)) {
65
73
  if (condition.length === 0) {
66
74
  // if empty array, the condition is ignored
@@ -70,26 +78,29 @@ export const customFieldsFilterScope = (
70
78
  const values = condition.map((v) => {
71
79
  const valRandom = generateRandomString();
72
80
  replacements[`${valRandom}`] = `${v}`;
73
- return ` :${valRandom} `;
81
+ return castValueToJsonb(`:${valRandom}`);
74
82
  }).join(',');
75
- return `(custom_fields->> :${replacemetKey} ) IN ( ${values} )`;
83
+ return `(${columnCondition} AND ${CV_VALUE_COLUMN} IN ( ${values} ))`;
76
84
  }
77
85
  return condition
78
86
  .map((c) => {
79
87
  const valRep = generateRandomString();
80
88
  replacements[valRep] = `${c.value}`;
81
- return `(custom_fields->> :${replacemetKey} )${castIfNeeded(c.value)} ${c.operator} :${valRep}`;
89
+ const valueAsJsonb = castValueToJsonb(`:${valRep}`);
90
+ return `(${columnCondition} AND ${CV_VALUE_COLUMN}${castIfNeeded(c.value)} ${c.operator} ${valueAsJsonb})`;
82
91
  }).join(AND_DELIMETER);
83
92
  }
84
93
  if (typeof condition === 'string' || typeof condition === 'number') {
85
94
  const conditionRep = generateRandomString();
86
95
  replacements[conditionRep] = `${condition}`;
87
- return `(custom_fields->> :${replacemetKey} ) ${castIfNeeded(condition)} = :${conditionRep}`;
96
+ const valueAsJsonb = castValueToJsonb(`:${conditionRep}`);
97
+ return `(${columnCondition} AND ${CV_VALUE_COLUMN}${castIfNeeded(condition)} = ${valueAsJsonb})`;
88
98
  }
89
99
  if (condition?.operator) {
90
100
  const valueRep = generateRandomString();
91
101
  replacements[valueRep] = `${condition.value}`;
92
- return `(custom_fields->> :${replacemetKey} ) ${castIfNeeded(condition.value)} ${condition.operator} :${valueRep}`;
102
+ const valueAsJsonb = castValueToJsonb(`:${valueRep}`);
103
+ return `( ${columnCondition} AND ${CV_VALUE_COLUMN}${castIfNeeded(condition.value)} ${condition.operator} ${valueAsJsonb})`;
93
104
  }
94
105
 
95
106
  return false;
@@ -99,14 +110,16 @@ export const customFieldsFilterScope = (
99
110
  if (conditionsStrings.length === 0) {
100
111
  return {};
101
112
  }
102
- const customFieldConditions = conditionsStrings.join(AND_DELIMETER);
103
- const subQuery = `${'SELECT model_id FROM ('
104
- + 'SELECT cv.model_id, jsonb_object_agg(cd.name, cv.value) AS custom_fields '
105
- + 'FROM custom_field_values AS cv '
106
- + 'INNER JOIN custom_field_definitions AS cd ON cv.custom_field_definition_id = cd.id '
107
- + `AND cd.model_type = :${ConditionNameRandomStr} `
108
- + 'GROUP BY cv.model_id'
109
- + ') AS CustomFieldAggregation WHERE '} ${customFieldConditions}`;
113
+ const customFieldConditions = conditionsStrings.join(OR_DELIMETER);
114
+ const subQuery = `
115
+ SELECT cv.model_id
116
+ FROM custom_field_values AS cv
117
+ INNER JOIN custom_field_definitions AS cd ON cv.custom_field_definition_id = cd.id
118
+ AND cd.model_type = :${ConditionNameRandomStr}
119
+ WHERE ${customFieldConditions}
120
+ GROUP BY cv.model_id
121
+ HAVING COUNT(DISTINCT cv.custom_field_definition_id) = ${conditionsStrings.length}
122
+ `.replace(/\n/g, '');
110
123
  return {
111
124
  where: {
112
125
  id: {