@m5kdev/backend 0.8.8 → 0.8.10

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 (31) hide show
  1. package/dist/src/modules/auth/auth.dto.d.cts +6 -6
  2. package/dist/src/modules/auth/auth.dto.d.mts +6 -6
  3. package/dist/src/modules/auth/auth.lib.d.cts +4 -4
  4. package/dist/src/modules/auth/auth.lib.d.mts +4 -4
  5. package/dist/src/modules/auth/auth.trpc.d.cts +17 -17
  6. package/dist/src/modules/auth/auth.trpc.d.mts +17 -17
  7. package/dist/src/modules/base/base.repository.cjs +1 -1
  8. package/dist/src/modules/base/base.repository.mjs +1 -1
  9. package/dist/src/modules/billing/billing.repository.d.cts +11 -11
  10. package/dist/src/modules/billing/billing.service.d.cts +7 -7
  11. package/dist/src/modules/connect/connect.dto.d.cts +8 -8
  12. package/dist/src/modules/connect/connect.dto.d.mts +8 -8
  13. package/dist/src/modules/connect/connect.repository.d.cts +6 -6
  14. package/dist/src/modules/connect/connect.repository.d.mts +6 -6
  15. package/dist/src/modules/connect/connect.service.d.cts +12 -12
  16. package/dist/src/modules/connect/connect.service.d.mts +12 -12
  17. package/dist/src/modules/connect/connect.trpc.d.cts +4 -4
  18. package/dist/src/modules/connect/connect.trpc.d.mts +4 -4
  19. package/dist/src/modules/recurrence/recurrence.service.d.cts +4 -4
  20. package/dist/src/modules/recurrence/recurrence.service.d.mts +4 -4
  21. package/dist/src/modules/recurrence/recurrence.trpc.d.cts +2 -2
  22. package/dist/src/modules/recurrence/recurrence.trpc.d.mts +2 -2
  23. package/dist/src/modules/tag/tag.trpc.d.cts +4 -4
  24. package/dist/src/modules/tag/tag.trpc.d.mts +4 -4
  25. package/dist/src/modules/utils/getConditionsFromFilters.cjs +32 -0
  26. package/dist/src/modules/utils/getConditionsFromFilters.cjs.map +1 -1
  27. package/dist/src/modules/utils/getConditionsFromFilters.mjs +33 -1
  28. package/dist/src/modules/utils/getConditionsFromFilters.mjs.map +1 -1
  29. package/dist/src/types.d.cts +17 -17
  30. package/dist/src/types.d.mts +17 -17
  31. package/package.json +3 -3
@@ -394,24 +394,24 @@ declare class ConnectRepository extends BaseTableRepository<Orm, Schema, Record<
394
394
  }[]>>;
395
395
  upsert(data: ConnectInsert, tx?: Orm): Promise<ServerResult<{
396
396
  id: string;
397
- createdAt: Date;
398
- updatedAt: Date | null;
399
- expiresAt: Date | null;
400
397
  userId: string;
401
398
  provider: string;
402
- accessToken: string;
403
- refreshToken: string | null;
404
- scope: string | null;
405
399
  accountType: string;
406
400
  providerAccountId: string;
407
401
  handle: string | null;
408
402
  displayName: string | null;
409
403
  avatarUrl: string | null;
404
+ accessToken: string;
405
+ refreshToken: string | null;
410
406
  tokenType: string | null;
407
+ scope: string | null;
408
+ expiresAt: Date | null;
411
409
  parentId: string | null;
412
410
  metadataJson: unknown;
413
411
  revokedAt: Date | null;
414
412
  lastRefreshedAt: Date | null;
413
+ createdAt: Date;
414
+ updatedAt: Date | null;
415
415
  }>>;
416
416
  }
417
417
  //#endregion
@@ -20,45 +20,45 @@ declare class ConnectService extends BaseService<{
20
20
  }>;
21
21
  handleCallback(user: User, sessionId: string, providerId: string, code: string, state: string): Promise<ServerResult<{
22
22
  id: string;
23
- createdAt: Date;
24
- updatedAt: Date | null;
25
- expiresAt: Date | null;
26
23
  userId: string;
27
24
  provider: string;
28
- accessToken: string;
29
- refreshToken: string | null;
30
- scope: string | null;
31
25
  accountType: string;
32
26
  providerAccountId: string;
33
27
  handle: string | null;
34
28
  displayName: string | null;
35
29
  avatarUrl: string | null;
30
+ accessToken: string;
31
+ refreshToken: string | null;
36
32
  tokenType: string | null;
33
+ scope: string | null;
34
+ expiresAt: Date | null;
37
35
  parentId: string | null;
38
36
  metadataJson: unknown;
39
37
  revokedAt: Date | null;
40
38
  lastRefreshedAt: Date | null;
39
+ createdAt: Date;
40
+ updatedAt: Date | null;
41
41
  }>>;
42
42
  refreshToken(connectionId: string): Promise<ServerResult<{
43
43
  id: string;
44
- createdAt: Date;
45
- updatedAt: Date | null;
46
- expiresAt: Date | null;
47
44
  userId: string;
48
45
  provider: string;
49
- accessToken: string;
50
- refreshToken: string | null;
51
- scope: string | null;
52
46
  accountType: string;
53
47
  providerAccountId: string;
54
48
  handle: string | null;
55
49
  displayName: string | null;
56
50
  avatarUrl: string | null;
51
+ accessToken: string;
52
+ refreshToken: string | null;
57
53
  tokenType: string | null;
54
+ scope: string | null;
55
+ expiresAt: Date | null;
58
56
  parentId: string | null;
59
57
  metadataJson: unknown;
60
58
  revokedAt: Date | null;
61
59
  lastRefreshedAt: Date | null;
60
+ createdAt: Date;
61
+ updatedAt: Date | null;
62
62
  }>>;
63
63
  readonly list: ServiceProcedure<{
64
64
  providers?: string[] | undefined;
@@ -20,45 +20,45 @@ declare class ConnectService extends BaseService<{
20
20
  }>;
21
21
  handleCallback(user: User, sessionId: string, providerId: string, code: string, state: string): Promise<ServerResult<{
22
22
  id: string;
23
- createdAt: Date;
24
- updatedAt: Date | null;
25
- expiresAt: Date | null;
26
23
  userId: string;
27
24
  provider: string;
28
- accessToken: string;
29
- refreshToken: string | null;
30
- scope: string | null;
31
25
  accountType: string;
32
26
  providerAccountId: string;
33
27
  handle: string | null;
34
28
  displayName: string | null;
35
29
  avatarUrl: string | null;
30
+ accessToken: string;
31
+ refreshToken: string | null;
36
32
  tokenType: string | null;
33
+ scope: string | null;
34
+ expiresAt: Date | null;
37
35
  parentId: string | null;
38
36
  metadataJson: unknown;
39
37
  revokedAt: Date | null;
40
38
  lastRefreshedAt: Date | null;
39
+ createdAt: Date;
40
+ updatedAt: Date | null;
41
41
  }>>;
42
42
  refreshToken(connectionId: string): Promise<ServerResult<{
43
43
  id: string;
44
- createdAt: Date;
45
- updatedAt: Date | null;
46
- expiresAt: Date | null;
47
44
  userId: string;
48
45
  provider: string;
49
- accessToken: string;
50
- refreshToken: string | null;
51
- scope: string | null;
52
46
  accountType: string;
53
47
  providerAccountId: string;
54
48
  handle: string | null;
55
49
  displayName: string | null;
56
50
  avatarUrl: string | null;
51
+ accessToken: string;
52
+ refreshToken: string | null;
57
53
  tokenType: string | null;
54
+ scope: string | null;
55
+ expiresAt: Date | null;
58
56
  parentId: string | null;
59
57
  metadataJson: unknown;
60
58
  revokedAt: Date | null;
61
59
  lastRefreshedAt: Date | null;
60
+ createdAt: Date;
61
+ updatedAt: Date | null;
62
62
  }>>;
63
63
  readonly list: ServiceProcedure<{
64
64
  providers?: string[] | undefined;
@@ -19,22 +19,22 @@ declare function createConnectTRPC({
19
19
  };
20
20
  output: {
21
21
  id: string;
22
- createdAt: Date;
23
22
  userId: string;
24
23
  provider: string;
25
24
  accountType: string;
26
25
  providerAccountId: string;
27
- updatedAt?: Date | null | undefined;
28
- expiresAt?: Date | null | undefined;
29
- scope?: string | null | undefined;
26
+ createdAt: Date;
30
27
  handle?: string | null | undefined;
31
28
  displayName?: string | null | undefined;
32
29
  avatarUrl?: string | null | undefined;
33
30
  tokenType?: string | null | undefined;
31
+ scope?: string | null | undefined;
32
+ expiresAt?: Date | null | undefined;
34
33
  parentId?: string | null | undefined;
35
34
  metadataJson?: unknown;
36
35
  revokedAt?: Date | null | undefined;
37
36
  lastRefreshedAt?: Date | null | undefined;
37
+ updatedAt?: Date | null | undefined;
38
38
  }[];
39
39
  meta: any;
40
40
  }>;
@@ -19,22 +19,22 @@ declare function createConnectTRPC({
19
19
  };
20
20
  output: {
21
21
  id: string;
22
- createdAt: Date;
23
22
  userId: string;
24
23
  provider: string;
25
24
  accountType: string;
26
25
  providerAccountId: string;
27
- updatedAt?: Date | null | undefined;
28
- expiresAt?: Date | null | undefined;
29
- scope?: string | null | undefined;
26
+ createdAt: Date;
30
27
  handle?: string | null | undefined;
31
28
  displayName?: string | null | undefined;
32
29
  avatarUrl?: string | null | undefined;
33
30
  tokenType?: string | null | undefined;
31
+ scope?: string | null | undefined;
32
+ expiresAt?: Date | null | undefined;
34
33
  parentId?: string | null | undefined;
35
34
  metadataJson?: unknown;
36
35
  revokedAt?: Date | null | undefined;
37
36
  lastRefreshedAt?: Date | null | undefined;
37
+ updatedAt?: Date | null | undefined;
38
38
  }[];
39
39
  meta: any;
40
40
  }>;
@@ -17,8 +17,8 @@ declare class RecurrenceService extends BaseService<{
17
17
  order?: "asc" | "desc" | undefined;
18
18
  filters?: {
19
19
  columnId: string;
20
- type: "string" | "number" | "boolean" | "date" | "enum";
21
- method: "contains" | "starts_with" | "ends_with" | "intersect" | "on" | "equals" | "greater_than" | "less_than" | "between" | "before" | "after" | "oneOf" | "isEmpty" | "isNotEmpty" | "is_null" | "is_not_null";
20
+ type: "string" | "number" | "boolean" | "date" | "enum" | "jsonArray";
21
+ method: "intersect" | "contains" | "starts_with" | "ends_with" | "equals" | "greater_than" | "less_than" | "on" | "between" | "before" | "after" | "oneOf" | "isEmpty" | "isNotEmpty" | "is_null" | "is_not_null";
22
22
  value: string | number | boolean | string[];
23
23
  valueTo?: string | undefined;
24
24
  endColumnId?: string | undefined;
@@ -30,11 +30,11 @@ declare class RecurrenceService extends BaseService<{
30
30
  actor: UserActor;
31
31
  }, {
32
32
  rows: {
33
- name: string | null;
34
33
  id: string;
34
+ name: string | null;
35
+ userId: string | null;
35
36
  createdAt: Date;
36
37
  updatedAt: Date;
37
- userId: string | null;
38
38
  metadata: Record<string, any> | null;
39
39
  organizationId: string | null;
40
40
  teamId: string | null;
@@ -17,8 +17,8 @@ declare class RecurrenceService extends BaseService<{
17
17
  order?: "asc" | "desc" | undefined;
18
18
  filters?: {
19
19
  columnId: string;
20
- type: "string" | "number" | "boolean" | "date" | "enum";
21
- method: "contains" | "starts_with" | "ends_with" | "intersect" | "on" | "equals" | "greater_than" | "less_than" | "between" | "before" | "after" | "oneOf" | "isEmpty" | "isNotEmpty" | "is_null" | "is_not_null";
20
+ type: "string" | "number" | "boolean" | "date" | "enum" | "jsonArray";
21
+ method: "intersect" | "contains" | "starts_with" | "ends_with" | "equals" | "greater_than" | "less_than" | "on" | "between" | "before" | "after" | "oneOf" | "isEmpty" | "isNotEmpty" | "is_null" | "is_not_null";
22
22
  value: string | number | boolean | string[];
23
23
  valueTo?: string | undefined;
24
24
  endColumnId?: string | undefined;
@@ -30,11 +30,11 @@ declare class RecurrenceService extends BaseService<{
30
30
  actor: UserActor;
31
31
  }, {
32
32
  rows: {
33
- name: string | null;
34
33
  id: string;
34
+ name: string | null;
35
+ userId: string | null;
35
36
  createdAt: Date;
36
37
  updatedAt: Date;
37
- userId: string | null;
38
38
  metadata: Record<string, any> | null;
39
39
  organizationId: string | null;
40
40
  teamId: string | null;
@@ -20,8 +20,8 @@ declare function createRecurrenceTRPC({
20
20
  order?: "asc" | "desc" | undefined;
21
21
  filters?: {
22
22
  columnId: string;
23
- type: "string" | "number" | "boolean" | "date" | "enum";
24
- method: "contains" | "starts_with" | "ends_with" | "intersect" | "on" | "equals" | "greater_than" | "less_than" | "between" | "before" | "after" | "oneOf" | "isEmpty" | "isNotEmpty" | "is_null" | "is_not_null";
23
+ type: "string" | "number" | "boolean" | "date" | "enum" | "jsonArray";
24
+ method: "intersect" | "contains" | "starts_with" | "ends_with" | "equals" | "greater_than" | "less_than" | "on" | "between" | "before" | "after" | "oneOf" | "isEmpty" | "isNotEmpty" | "is_null" | "is_not_null";
25
25
  value: string | number | boolean | string[];
26
26
  valueTo?: string | undefined;
27
27
  endColumnId?: string | undefined;
@@ -20,8 +20,8 @@ declare function createRecurrenceTRPC({
20
20
  order?: "asc" | "desc" | undefined;
21
21
  filters?: {
22
22
  columnId: string;
23
- type: "string" | "number" | "boolean" | "date" | "enum";
24
- method: "contains" | "starts_with" | "ends_with" | "intersect" | "on" | "equals" | "greater_than" | "less_than" | "between" | "before" | "after" | "oneOf" | "isEmpty" | "isNotEmpty" | "is_null" | "is_not_null";
23
+ type: "string" | "number" | "boolean" | "date" | "enum" | "jsonArray";
24
+ method: "intersect" | "contains" | "starts_with" | "ends_with" | "equals" | "greater_than" | "less_than" | "on" | "between" | "before" | "after" | "oneOf" | "isEmpty" | "isNotEmpty" | "is_null" | "is_not_null";
25
25
  value: string | number | boolean | string[];
26
26
  valueTo?: string | undefined;
27
27
  endColumnId?: string | undefined;
@@ -20,8 +20,8 @@ declare function createTagTRPC({
20
20
  order?: "asc" | "desc" | undefined;
21
21
  filters?: {
22
22
  columnId: string;
23
- type: "string" | "number" | "boolean" | "date" | "enum";
24
- method: "contains" | "starts_with" | "ends_with" | "intersect" | "on" | "equals" | "greater_than" | "less_than" | "between" | "before" | "after" | "oneOf" | "isEmpty" | "isNotEmpty" | "is_null" | "is_not_null";
23
+ type: "string" | "number" | "boolean" | "date" | "enum" | "jsonArray";
24
+ method: "intersect" | "contains" | "starts_with" | "ends_with" | "equals" | "greater_than" | "less_than" | "on" | "between" | "before" | "after" | "oneOf" | "isEmpty" | "isNotEmpty" | "is_null" | "is_not_null";
25
25
  value: string | number | boolean | string[];
26
26
  valueTo?: string | undefined;
27
27
  endColumnId?: string | undefined;
@@ -54,8 +54,8 @@ declare function createTagTRPC({
54
54
  resourceType: string;
55
55
  resourceIds?: {
56
56
  columnId: string;
57
- type: "string" | "number" | "boolean" | "date" | "enum";
58
- method: "contains" | "starts_with" | "ends_with" | "intersect" | "on" | "equals" | "greater_than" | "less_than" | "between" | "before" | "after" | "oneOf" | "isEmpty" | "isNotEmpty" | "is_null" | "is_not_null";
57
+ type: "string" | "number" | "boolean" | "date" | "enum" | "jsonArray";
58
+ method: "intersect" | "contains" | "starts_with" | "ends_with" | "equals" | "greater_than" | "less_than" | "on" | "between" | "before" | "after" | "oneOf" | "isEmpty" | "isNotEmpty" | "is_null" | "is_not_null";
59
59
  value: string | number | boolean | string[];
60
60
  valueTo?: string | undefined;
61
61
  endColumnId?: string | undefined;
@@ -20,8 +20,8 @@ declare function createTagTRPC({
20
20
  order?: "asc" | "desc" | undefined;
21
21
  filters?: {
22
22
  columnId: string;
23
- type: "string" | "number" | "boolean" | "date" | "enum";
24
- method: "contains" | "starts_with" | "ends_with" | "intersect" | "on" | "equals" | "greater_than" | "less_than" | "between" | "before" | "after" | "oneOf" | "isEmpty" | "isNotEmpty" | "is_null" | "is_not_null";
23
+ type: "string" | "number" | "boolean" | "date" | "enum" | "jsonArray";
24
+ method: "intersect" | "contains" | "starts_with" | "ends_with" | "equals" | "greater_than" | "less_than" | "on" | "between" | "before" | "after" | "oneOf" | "isEmpty" | "isNotEmpty" | "is_null" | "is_not_null";
25
25
  value: string | number | boolean | string[];
26
26
  valueTo?: string | undefined;
27
27
  endColumnId?: string | undefined;
@@ -54,8 +54,8 @@ declare function createTagTRPC({
54
54
  resourceType: string;
55
55
  resourceIds?: {
56
56
  columnId: string;
57
- type: "string" | "number" | "boolean" | "date" | "enum";
58
- method: "contains" | "starts_with" | "ends_with" | "intersect" | "on" | "equals" | "greater_than" | "less_than" | "between" | "before" | "after" | "oneOf" | "isEmpty" | "isNotEmpty" | "is_null" | "is_not_null";
57
+ type: "string" | "number" | "boolean" | "date" | "enum" | "jsonArray";
58
+ method: "intersect" | "contains" | "starts_with" | "ends_with" | "equals" | "greater_than" | "less_than" | "on" | "between" | "before" | "after" | "oneOf" | "isEmpty" | "isNotEmpty" | "is_null" | "is_not_null";
59
59
  value: string | number | boolean | string[];
60
60
  valueTo?: string | undefined;
61
61
  endColumnId?: string | undefined;
@@ -1,8 +1,12 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  require("../../../_virtual/_rolldown/runtime.cjs");
3
+ const require_src_modules_utils_getGlobalSearchCondition = require("./getGlobalSearchCondition.cjs");
3
4
  let drizzle_orm = require("drizzle-orm");
4
5
  let luxon = require("luxon");
5
6
  //#region src/modules/utils/getConditionsFromFilters.ts
7
+ function getJsonArrayLikeCondition(column, value) {
8
+ return drizzle_orm.sql`${column} LIKE ${`%${require_src_modules_utils_getGlobalSearchCondition.escapeLikeUserInput(JSON.stringify(value))}%`} ESCAPE '\\'`;
9
+ }
6
10
  const getUTCDateBoundaries = (isoString) => {
7
11
  const dateTime = luxon.DateTime.fromISO(isoString, { zone: "utc" });
8
12
  return {
@@ -22,6 +26,10 @@ const getConditionsFromFilters = (conditions, filters, table) => {
22
26
  if (method === "isEmpty") conditions.push((0, drizzle_orm.or)((0, drizzle_orm.isNull)(column), (0, drizzle_orm.eq)(column, "")));
23
27
  else conditions.push((0, drizzle_orm.and)((0, drizzle_orm.isNotNull)(column), (0, drizzle_orm.ne)(column, "")));
24
28
  continue;
29
+ case "jsonArray":
30
+ if (method === "isEmpty") conditions.push((0, drizzle_orm.or)((0, drizzle_orm.isNull)(column), (0, drizzle_orm.eq)(column, ""), (0, drizzle_orm.eq)(column, "[]")));
31
+ else conditions.push((0, drizzle_orm.and)((0, drizzle_orm.isNotNull)(column), (0, drizzle_orm.ne)(column, ""), (0, drizzle_orm.ne)(column, "[]")));
32
+ continue;
25
33
  case "number":
26
34
  if (method === "isEmpty") conditions.push((0, drizzle_orm.or)((0, drizzle_orm.isNull)(column), (0, drizzle_orm.eq)(column, 0)));
27
35
  else conditions.push((0, drizzle_orm.and)((0, drizzle_orm.isNotNull)(column), (0, drizzle_orm.ne)(column, 0)));
@@ -142,6 +150,30 @@ const getConditionsFromFilters = (conditions, filters, table) => {
142
150
  break;
143
151
  }
144
152
  break;
153
+ case "jsonArray":
154
+ switch (method) {
155
+ case "oneOf":
156
+ if (Array.isArray(value) && value.length > 0) {
157
+ const clauses = value.filter((v) => typeof v === "string" && v.length > 0).map((v) => getJsonArrayLikeCondition(column, v));
158
+ if (clauses.length === 1) conditions.push(clauses[0]);
159
+ else if (clauses.length > 1) conditions.push((0, drizzle_orm.or)(...clauses));
160
+ }
161
+ break;
162
+ case "equals":
163
+ if (Array.isArray(value) && value.length > 0) {
164
+ const clauses = value.filter((v) => typeof v === "string" && v.length > 0).map((v) => getJsonArrayLikeCondition(column, v));
165
+ if (clauses.length === 1) conditions.push(clauses[0]);
166
+ else if (clauses.length > 1) conditions.push((0, drizzle_orm.and)(...clauses));
167
+ }
168
+ break;
169
+ case "is_null":
170
+ conditions.push((0, drizzle_orm.isNull)(column));
171
+ break;
172
+ case "is_not_null":
173
+ conditions.push((0, drizzle_orm.isNotNull)(column));
174
+ break;
175
+ }
176
+ break;
145
177
  }
146
178
  }
147
179
  return conditions;
@@ -1 +1 @@
1
- {"version":3,"file":"getConditionsFromFilters.cjs","names":["DateTime"],"sources":["../../../../src/modules/utils/getConditionsFromFilters.ts"],"sourcesContent":["import type { QueryFilters } from \"@m5kdev/commons/modules/schemas/query.schema\";\r\nimport { and, between, eq, gte, inArray, isNotNull, isNull, like, lte, ne, or } from \"drizzle-orm\";\r\nimport type { SQLiteTableWithColumns } from \"drizzle-orm/sqlite-core\";\r\nimport { DateTime } from \"luxon\";\r\nimport type { ConditionBuilder } from \"../base/base.repository\";\r\n\r\ntype ColumnDataType = \"string\" | \"number\" | \"date\" | \"boolean\" | \"enum\";\r\n\r\n// Helper: Create UTC date boundaries from ISO string\r\nconst getUTCDateBoundaries = (isoString: string) => {\r\n const dateTime = DateTime.fromISO(isoString, { zone: \"utc\" });\r\n return {\r\n start: dateTime.startOf(\"day\").toJSDate(),\r\n end: dateTime.endOf(\"day\").toJSDate(),\r\n };\r\n};\r\n\r\nexport const getConditionsFromFilters = <T extends SQLiteTableWithColumns<any>>(\r\n conditions: ConditionBuilder,\r\n filters: QueryFilters | undefined,\r\n table: T\r\n): ConditionBuilder => {\r\n if (!filters || filters.length === 0) {\r\n return conditions;\r\n }\r\n\r\n // Process each filter (maximum one filter per column)\r\n for (const filter of filters) {\r\n const { columnId, type, method, value, valueTo } = filter;\r\n\r\n // Get the column from the table using columnId\r\n const column = (table as any)[columnId];\r\n if (!column) {\r\n continue; // Skip if column doesn't exist\r\n }\r\n\r\n // Handle isEmpty/isNotEmpty methods (work across types, ignore value)\r\n if (method === \"isEmpty\" || method === \"isNotEmpty\") {\r\n switch (type as ColumnDataType) {\r\n case \"string\":\r\n case \"enum\":\r\n // isEmpty: IS NULL OR = ''\r\n // isNotEmpty: IS NOT NULL AND != ''\r\n if (method === \"isEmpty\") {\r\n conditions.push(or(isNull(column), eq(column, \"\")));\r\n } else {\r\n conditions.push(and(isNotNull(column), ne(column, \"\")));\r\n }\r\n continue;\r\n case \"number\":\r\n // isEmpty: IS NULL OR = 0\r\n // isNotEmpty: IS NOT NULL AND != 0\r\n if (method === \"isEmpty\") {\r\n conditions.push(or(isNull(column), eq(column, 0)));\r\n } else {\r\n conditions.push(and(isNotNull(column), ne(column, 0)));\r\n }\r\n continue;\r\n case \"boolean\":\r\n // Should not happen per plan, but handle gracefully\r\n continue;\r\n default:\r\n continue;\r\n }\r\n }\r\n\r\n // Apply filter based on type and method\r\n switch (type as ColumnDataType) {\r\n case \"string\":\r\n switch (method) {\r\n case \"contains\":\r\n if (typeof value === \"string\") {\r\n conditions.push(like(column, `%${value}%`));\r\n }\r\n break;\r\n case \"equals\":\r\n if (typeof value === \"string\") {\r\n conditions.push(eq(column, value));\r\n }\r\n break;\r\n case \"starts_with\":\r\n if (typeof value === \"string\") {\r\n conditions.push(like(column, `${value}%`));\r\n }\r\n break;\r\n case \"ends_with\":\r\n if (typeof value === \"string\") {\r\n conditions.push(like(column, `%${value}`));\r\n }\r\n break;\r\n case \"is_null\":\r\n conditions.push(isNull(column));\r\n break;\r\n case \"is_not_null\":\r\n conditions.push(isNotNull(column));\r\n break;\r\n }\r\n break;\r\n\r\n case \"number\":\r\n switch (method) {\r\n case \"equals\":\r\n if (typeof value === \"number\") {\r\n conditions.push(eq(column, value));\r\n }\r\n break;\r\n case \"greater_than\":\r\n if (typeof value === \"number\") {\r\n conditions.push(gte(column, value));\r\n }\r\n break;\r\n case \"less_than\":\r\n if (typeof value === \"number\") {\r\n conditions.push(lte(column, value));\r\n }\r\n break;\r\n case \"is_null\":\r\n conditions.push(isNull(column));\r\n break;\r\n case \"is_not_null\":\r\n conditions.push(isNotNull(column));\r\n break;\r\n }\r\n break;\r\n\r\n case \"date\":\r\n if (typeof value !== \"string\") break;\r\n\r\n switch (method) {\r\n case \"on\": {\r\n const { start, end } = getUTCDateBoundaries(value);\r\n conditions.push(and(gte(column, start), lte(column, end)));\r\n break;\r\n }\r\n case \"between\":\r\n if (valueTo) {\r\n const { start } = getUTCDateBoundaries(value);\r\n const { end } = getUTCDateBoundaries(valueTo);\r\n conditions.push(between(column, start, end));\r\n }\r\n break;\r\n case \"before\": {\r\n const { end } = getUTCDateBoundaries(value);\r\n conditions.push(lte(column, end));\r\n break;\r\n }\r\n case \"after\": {\r\n const { start } = getUTCDateBoundaries(value);\r\n conditions.push(gte(column, start));\r\n break;\r\n }\r\n case \"intersect\": {\r\n // Interval overlap: [columnId, endColumnId] intersects with [value, valueTo]\r\n // Logic: columnId <= valueTo AND (endColumnId IS NULL OR endColumnId >= value)\r\n if (!valueTo || !filter.endColumnId) break;\r\n\r\n const endColumn = (table as any)[filter.endColumnId];\r\n if (!endColumn) break;\r\n\r\n const { start } = getUTCDateBoundaries(value);\r\n const { end } = getUTCDateBoundaries(valueTo);\r\n\r\n conditions.push(and(lte(column, end), or(isNull(endColumn), gte(endColumn, start))));\r\n break;\r\n }\r\n case \"is_null\":\r\n conditions.push(isNull(column));\r\n break;\r\n case \"is_not_null\":\r\n conditions.push(isNotNull(column));\r\n break;\r\n }\r\n break;\r\n\r\n case \"boolean\":\r\n switch (method) {\r\n case \"equals\":\r\n if (typeof value === \"boolean\") {\r\n conditions.push(eq(column, value));\r\n }\r\n break;\r\n case \"is_null\":\r\n conditions.push(isNull(column));\r\n break;\r\n case \"is_not_null\":\r\n conditions.push(isNotNull(column));\r\n break;\r\n }\r\n\r\n break;\r\n\r\n case \"enum\":\r\n switch (method) {\r\n case \"oneOf\":\r\n if (Array.isArray(value) && value.length > 0) {\r\n conditions.push(inArray(column, value));\r\n }\r\n break;\r\n case \"equals\":\r\n if (typeof value === \"string\") {\r\n conditions.push(eq(column, value));\r\n }\r\n break;\r\n case \"is_null\":\r\n conditions.push(isNull(column));\r\n break;\r\n case \"is_not_null\":\r\n conditions.push(isNotNull(column));\r\n break;\r\n }\r\n break;\r\n }\r\n }\r\n\r\n return conditions;\r\n};\r\n"],"mappings":"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"}
1
+ {"version":3,"file":"getConditionsFromFilters.cjs","names":["escapeLikeUserInput","DateTime"],"sources":["../../../../src/modules/utils/getConditionsFromFilters.ts"],"sourcesContent":["import type { QueryFilters } from \"@m5kdev/commons/modules/schemas/query.schema\";\r\nimport {\r\n and,\r\n between,\r\n eq,\r\n gte,\r\n inArray,\r\n isNotNull,\r\n isNull,\r\n like,\r\n lte,\r\n ne,\r\n or,\r\n sql,\r\n} from \"drizzle-orm\";\r\nimport type { SQLiteColumn, SQLiteTableWithColumns } from \"drizzle-orm/sqlite-core\";\r\nimport { DateTime } from \"luxon\";\r\nimport type { ConditionBuilder } from \"../base/base.repository\";\r\nimport { escapeLikeUserInput } from \"./getGlobalSearchCondition\";\r\n\r\ntype ColumnDataType = \"string\" | \"number\" | \"date\" | \"boolean\" | \"enum\" | \"jsonArray\";\r\n\r\nfunction getJsonArrayLikeCondition(\r\n column: SQLiteColumn,\r\n value: string\r\n): ReturnType<typeof sql> {\r\n // We store JSON arrays as TEXT (e.g. [\"a\",\"b\"]). To avoid partial token matches,\r\n // search for the JSON-stringified element, including quotes/escapes.\r\n const needle = JSON.stringify(value);\r\n const pattern = `%${escapeLikeUserInput(needle)}%`;\r\n return sql`${column} LIKE ${pattern} ESCAPE '\\\\'`;\r\n}\r\n\r\n// Helper: Create UTC date boundaries from ISO string\r\nconst getUTCDateBoundaries = (isoString: string) => {\r\n const dateTime = DateTime.fromISO(isoString, { zone: \"utc\" });\r\n return {\r\n start: dateTime.startOf(\"day\").toJSDate(),\r\n end: dateTime.endOf(\"day\").toJSDate(),\r\n };\r\n};\r\n\r\n// biome-ignore lint/suspicious/noExplicitAny: Drizzle TableConfig is complex; we access columns dynamically by `columnId`.\r\nexport const getConditionsFromFilters = <T extends SQLiteTableWithColumns<any>>(\r\n conditions: ConditionBuilder,\r\n filters: QueryFilters | undefined,\r\n table: T\r\n): ConditionBuilder => {\r\n if (!filters || filters.length === 0) {\r\n return conditions;\r\n }\r\n\r\n // Process each filter (maximum one filter per column)\r\n for (const filter of filters) {\r\n const { columnId, type, method, value, valueTo } = filter;\r\n\r\n // Get the column from the table using columnId\r\n const column = (table as unknown as Record<string, SQLiteColumn>)[columnId];\r\n if (!column) {\r\n continue; // Skip if column doesn't exist\r\n }\r\n\r\n // Handle isEmpty/isNotEmpty methods (work across types, ignore value)\r\n if (method === \"isEmpty\" || method === \"isNotEmpty\") {\r\n switch (type as ColumnDataType) {\r\n case \"string\":\r\n case \"enum\":\r\n // isEmpty: IS NULL OR = ''\r\n // isNotEmpty: IS NOT NULL AND != ''\r\n if (method === \"isEmpty\") {\r\n conditions.push(or(isNull(column), eq(column, \"\")));\r\n } else {\r\n conditions.push(and(isNotNull(column), ne(column, \"\")));\r\n }\r\n continue;\r\n case \"jsonArray\":\r\n // isEmpty: IS NULL OR = '' OR = '[]'\r\n // isNotEmpty: IS NOT NULL AND != '' AND != '[]'\r\n if (method === \"isEmpty\") {\r\n conditions.push(or(isNull(column), eq(column, \"\"), eq(column, \"[]\")));\r\n } else {\r\n conditions.push(and(isNotNull(column), ne(column, \"\"), ne(column, \"[]\")));\r\n }\r\n continue;\r\n case \"number\":\r\n // isEmpty: IS NULL OR = 0\r\n // isNotEmpty: IS NOT NULL AND != 0\r\n if (method === \"isEmpty\") {\r\n conditions.push(or(isNull(column), eq(column, 0)));\r\n } else {\r\n conditions.push(and(isNotNull(column), ne(column, 0)));\r\n }\r\n continue;\r\n case \"boolean\":\r\n // Should not happen per plan, but handle gracefully\r\n continue;\r\n default:\r\n continue;\r\n }\r\n }\r\n\r\n // Apply filter based on type and method\r\n switch (type as ColumnDataType) {\r\n case \"string\":\r\n switch (method) {\r\n case \"contains\":\r\n if (typeof value === \"string\") {\r\n conditions.push(like(column, `%${value}%`));\r\n }\r\n break;\r\n case \"equals\":\r\n if (typeof value === \"string\") {\r\n conditions.push(eq(column, value));\r\n }\r\n break;\r\n case \"starts_with\":\r\n if (typeof value === \"string\") {\r\n conditions.push(like(column, `${value}%`));\r\n }\r\n break;\r\n case \"ends_with\":\r\n if (typeof value === \"string\") {\r\n conditions.push(like(column, `%${value}`));\r\n }\r\n break;\r\n case \"is_null\":\r\n conditions.push(isNull(column));\r\n break;\r\n case \"is_not_null\":\r\n conditions.push(isNotNull(column));\r\n break;\r\n }\r\n break;\r\n\r\n case \"number\":\r\n switch (method) {\r\n case \"equals\":\r\n if (typeof value === \"number\") {\r\n conditions.push(eq(column, value));\r\n }\r\n break;\r\n case \"greater_than\":\r\n if (typeof value === \"number\") {\r\n conditions.push(gte(column, value));\r\n }\r\n break;\r\n case \"less_than\":\r\n if (typeof value === \"number\") {\r\n conditions.push(lte(column, value));\r\n }\r\n break;\r\n case \"is_null\":\r\n conditions.push(isNull(column));\r\n break;\r\n case \"is_not_null\":\r\n conditions.push(isNotNull(column));\r\n break;\r\n }\r\n break;\r\n\r\n case \"date\":\r\n if (typeof value !== \"string\") break;\r\n\r\n switch (method) {\r\n case \"on\": {\r\n const { start, end } = getUTCDateBoundaries(value);\r\n conditions.push(and(gte(column, start), lte(column, end)));\r\n break;\r\n }\r\n case \"between\":\r\n if (valueTo) {\r\n const { start } = getUTCDateBoundaries(value);\r\n const { end } = getUTCDateBoundaries(valueTo);\r\n conditions.push(between(column, start, end));\r\n }\r\n break;\r\n case \"before\": {\r\n const { end } = getUTCDateBoundaries(value);\r\n conditions.push(lte(column, end));\r\n break;\r\n }\r\n case \"after\": {\r\n const { start } = getUTCDateBoundaries(value);\r\n conditions.push(gte(column, start));\r\n break;\r\n }\r\n case \"intersect\": {\r\n // Interval overlap: [columnId, endColumnId] intersects with [value, valueTo]\r\n // Logic: columnId <= valueTo AND (endColumnId IS NULL OR endColumnId >= value)\r\n if (!valueTo || !filter.endColumnId) break;\r\n\r\n const endColumn = (table as unknown as Record<string, SQLiteColumn>)[filter.endColumnId];\r\n if (!endColumn) break;\r\n\r\n const { start } = getUTCDateBoundaries(value);\r\n const { end } = getUTCDateBoundaries(valueTo);\r\n\r\n conditions.push(and(lte(column, end), or(isNull(endColumn), gte(endColumn, start))));\r\n break;\r\n }\r\n case \"is_null\":\r\n conditions.push(isNull(column));\r\n break;\r\n case \"is_not_null\":\r\n conditions.push(isNotNull(column));\r\n break;\r\n }\r\n break;\r\n\r\n case \"boolean\":\r\n switch (method) {\r\n case \"equals\":\r\n if (typeof value === \"boolean\") {\r\n conditions.push(eq(column, value));\r\n }\r\n break;\r\n case \"is_null\":\r\n conditions.push(isNull(column));\r\n break;\r\n case \"is_not_null\":\r\n conditions.push(isNotNull(column));\r\n break;\r\n }\r\n\r\n break;\r\n\r\n case \"enum\":\r\n switch (method) {\r\n case \"oneOf\":\r\n if (Array.isArray(value) && value.length > 0) {\r\n conditions.push(inArray(column, value));\r\n }\r\n break;\r\n case \"equals\":\r\n if (typeof value === \"string\") {\r\n conditions.push(eq(column, value));\r\n }\r\n break;\r\n case \"is_null\":\r\n conditions.push(isNull(column));\r\n break;\r\n case \"is_not_null\":\r\n conditions.push(isNotNull(column));\r\n break;\r\n }\r\n break;\r\n\r\n case \"jsonArray\":\r\n switch (method) {\r\n case \"oneOf\": {\r\n if (Array.isArray(value) && value.length > 0) {\r\n const clauses = value\r\n .filter((v): v is string => typeof v === \"string\" && v.length > 0)\r\n .map((v) => getJsonArrayLikeCondition(column, v));\r\n\r\n if (clauses.length === 1) {\r\n conditions.push(clauses[0]);\r\n } else if (clauses.length > 1) {\r\n conditions.push(or(...clauses));\r\n }\r\n }\r\n break;\r\n }\r\n case \"equals\": {\r\n if (Array.isArray(value) && value.length > 0) {\r\n const clauses = value\r\n .filter((v): v is string => typeof v === \"string\" && v.length > 0)\r\n .map((v) => getJsonArrayLikeCondition(column, v));\r\n\r\n if (clauses.length === 1) {\r\n conditions.push(clauses[0]);\r\n } else if (clauses.length > 1) {\r\n conditions.push(and(...clauses));\r\n }\r\n }\r\n break;\r\n }\r\n case \"is_null\":\r\n conditions.push(isNull(column));\r\n break;\r\n case \"is_not_null\":\r\n conditions.push(isNotNull(column));\r\n break;\r\n }\r\n break;\r\n }\r\n }\r\n\r\n return conditions;\r\n};\r\n"],"mappings":"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"}
@@ -1,6 +1,10 @@
1
- import { and, between, eq, gte, inArray, isNotNull, isNull, like, lte, ne, or } from "drizzle-orm";
1
+ import { escapeLikeUserInput } from "./getGlobalSearchCondition.mjs";
2
+ import { and, between, eq, gte, inArray, isNotNull, isNull, like, lte, ne, or, sql } from "drizzle-orm";
2
3
  import { DateTime } from "luxon";
3
4
  //#region src/modules/utils/getConditionsFromFilters.ts
5
+ function getJsonArrayLikeCondition(column, value) {
6
+ return sql`${column} LIKE ${`%${escapeLikeUserInput(JSON.stringify(value))}%`} ESCAPE '\\'`;
7
+ }
4
8
  const getUTCDateBoundaries = (isoString) => {
5
9
  const dateTime = DateTime.fromISO(isoString, { zone: "utc" });
6
10
  return {
@@ -20,6 +24,10 @@ const getConditionsFromFilters = (conditions, filters, table) => {
20
24
  if (method === "isEmpty") conditions.push(or(isNull(column), eq(column, "")));
21
25
  else conditions.push(and(isNotNull(column), ne(column, "")));
22
26
  continue;
27
+ case "jsonArray":
28
+ if (method === "isEmpty") conditions.push(or(isNull(column), eq(column, ""), eq(column, "[]")));
29
+ else conditions.push(and(isNotNull(column), ne(column, ""), ne(column, "[]")));
30
+ continue;
23
31
  case "number":
24
32
  if (method === "isEmpty") conditions.push(or(isNull(column), eq(column, 0)));
25
33
  else conditions.push(and(isNotNull(column), ne(column, 0)));
@@ -140,6 +148,30 @@ const getConditionsFromFilters = (conditions, filters, table) => {
140
148
  break;
141
149
  }
142
150
  break;
151
+ case "jsonArray":
152
+ switch (method) {
153
+ case "oneOf":
154
+ if (Array.isArray(value) && value.length > 0) {
155
+ const clauses = value.filter((v) => typeof v === "string" && v.length > 0).map((v) => getJsonArrayLikeCondition(column, v));
156
+ if (clauses.length === 1) conditions.push(clauses[0]);
157
+ else if (clauses.length > 1) conditions.push(or(...clauses));
158
+ }
159
+ break;
160
+ case "equals":
161
+ if (Array.isArray(value) && value.length > 0) {
162
+ const clauses = value.filter((v) => typeof v === "string" && v.length > 0).map((v) => getJsonArrayLikeCondition(column, v));
163
+ if (clauses.length === 1) conditions.push(clauses[0]);
164
+ else if (clauses.length > 1) conditions.push(and(...clauses));
165
+ }
166
+ break;
167
+ case "is_null":
168
+ conditions.push(isNull(column));
169
+ break;
170
+ case "is_not_null":
171
+ conditions.push(isNotNull(column));
172
+ break;
173
+ }
174
+ break;
143
175
  }
144
176
  }
145
177
  return conditions;
@@ -1 +1 @@
1
- {"version":3,"file":"getConditionsFromFilters.mjs","names":[],"sources":["../../../../src/modules/utils/getConditionsFromFilters.ts"],"sourcesContent":["import type { QueryFilters } from \"@m5kdev/commons/modules/schemas/query.schema\";\r\nimport { and, between, eq, gte, inArray, isNotNull, isNull, like, lte, ne, or } from \"drizzle-orm\";\r\nimport type { SQLiteTableWithColumns } from \"drizzle-orm/sqlite-core\";\r\nimport { DateTime } from \"luxon\";\r\nimport type { ConditionBuilder } from \"../base/base.repository\";\r\n\r\ntype ColumnDataType = \"string\" | \"number\" | \"date\" | \"boolean\" | \"enum\";\r\n\r\n// Helper: Create UTC date boundaries from ISO string\r\nconst getUTCDateBoundaries = (isoString: string) => {\r\n const dateTime = DateTime.fromISO(isoString, { zone: \"utc\" });\r\n return {\r\n start: dateTime.startOf(\"day\").toJSDate(),\r\n end: dateTime.endOf(\"day\").toJSDate(),\r\n };\r\n};\r\n\r\nexport const getConditionsFromFilters = <T extends SQLiteTableWithColumns<any>>(\r\n conditions: ConditionBuilder,\r\n filters: QueryFilters | undefined,\r\n table: T\r\n): ConditionBuilder => {\r\n if (!filters || filters.length === 0) {\r\n return conditions;\r\n }\r\n\r\n // Process each filter (maximum one filter per column)\r\n for (const filter of filters) {\r\n const { columnId, type, method, value, valueTo } = filter;\r\n\r\n // Get the column from the table using columnId\r\n const column = (table as any)[columnId];\r\n if (!column) {\r\n continue; // Skip if column doesn't exist\r\n }\r\n\r\n // Handle isEmpty/isNotEmpty methods (work across types, ignore value)\r\n if (method === \"isEmpty\" || method === \"isNotEmpty\") {\r\n switch (type as ColumnDataType) {\r\n case \"string\":\r\n case \"enum\":\r\n // isEmpty: IS NULL OR = ''\r\n // isNotEmpty: IS NOT NULL AND != ''\r\n if (method === \"isEmpty\") {\r\n conditions.push(or(isNull(column), eq(column, \"\")));\r\n } else {\r\n conditions.push(and(isNotNull(column), ne(column, \"\")));\r\n }\r\n continue;\r\n case \"number\":\r\n // isEmpty: IS NULL OR = 0\r\n // isNotEmpty: IS NOT NULL AND != 0\r\n if (method === \"isEmpty\") {\r\n conditions.push(or(isNull(column), eq(column, 0)));\r\n } else {\r\n conditions.push(and(isNotNull(column), ne(column, 0)));\r\n }\r\n continue;\r\n case \"boolean\":\r\n // Should not happen per plan, but handle gracefully\r\n continue;\r\n default:\r\n continue;\r\n }\r\n }\r\n\r\n // Apply filter based on type and method\r\n switch (type as ColumnDataType) {\r\n case \"string\":\r\n switch (method) {\r\n case \"contains\":\r\n if (typeof value === \"string\") {\r\n conditions.push(like(column, `%${value}%`));\r\n }\r\n break;\r\n case \"equals\":\r\n if (typeof value === \"string\") {\r\n conditions.push(eq(column, value));\r\n }\r\n break;\r\n case \"starts_with\":\r\n if (typeof value === \"string\") {\r\n conditions.push(like(column, `${value}%`));\r\n }\r\n break;\r\n case \"ends_with\":\r\n if (typeof value === \"string\") {\r\n conditions.push(like(column, `%${value}`));\r\n }\r\n break;\r\n case \"is_null\":\r\n conditions.push(isNull(column));\r\n break;\r\n case \"is_not_null\":\r\n conditions.push(isNotNull(column));\r\n break;\r\n }\r\n break;\r\n\r\n case \"number\":\r\n switch (method) {\r\n case \"equals\":\r\n if (typeof value === \"number\") {\r\n conditions.push(eq(column, value));\r\n }\r\n break;\r\n case \"greater_than\":\r\n if (typeof value === \"number\") {\r\n conditions.push(gte(column, value));\r\n }\r\n break;\r\n case \"less_than\":\r\n if (typeof value === \"number\") {\r\n conditions.push(lte(column, value));\r\n }\r\n break;\r\n case \"is_null\":\r\n conditions.push(isNull(column));\r\n break;\r\n case \"is_not_null\":\r\n conditions.push(isNotNull(column));\r\n break;\r\n }\r\n break;\r\n\r\n case \"date\":\r\n if (typeof value !== \"string\") break;\r\n\r\n switch (method) {\r\n case \"on\": {\r\n const { start, end } = getUTCDateBoundaries(value);\r\n conditions.push(and(gte(column, start), lte(column, end)));\r\n break;\r\n }\r\n case \"between\":\r\n if (valueTo) {\r\n const { start } = getUTCDateBoundaries(value);\r\n const { end } = getUTCDateBoundaries(valueTo);\r\n conditions.push(between(column, start, end));\r\n }\r\n break;\r\n case \"before\": {\r\n const { end } = getUTCDateBoundaries(value);\r\n conditions.push(lte(column, end));\r\n break;\r\n }\r\n case \"after\": {\r\n const { start } = getUTCDateBoundaries(value);\r\n conditions.push(gte(column, start));\r\n break;\r\n }\r\n case \"intersect\": {\r\n // Interval overlap: [columnId, endColumnId] intersects with [value, valueTo]\r\n // Logic: columnId <= valueTo AND (endColumnId IS NULL OR endColumnId >= value)\r\n if (!valueTo || !filter.endColumnId) break;\r\n\r\n const endColumn = (table as any)[filter.endColumnId];\r\n if (!endColumn) break;\r\n\r\n const { start } = getUTCDateBoundaries(value);\r\n const { end } = getUTCDateBoundaries(valueTo);\r\n\r\n conditions.push(and(lte(column, end), or(isNull(endColumn), gte(endColumn, start))));\r\n break;\r\n }\r\n case \"is_null\":\r\n conditions.push(isNull(column));\r\n break;\r\n case \"is_not_null\":\r\n conditions.push(isNotNull(column));\r\n break;\r\n }\r\n break;\r\n\r\n case \"boolean\":\r\n switch (method) {\r\n case \"equals\":\r\n if (typeof value === \"boolean\") {\r\n conditions.push(eq(column, value));\r\n }\r\n break;\r\n case \"is_null\":\r\n conditions.push(isNull(column));\r\n break;\r\n case \"is_not_null\":\r\n conditions.push(isNotNull(column));\r\n break;\r\n }\r\n\r\n break;\r\n\r\n case \"enum\":\r\n switch (method) {\r\n case \"oneOf\":\r\n if (Array.isArray(value) && value.length > 0) {\r\n conditions.push(inArray(column, value));\r\n }\r\n break;\r\n case \"equals\":\r\n if (typeof value === \"string\") {\r\n conditions.push(eq(column, value));\r\n }\r\n break;\r\n case \"is_null\":\r\n conditions.push(isNull(column));\r\n break;\r\n case \"is_not_null\":\r\n conditions.push(isNotNull(column));\r\n break;\r\n }\r\n break;\r\n }\r\n }\r\n\r\n return conditions;\r\n};\r\n"],"mappings":"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"}
1
+ {"version":3,"file":"getConditionsFromFilters.mjs","names":[],"sources":["../../../../src/modules/utils/getConditionsFromFilters.ts"],"sourcesContent":["import type { QueryFilters } from \"@m5kdev/commons/modules/schemas/query.schema\";\r\nimport {\r\n and,\r\n between,\r\n eq,\r\n gte,\r\n inArray,\r\n isNotNull,\r\n isNull,\r\n like,\r\n lte,\r\n ne,\r\n or,\r\n sql,\r\n} from \"drizzle-orm\";\r\nimport type { SQLiteColumn, SQLiteTableWithColumns } from \"drizzle-orm/sqlite-core\";\r\nimport { DateTime } from \"luxon\";\r\nimport type { ConditionBuilder } from \"../base/base.repository\";\r\nimport { escapeLikeUserInput } from \"./getGlobalSearchCondition\";\r\n\r\ntype ColumnDataType = \"string\" | \"number\" | \"date\" | \"boolean\" | \"enum\" | \"jsonArray\";\r\n\r\nfunction getJsonArrayLikeCondition(\r\n column: SQLiteColumn,\r\n value: string\r\n): ReturnType<typeof sql> {\r\n // We store JSON arrays as TEXT (e.g. [\"a\",\"b\"]). To avoid partial token matches,\r\n // search for the JSON-stringified element, including quotes/escapes.\r\n const needle = JSON.stringify(value);\r\n const pattern = `%${escapeLikeUserInput(needle)}%`;\r\n return sql`${column} LIKE ${pattern} ESCAPE '\\\\'`;\r\n}\r\n\r\n// Helper: Create UTC date boundaries from ISO string\r\nconst getUTCDateBoundaries = (isoString: string) => {\r\n const dateTime = DateTime.fromISO(isoString, { zone: \"utc\" });\r\n return {\r\n start: dateTime.startOf(\"day\").toJSDate(),\r\n end: dateTime.endOf(\"day\").toJSDate(),\r\n };\r\n};\r\n\r\n// biome-ignore lint/suspicious/noExplicitAny: Drizzle TableConfig is complex; we access columns dynamically by `columnId`.\r\nexport const getConditionsFromFilters = <T extends SQLiteTableWithColumns<any>>(\r\n conditions: ConditionBuilder,\r\n filters: QueryFilters | undefined,\r\n table: T\r\n): ConditionBuilder => {\r\n if (!filters || filters.length === 0) {\r\n return conditions;\r\n }\r\n\r\n // Process each filter (maximum one filter per column)\r\n for (const filter of filters) {\r\n const { columnId, type, method, value, valueTo } = filter;\r\n\r\n // Get the column from the table using columnId\r\n const column = (table as unknown as Record<string, SQLiteColumn>)[columnId];\r\n if (!column) {\r\n continue; // Skip if column doesn't exist\r\n }\r\n\r\n // Handle isEmpty/isNotEmpty methods (work across types, ignore value)\r\n if (method === \"isEmpty\" || method === \"isNotEmpty\") {\r\n switch (type as ColumnDataType) {\r\n case \"string\":\r\n case \"enum\":\r\n // isEmpty: IS NULL OR = ''\r\n // isNotEmpty: IS NOT NULL AND != ''\r\n if (method === \"isEmpty\") {\r\n conditions.push(or(isNull(column), eq(column, \"\")));\r\n } else {\r\n conditions.push(and(isNotNull(column), ne(column, \"\")));\r\n }\r\n continue;\r\n case \"jsonArray\":\r\n // isEmpty: IS NULL OR = '' OR = '[]'\r\n // isNotEmpty: IS NOT NULL AND != '' AND != '[]'\r\n if (method === \"isEmpty\") {\r\n conditions.push(or(isNull(column), eq(column, \"\"), eq(column, \"[]\")));\r\n } else {\r\n conditions.push(and(isNotNull(column), ne(column, \"\"), ne(column, \"[]\")));\r\n }\r\n continue;\r\n case \"number\":\r\n // isEmpty: IS NULL OR = 0\r\n // isNotEmpty: IS NOT NULL AND != 0\r\n if (method === \"isEmpty\") {\r\n conditions.push(or(isNull(column), eq(column, 0)));\r\n } else {\r\n conditions.push(and(isNotNull(column), ne(column, 0)));\r\n }\r\n continue;\r\n case \"boolean\":\r\n // Should not happen per plan, but handle gracefully\r\n continue;\r\n default:\r\n continue;\r\n }\r\n }\r\n\r\n // Apply filter based on type and method\r\n switch (type as ColumnDataType) {\r\n case \"string\":\r\n switch (method) {\r\n case \"contains\":\r\n if (typeof value === \"string\") {\r\n conditions.push(like(column, `%${value}%`));\r\n }\r\n break;\r\n case \"equals\":\r\n if (typeof value === \"string\") {\r\n conditions.push(eq(column, value));\r\n }\r\n break;\r\n case \"starts_with\":\r\n if (typeof value === \"string\") {\r\n conditions.push(like(column, `${value}%`));\r\n }\r\n break;\r\n case \"ends_with\":\r\n if (typeof value === \"string\") {\r\n conditions.push(like(column, `%${value}`));\r\n }\r\n break;\r\n case \"is_null\":\r\n conditions.push(isNull(column));\r\n break;\r\n case \"is_not_null\":\r\n conditions.push(isNotNull(column));\r\n break;\r\n }\r\n break;\r\n\r\n case \"number\":\r\n switch (method) {\r\n case \"equals\":\r\n if (typeof value === \"number\") {\r\n conditions.push(eq(column, value));\r\n }\r\n break;\r\n case \"greater_than\":\r\n if (typeof value === \"number\") {\r\n conditions.push(gte(column, value));\r\n }\r\n break;\r\n case \"less_than\":\r\n if (typeof value === \"number\") {\r\n conditions.push(lte(column, value));\r\n }\r\n break;\r\n case \"is_null\":\r\n conditions.push(isNull(column));\r\n break;\r\n case \"is_not_null\":\r\n conditions.push(isNotNull(column));\r\n break;\r\n }\r\n break;\r\n\r\n case \"date\":\r\n if (typeof value !== \"string\") break;\r\n\r\n switch (method) {\r\n case \"on\": {\r\n const { start, end } = getUTCDateBoundaries(value);\r\n conditions.push(and(gte(column, start), lte(column, end)));\r\n break;\r\n }\r\n case \"between\":\r\n if (valueTo) {\r\n const { start } = getUTCDateBoundaries(value);\r\n const { end } = getUTCDateBoundaries(valueTo);\r\n conditions.push(between(column, start, end));\r\n }\r\n break;\r\n case \"before\": {\r\n const { end } = getUTCDateBoundaries(value);\r\n conditions.push(lte(column, end));\r\n break;\r\n }\r\n case \"after\": {\r\n const { start } = getUTCDateBoundaries(value);\r\n conditions.push(gte(column, start));\r\n break;\r\n }\r\n case \"intersect\": {\r\n // Interval overlap: [columnId, endColumnId] intersects with [value, valueTo]\r\n // Logic: columnId <= valueTo AND (endColumnId IS NULL OR endColumnId >= value)\r\n if (!valueTo || !filter.endColumnId) break;\r\n\r\n const endColumn = (table as unknown as Record<string, SQLiteColumn>)[filter.endColumnId];\r\n if (!endColumn) break;\r\n\r\n const { start } = getUTCDateBoundaries(value);\r\n const { end } = getUTCDateBoundaries(valueTo);\r\n\r\n conditions.push(and(lte(column, end), or(isNull(endColumn), gte(endColumn, start))));\r\n break;\r\n }\r\n case \"is_null\":\r\n conditions.push(isNull(column));\r\n break;\r\n case \"is_not_null\":\r\n conditions.push(isNotNull(column));\r\n break;\r\n }\r\n break;\r\n\r\n case \"boolean\":\r\n switch (method) {\r\n case \"equals\":\r\n if (typeof value === \"boolean\") {\r\n conditions.push(eq(column, value));\r\n }\r\n break;\r\n case \"is_null\":\r\n conditions.push(isNull(column));\r\n break;\r\n case \"is_not_null\":\r\n conditions.push(isNotNull(column));\r\n break;\r\n }\r\n\r\n break;\r\n\r\n case \"enum\":\r\n switch (method) {\r\n case \"oneOf\":\r\n if (Array.isArray(value) && value.length > 0) {\r\n conditions.push(inArray(column, value));\r\n }\r\n break;\r\n case \"equals\":\r\n if (typeof value === \"string\") {\r\n conditions.push(eq(column, value));\r\n }\r\n break;\r\n case \"is_null\":\r\n conditions.push(isNull(column));\r\n break;\r\n case \"is_not_null\":\r\n conditions.push(isNotNull(column));\r\n break;\r\n }\r\n break;\r\n\r\n case \"jsonArray\":\r\n switch (method) {\r\n case \"oneOf\": {\r\n if (Array.isArray(value) && value.length > 0) {\r\n const clauses = value\r\n .filter((v): v is string => typeof v === \"string\" && v.length > 0)\r\n .map((v) => getJsonArrayLikeCondition(column, v));\r\n\r\n if (clauses.length === 1) {\r\n conditions.push(clauses[0]);\r\n } else if (clauses.length > 1) {\r\n conditions.push(or(...clauses));\r\n }\r\n }\r\n break;\r\n }\r\n case \"equals\": {\r\n if (Array.isArray(value) && value.length > 0) {\r\n const clauses = value\r\n .filter((v): v is string => typeof v === \"string\" && v.length > 0)\r\n .map((v) => getJsonArrayLikeCondition(column, v));\r\n\r\n if (clauses.length === 1) {\r\n conditions.push(clauses[0]);\r\n } else if (clauses.length > 1) {\r\n conditions.push(and(...clauses));\r\n }\r\n }\r\n break;\r\n }\r\n case \"is_null\":\r\n conditions.push(isNull(column));\r\n break;\r\n case \"is_not_null\":\r\n conditions.push(isNotNull(column));\r\n break;\r\n }\r\n break;\r\n }\r\n }\r\n\r\n return conditions;\r\n};\r\n"],"mappings":"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"}