@autofleet/sadot 0.6.4-beta.1 → 0.6.4

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.
@@ -4,7 +4,11 @@ import { WhereOptions } from 'sequelize';
4
4
  * Currently supporting strings and arrays of strings.
5
5
  * More types to be added (TBA).
6
6
  */
7
- export type ConditionValue = string | string[];
7
+ type ConditionWithOperator = {
8
+ operator: string;
9
+ value: string;
10
+ };
11
+ export type ConditionValue = ConditionWithOperator | ConditionWithOperator[] | string | string[];
8
12
  export type CustomFieldSort = {
9
13
  field: string;
10
14
  direction: 'ASC' | 'DESC';
@@ -26,7 +30,8 @@ export declare const customFieldsSortScope: (name: string) => (sort: CustomField
26
30
  order?: undefined;
27
31
  } | {
28
32
  attributes: {
29
- include: (string | import("sequelize/types/utils").Literal)[][];
33
+ include: import("sequelize/types/utils").Literal[];
30
34
  };
31
35
  order: import("sequelize/types/utils").Literal[];
32
36
  };
37
+ export {};
@@ -6,6 +6,13 @@ 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
8
  const { CUSTOM_FIELDS_FILTER_SCOPE } = common_types_1.customFields;
9
+ const castIfNeeded = (conditionValue) => {
10
+ if (!Number.isNaN(Date.parse(conditionValue))) {
11
+ return '::timestamp';
12
+ }
13
+ return '';
14
+ };
15
+ const AND_DELIMETER = ' AND ';
9
16
  /**
10
17
  * A Sequelize scope for filtering models by custom fields.
11
18
  * This scope builds a WHERE clause to be applied on the main query.
@@ -19,30 +26,39 @@ const customFieldsFilterScope = (name) => (conditions) => {
19
26
  }
20
27
  // Build the WHERE clause for custom field filtering
21
28
  const conditionsStrings = Object.entries(conditions)
22
- .map(([key, value]) => {
23
- if (Array.isArray(value)) {
24
- if (value.length === 0) {
29
+ .map(([key, condition]) => {
30
+ if (Array.isArray(condition)) {
31
+ if (condition.length === 0) {
25
32
  // if empty array, the condition is ignored
26
33
  return false;
27
34
  }
28
- const values = value.map((v) => `'${v}'`).join(',');
29
- return `custom_fields->>'${key}' IN (${values})`;
35
+ if (typeof condition[0] === 'string') {
36
+ const values = condition.map((v) => `'${v}'`).join(',');
37
+ return `(custom_fields->>'${key}') IN (${values})`;
38
+ }
39
+ return condition
40
+ .map((c) => `(custom_fields->>'${key}')${castIfNeeded(c.value)} ${c.operator} '${c.value}'`).join(AND_DELIMETER);
41
+ }
42
+ if (typeof condition === 'string') {
43
+ return `(custom_fields->>'${key}')${castIfNeeded(condition)} = '${condition}'`;
44
+ }
45
+ if (condition?.operator) {
46
+ return `(custom_fields->>'${key}')${castIfNeeded(condition.value)} ${condition.operator} '${condition.value}'`;
30
47
  }
31
- return `custom_fields->>'${key}' = '${value}'`;
48
+ return false;
32
49
  })
33
50
  .filter(Boolean);
34
51
  if (conditionsStrings.length === 0) {
35
52
  return {};
36
53
  }
37
- const customFieldConditions = conditionsStrings.join(' AND ');
54
+ const customFieldConditions = conditionsStrings.join(AND_DELIMETER);
38
55
  const subQuery = `${'SELECT model_id FROM ('
39
56
  + 'SELECT cv.model_id, jsonb_object_agg(cd.name, cv.value) AS custom_fields '
40
57
  + 'FROM custom_field_values AS cv '
41
58
  + 'INNER JOIN custom_field_definitions AS cd ON cv.custom_field_definition_id = cd.id '
42
59
  + `AND cd.model_type = '${name}' `
43
60
  + 'GROUP BY cv.model_id'
44
- + ') AS CustomFieldAggregation '
45
- + 'WHERE '}${customFieldConditions}`;
61
+ + ') AS CustomFieldAggregation WHERE '}${customFieldConditions}`;
46
62
  return {
47
63
  where: {
48
64
  id: {
@@ -57,24 +73,17 @@ const customFieldsSortScope = (name) => (sort) => {
57
73
  if (!sort || sort.length === 0) {
58
74
  return {};
59
75
  }
60
- const includes = Object.entries(sort).map(([key]) => ([
61
- sequelize_typescript_1.Sequelize.literal(`(
62
- SELECT custom_fields->>'${key}'
63
- FROM (
64
- SELECT
65
- cv.model_id,
66
- jsonb_object_agg(cd.name, cv.value) AS custom_fields
67
- FROM custom_field_values AS cv
68
- INNER JOIN custom_field_definitions AS cd
69
- ON cv.custom_field_definition_id = cd.id
70
- AND cd.model_type = '${name}'
71
- WHERE cv.model_id = "${name}"."id"
72
- GROUP BY cv.model_id
73
- ) AS CustomFieldAggregation
74
- )`),
75
- `customFields_${key}`,
76
- ]));
77
- const orders = Object.entries(sort).map(([key, value]) => sequelize_typescript_1.Sequelize.literal(`"customFields_${key}" ${value}`));
76
+ console.log('sort', sort);
77
+ console.log('name', name);
78
+ console.log('Object.entries(sort)', Object.entries(sort));
79
+ const includes = Object.entries(sort).map(([key]) => sequelize_typescript_1.Sequelize.literal(`(select CustomFieldAggregation.custom_fields->>'${key}'
80
+ from (SELECT cv.model_id, jsonb_object_agg(cd.name, cv.value) AS custom_fields
81
+ FROM custom_field_values AS cv
82
+ INNER JOIN custom_field_definitions AS cd
83
+ ON cv.custom_field_definition_id = cd.id AND cd.model_type = '${name}'
84
+ where cv.model_id = "${name}"."id"
85
+ GROUP BY cv.model_id) AS CustomFieldAggregation) as "customFields.${key}"`));
86
+ const orders = Object.entries(sort).map(([key, value]) => sequelize_typescript_1.Sequelize.literal(`"customFields.${key}" ${value}`));
78
87
  return {
79
88
  attributes: {
80
89
  include: includes,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@autofleet/sadot",
3
- "version": "0.6.4-beta.1",
3
+ "version": "0.6.4",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "scripts": {
@@ -10,7 +10,11 @@ const { CUSTOM_FIELDS_FILTER_SCOPE } = customFields;
10
10
  * Currently supporting strings and arrays of strings.
11
11
  * More types to be added (TBA).
12
12
  */
13
- export type ConditionValue = string | string[];
13
+ type ConditionWithOperator = {
14
+ operator: string;
15
+ value: string;
16
+ };
17
+ export type ConditionValue = ConditionWithOperator | ConditionWithOperator[] | string | string[];
14
18
 
15
19
  export type CustomFieldSort = {
16
20
  field: string;
@@ -21,6 +25,13 @@ export type CustomFieldFilterOptions = {
21
25
  where?: WhereOptions;
22
26
  }
23
27
 
28
+ const castIfNeeded = (conditionValue: string): string => {
29
+ if (!Number.isNaN(Date.parse(conditionValue))) {
30
+ return '::timestamp';
31
+ }
32
+ return '';
33
+ };
34
+ const AND_DELIMETER = ' AND ';
24
35
  /**
25
36
  * A Sequelize scope for filtering models by custom fields.
26
37
  * This scope builds a WHERE clause to be applied on the main query.
@@ -37,24 +48,33 @@ export const customFieldsFilterScope = (
37
48
  // Build the WHERE clause for custom field filtering
38
49
  const conditionsStrings = Object.entries(conditions)
39
50
  .map(
40
- ([key, value]) => {
41
- if (Array.isArray(value)) {
42
- if (value.length === 0) {
51
+ ([key, condition]) => {
52
+ if (Array.isArray(condition)) {
53
+ if (condition.length === 0) {
43
54
  // if empty array, the condition is ignored
44
55
  return false;
45
56
  }
46
- const values = value.map((v) => `'${v}'`).join(',');
47
- return `custom_fields->>'${key}' IN (${values})`;
57
+ if (typeof condition[0] === 'string') {
58
+ const values = condition.map((v) => `'${v}'`).join(',');
59
+ return `(custom_fields->>'${key}') IN (${values})`;
60
+ }
61
+ return condition
62
+ .map((c) => `(custom_fields->>'${key}')${castIfNeeded(c.value)} ${c.operator} '${c.value}'`).join(AND_DELIMETER);
48
63
  }
49
- return `custom_fields->>'${key}' = '${value}'`;
64
+ if (typeof condition === 'string') {
65
+ return `(custom_fields->>'${key}')${castIfNeeded(condition)} = '${condition}'`;
66
+ }
67
+ if (condition?.operator) {
68
+ return `(custom_fields->>'${key}')${castIfNeeded(condition.value)} ${condition.operator} '${condition.value}'`;
69
+ }
70
+ return false;
50
71
  },
51
72
  )
52
73
  .filter(Boolean);
53
-
54
74
  if (conditionsStrings.length === 0) {
55
75
  return {};
56
76
  }
57
- const customFieldConditions = conditionsStrings.join(' AND ');
77
+ const customFieldConditions = conditionsStrings.join(AND_DELIMETER);
58
78
 
59
79
  const subQuery = `${'SELECT model_id FROM ('
60
80
  + 'SELECT cv.model_id, jsonb_object_agg(cd.name, cv.value) AS custom_fields '
@@ -62,8 +82,7 @@ export const customFieldsFilterScope = (
62
82
  + 'INNER JOIN custom_field_definitions AS cd ON cv.custom_field_definition_id = cd.id '
63
83
  + `AND cd.model_type = '${name}' `
64
84
  + 'GROUP BY cv.model_id'
65
- + ') AS CustomFieldAggregation '
66
- + 'WHERE '}${customFieldConditions}`;
85
+ + ') AS CustomFieldAggregation WHERE '}${customFieldConditions}`;
67
86
 
68
87
  return {
69
88
  where: {
@@ -82,26 +101,20 @@ export const customFieldsSortScope = (
82
101
  if (!sort || sort.length === 0) {
83
102
  return {};
84
103
  }
104
+
105
+ console.log('sort', sort);
106
+ console.log('name', name);
107
+ console.log('Object.entries(sort)', Object.entries(sort));
85
108
  const includes = Object.entries(sort).map(([key]) =>
86
- ([
87
- Sequelize.literal(`(
88
- SELECT custom_fields->>'${key}'
89
- FROM (
90
- SELECT
91
- cv.model_id,
92
- jsonb_object_agg(cd.name, cv.value) AS custom_fields
93
- FROM custom_field_values AS cv
94
- INNER JOIN custom_field_definitions AS cd
95
- ON cv.custom_field_definition_id = cd.id
96
- AND cd.model_type = '${name}'
97
- WHERE cv.model_id = "${name}"."id"
98
- GROUP BY cv.model_id
99
- ) AS CustomFieldAggregation
100
- )`),
101
- `customFields_${key}`,
102
- ]));
109
+ Sequelize.literal(`(select CustomFieldAggregation.custom_fields->>'${key}'
110
+ from (SELECT cv.model_id, jsonb_object_agg(cd.name, cv.value) AS custom_fields
111
+ FROM custom_field_values AS cv
112
+ INNER JOIN custom_field_definitions AS cd
113
+ ON cv.custom_field_definition_id = cd.id AND cd.model_type = '${name}'
114
+ where cv.model_id = "${name}"."id"
115
+ GROUP BY cv.model_id) AS CustomFieldAggregation) as "customFields.${key}"`));
116
+ const orders = Object.entries(sort).map(([key, value]) => Sequelize.literal(`"customFields.${key}" ${value}`));
103
117
 
104
- const orders = Object.entries(sort).map(([key, value]) => Sequelize.literal(`"customFields_${key}" ${value}`));
105
118
  return {
106
119
  attributes: {
107
120
  include: includes,