@m5kdev/backend 0.8.9 → 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 +5 -5
  2. package/dist/src/modules/auth/auth.dto.d.mts +5 -5
  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 +12 -12
  6. package/dist/src/modules/auth/auth.trpc.d.mts +12 -12
  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 +10 -10
  12. package/dist/src/modules/connect/connect.dto.d.mts +10 -10
  13. package/dist/src/modules/connect/connect.repository.d.cts +7 -7
  14. package/dist/src/modules/connect/connect.repository.d.mts +7 -7
  15. package/dist/src/modules/connect/connect.service.d.cts +14 -14
  16. package/dist/src/modules/connect/connect.service.d.mts +14 -14
  17. package/dist/src/modules/connect/connect.trpc.d.cts +5 -5
  18. package/dist/src/modules/connect/connect.trpc.d.mts +5 -5
  19. package/dist/src/modules/recurrence/recurrence.service.d.cts +3 -3
  20. package/dist/src/modules/recurrence/recurrence.service.d.mts +3 -3
  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 +12 -12
  30. package/dist/src/types.d.mts +12 -12
  31. package/package.json +3 -3
@@ -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
- accessToken: string;
28
- refreshToken: string | null;
29
- scope: string | null;
30
24
  provider: string;
31
- parentId: string | null;
32
25
  accountType: string;
33
26
  providerAccountId: string;
34
27
  handle: string | null;
35
28
  displayName: string | null;
36
29
  avatarUrl: string | null;
30
+ accessToken: string;
31
+ refreshToken: string | null;
37
32
  tokenType: string | null;
33
+ scope: string | null;
34
+ expiresAt: Date | null;
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
- accessToken: string;
49
- refreshToken: string | null;
50
- scope: string | null;
51
45
  provider: string;
52
- parentId: string | null;
53
46
  accountType: string;
54
47
  providerAccountId: string;
55
48
  handle: string | null;
56
49
  displayName: string | null;
57
50
  avatarUrl: string | null;
51
+ accessToken: string;
52
+ refreshToken: string | null;
58
53
  tokenType: string | null;
54
+ scope: string | null;
55
+ expiresAt: Date | null;
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
- accessToken: string;
28
- refreshToken: string | null;
29
- scope: string | null;
30
24
  provider: string;
31
- parentId: string | null;
32
25
  accountType: string;
33
26
  providerAccountId: string;
34
27
  handle: string | null;
35
28
  displayName: string | null;
36
29
  avatarUrl: string | null;
30
+ accessToken: string;
31
+ refreshToken: string | null;
37
32
  tokenType: string | null;
33
+ scope: string | null;
34
+ expiresAt: Date | null;
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
- accessToken: string;
49
- refreshToken: string | null;
50
- scope: string | null;
51
45
  provider: string;
52
- parentId: string | null;
53
46
  accountType: string;
54
47
  providerAccountId: string;
55
48
  handle: string | null;
56
49
  displayName: string | null;
57
50
  avatarUrl: string | null;
51
+ accessToken: string;
52
+ refreshToken: string | null;
58
53
  tokenType: string | null;
54
+ scope: string | null;
55
+ expiresAt: Date | null;
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;
30
- parentId?: string | null | undefined;
26
+ createdAt: Date;
31
27
  handle?: string | null | undefined;
32
28
  displayName?: string | null | undefined;
33
29
  avatarUrl?: string | null | undefined;
34
30
  tokenType?: string | null | undefined;
31
+ scope?: string | null | undefined;
32
+ expiresAt?: Date | null | undefined;
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;
30
- parentId?: string | null | undefined;
26
+ createdAt: Date;
31
27
  handle?: string | null | undefined;
32
28
  displayName?: string | null | undefined;
33
29
  avatarUrl?: string | null | undefined;
34
30
  tokenType?: string | null | undefined;
31
+ scope?: string | null | undefined;
32
+ expiresAt?: Date | null | undefined;
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" | "equals" | "greater_than" | "less_than" | "on" | "between" | "before" | "after" | "oneOf" | "intersect" | "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;
@@ -32,10 +32,10 @@ declare class RecurrenceService extends BaseService<{
32
32
  rows: {
33
33
  id: string;
34
34
  name: string | null;
35
+ userId: string | null;
35
36
  createdAt: Date;
36
37
  updatedAt: Date;
37
38
  metadata: Record<string, any> | null;
38
- userId: string | null;
39
39
  organizationId: string | null;
40
40
  teamId: string | null;
41
41
  enabled: boolean;
@@ -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" | "equals" | "greater_than" | "less_than" | "on" | "between" | "before" | "after" | "oneOf" | "intersect" | "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;
@@ -32,10 +32,10 @@ declare class RecurrenceService extends BaseService<{
32
32
  rows: {
33
33
  id: string;
34
34
  name: string | null;
35
+ userId: string | null;
35
36
  createdAt: Date;
36
37
  updatedAt: Date;
37
38
  metadata: Record<string, any> | null;
38
- userId: string | null;
39
39
  organizationId: string | null;
40
40
  teamId: string | null;
41
41
  enabled: boolean;
@@ -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" | "equals" | "greater_than" | "less_than" | "on" | "between" | "before" | "after" | "oneOf" | "intersect" | "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" | "equals" | "greater_than" | "less_than" | "on" | "between" | "before" | "after" | "oneOf" | "intersect" | "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" | "equals" | "greater_than" | "less_than" | "on" | "between" | "before" | "after" | "oneOf" | "intersect" | "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" | "equals" | "greater_than" | "less_than" | "on" | "between" | "before" | "after" | "oneOf" | "intersect" | "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" | "equals" | "greater_than" | "less_than" | "on" | "between" | "before" | "after" | "oneOf" | "intersect" | "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" | "equals" | "greater_than" | "less_than" | "on" | "between" | "before" | "after" | "oneOf" | "intersect" | "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":";;;;;AASA,MAAM,wBAAwB,cAAsB;CAClD,MAAM,WAAWA,MAAAA,SAAS,QAAQ,WAAW,EAAE,MAAM,OAAO,CAAC;AAC7D,QAAO;EACL,OAAO,SAAS,QAAQ,MAAM,CAAC,UAAU;EACzC,KAAK,SAAS,MAAM,MAAM,CAAC,UAAU;EACtC;;AAGH,MAAa,4BACX,YACA,SACA,UACqB;AACrB,KAAI,CAAC,WAAW,QAAQ,WAAW,EACjC,QAAO;AAIT,MAAK,MAAM,UAAU,SAAS;EAC5B,MAAM,EAAE,UAAU,MAAM,QAAQ,OAAO,YAAY;EAGnD,MAAM,SAAU,MAAc;AAC9B,MAAI,CAAC,OACH;AAIF,MAAI,WAAW,aAAa,WAAW,aACrC,SAAQ,MAAR;GACE,KAAK;GACL,KAAK;AAGH,QAAI,WAAW,UACb,YAAW,MAAA,GAAA,YAAA,KAAA,GAAA,YAAA,QAAe,OAAO,GAAA,GAAA,YAAA,IAAK,QAAQ,GAAG,CAAC,CAAC;QAEnD,YAAW,MAAA,GAAA,YAAA,MAAA,GAAA,YAAA,WAAmB,OAAO,GAAA,GAAA,YAAA,IAAK,QAAQ,GAAG,CAAC,CAAC;AAEzD;GACF,KAAK;AAGH,QAAI,WAAW,UACb,YAAW,MAAA,GAAA,YAAA,KAAA,GAAA,YAAA,QAAe,OAAO,GAAA,GAAA,YAAA,IAAK,QAAQ,EAAE,CAAC,CAAC;QAElD,YAAW,MAAA,GAAA,YAAA,MAAA,GAAA,YAAA,WAAmB,OAAO,GAAA,GAAA,YAAA,IAAK,QAAQ,EAAE,CAAC,CAAC;AAExD;GACF,KAAK,UAEH;GACF,QACE;;AAKN,UAAQ,MAAR;GACE,KAAK;AACH,YAAQ,QAAR;KACE,KAAK;AACH,UAAI,OAAO,UAAU,SACnB,YAAW,MAAA,GAAA,YAAA,MAAU,QAAQ,IAAI,MAAM,GAAG,CAAC;AAE7C;KACF,KAAK;AACH,UAAI,OAAO,UAAU,SACnB,YAAW,MAAA,GAAA,YAAA,IAAQ,QAAQ,MAAM,CAAC;AAEpC;KACF,KAAK;AACH,UAAI,OAAO,UAAU,SACnB,YAAW,MAAA,GAAA,YAAA,MAAU,QAAQ,GAAG,MAAM,GAAG,CAAC;AAE5C;KACF,KAAK;AACH,UAAI,OAAO,UAAU,SACnB,YAAW,MAAA,GAAA,YAAA,MAAU,QAAQ,IAAI,QAAQ,CAAC;AAE5C;KACF,KAAK;AACH,iBAAW,MAAA,GAAA,YAAA,QAAY,OAAO,CAAC;AAC/B;KACF,KAAK;AACH,iBAAW,MAAA,GAAA,YAAA,WAAe,OAAO,CAAC;AAClC;;AAEJ;GAEF,KAAK;AACH,YAAQ,QAAR;KACE,KAAK;AACH,UAAI,OAAO,UAAU,SACnB,YAAW,MAAA,GAAA,YAAA,IAAQ,QAAQ,MAAM,CAAC;AAEpC;KACF,KAAK;AACH,UAAI,OAAO,UAAU,SACnB,YAAW,MAAA,GAAA,YAAA,KAAS,QAAQ,MAAM,CAAC;AAErC;KACF,KAAK;AACH,UAAI,OAAO,UAAU,SACnB,YAAW,MAAA,GAAA,YAAA,KAAS,QAAQ,MAAM,CAAC;AAErC;KACF,KAAK;AACH,iBAAW,MAAA,GAAA,YAAA,QAAY,OAAO,CAAC;AAC/B;KACF,KAAK;AACH,iBAAW,MAAA,GAAA,YAAA,WAAe,OAAO,CAAC;AAClC;;AAEJ;GAEF,KAAK;AACH,QAAI,OAAO,UAAU,SAAU;AAE/B,YAAQ,QAAR;KACE,KAAK,MAAM;MACT,MAAM,EAAE,OAAO,QAAQ,qBAAqB,MAAM;AAClD,iBAAW,MAAA,GAAA,YAAA,MAAA,GAAA,YAAA,KAAa,QAAQ,MAAM,GAAA,GAAA,YAAA,KAAM,QAAQ,IAAI,CAAC,CAAC;AAC1D;;KAEF,KAAK;AACH,UAAI,SAAS;OACX,MAAM,EAAE,UAAU,qBAAqB,MAAM;OAC7C,MAAM,EAAE,QAAQ,qBAAqB,QAAQ;AAC7C,kBAAW,MAAA,GAAA,YAAA,SAAa,QAAQ,OAAO,IAAI,CAAC;;AAE9C;KACF,KAAK,UAAU;MACb,MAAM,EAAE,QAAQ,qBAAqB,MAAM;AAC3C,iBAAW,MAAA,GAAA,YAAA,KAAS,QAAQ,IAAI,CAAC;AACjC;;KAEF,KAAK,SAAS;MACZ,MAAM,EAAE,UAAU,qBAAqB,MAAM;AAC7C,iBAAW,MAAA,GAAA,YAAA,KAAS,QAAQ,MAAM,CAAC;AACnC;;KAEF,KAAK,aAAa;AAGhB,UAAI,CAAC,WAAW,CAAC,OAAO,YAAa;MAErC,MAAM,YAAa,MAAc,OAAO;AACxC,UAAI,CAAC,UAAW;MAEhB,MAAM,EAAE,UAAU,qBAAqB,MAAM;MAC7C,MAAM,EAAE,QAAQ,qBAAqB,QAAQ;AAE7C,iBAAW,MAAA,GAAA,YAAA,MAAA,GAAA,YAAA,KAAa,QAAQ,IAAI,GAAA,GAAA,YAAA,KAAA,GAAA,YAAA,QAAY,UAAU,GAAA,GAAA,YAAA,KAAM,WAAW,MAAM,CAAC,CAAC,CAAC;AACpF;;KAEF,KAAK;AACH,iBAAW,MAAA,GAAA,YAAA,QAAY,OAAO,CAAC;AAC/B;KACF,KAAK;AACH,iBAAW,MAAA,GAAA,YAAA,WAAe,OAAO,CAAC;AAClC;;AAEJ;GAEF,KAAK;AACH,YAAQ,QAAR;KACE,KAAK;AACH,UAAI,OAAO,UAAU,UACnB,YAAW,MAAA,GAAA,YAAA,IAAQ,QAAQ,MAAM,CAAC;AAEpC;KACF,KAAK;AACH,iBAAW,MAAA,GAAA,YAAA,QAAY,OAAO,CAAC;AAC/B;KACF,KAAK;AACH,iBAAW,MAAA,GAAA,YAAA,WAAe,OAAO,CAAC;AAClC;;AAGJ;GAEF,KAAK;AACH,YAAQ,QAAR;KACE,KAAK;AACH,UAAI,MAAM,QAAQ,MAAM,IAAI,MAAM,SAAS,EACzC,YAAW,MAAA,GAAA,YAAA,SAAa,QAAQ,MAAM,CAAC;AAEzC;KACF,KAAK;AACH,UAAI,OAAO,UAAU,SACnB,YAAW,MAAA,GAAA,YAAA,IAAQ,QAAQ,MAAM,CAAC;AAEpC;KACF,KAAK;AACH,iBAAW,MAAA,GAAA,YAAA,QAAY,OAAO,CAAC;AAC/B;KACF,KAAK;AACH,iBAAW,MAAA,GAAA,YAAA,WAAe,OAAO,CAAC;AAClC;;AAEJ;;;AAIN,QAAO"}
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":";;;AASA,MAAM,wBAAwB,cAAsB;CAClD,MAAM,WAAW,SAAS,QAAQ,WAAW,EAAE,MAAM,OAAO,CAAC;AAC7D,QAAO;EACL,OAAO,SAAS,QAAQ,MAAM,CAAC,UAAU;EACzC,KAAK,SAAS,MAAM,MAAM,CAAC,UAAU;EACtC;;AAGH,MAAa,4BACX,YACA,SACA,UACqB;AACrB,KAAI,CAAC,WAAW,QAAQ,WAAW,EACjC,QAAO;AAIT,MAAK,MAAM,UAAU,SAAS;EAC5B,MAAM,EAAE,UAAU,MAAM,QAAQ,OAAO,YAAY;EAGnD,MAAM,SAAU,MAAc;AAC9B,MAAI,CAAC,OACH;AAIF,MAAI,WAAW,aAAa,WAAW,aACrC,SAAQ,MAAR;GACE,KAAK;GACL,KAAK;AAGH,QAAI,WAAW,UACb,YAAW,KAAK,GAAG,OAAO,OAAO,EAAE,GAAG,QAAQ,GAAG,CAAC,CAAC;QAEnD,YAAW,KAAK,IAAI,UAAU,OAAO,EAAE,GAAG,QAAQ,GAAG,CAAC,CAAC;AAEzD;GACF,KAAK;AAGH,QAAI,WAAW,UACb,YAAW,KAAK,GAAG,OAAO,OAAO,EAAE,GAAG,QAAQ,EAAE,CAAC,CAAC;QAElD,YAAW,KAAK,IAAI,UAAU,OAAO,EAAE,GAAG,QAAQ,EAAE,CAAC,CAAC;AAExD;GACF,KAAK,UAEH;GACF,QACE;;AAKN,UAAQ,MAAR;GACE,KAAK;AACH,YAAQ,QAAR;KACE,KAAK;AACH,UAAI,OAAO,UAAU,SACnB,YAAW,KAAK,KAAK,QAAQ,IAAI,MAAM,GAAG,CAAC;AAE7C;KACF,KAAK;AACH,UAAI,OAAO,UAAU,SACnB,YAAW,KAAK,GAAG,QAAQ,MAAM,CAAC;AAEpC;KACF,KAAK;AACH,UAAI,OAAO,UAAU,SACnB,YAAW,KAAK,KAAK,QAAQ,GAAG,MAAM,GAAG,CAAC;AAE5C;KACF,KAAK;AACH,UAAI,OAAO,UAAU,SACnB,YAAW,KAAK,KAAK,QAAQ,IAAI,QAAQ,CAAC;AAE5C;KACF,KAAK;AACH,iBAAW,KAAK,OAAO,OAAO,CAAC;AAC/B;KACF,KAAK;AACH,iBAAW,KAAK,UAAU,OAAO,CAAC;AAClC;;AAEJ;GAEF,KAAK;AACH,YAAQ,QAAR;KACE,KAAK;AACH,UAAI,OAAO,UAAU,SACnB,YAAW,KAAK,GAAG,QAAQ,MAAM,CAAC;AAEpC;KACF,KAAK;AACH,UAAI,OAAO,UAAU,SACnB,YAAW,KAAK,IAAI,QAAQ,MAAM,CAAC;AAErC;KACF,KAAK;AACH,UAAI,OAAO,UAAU,SACnB,YAAW,KAAK,IAAI,QAAQ,MAAM,CAAC;AAErC;KACF,KAAK;AACH,iBAAW,KAAK,OAAO,OAAO,CAAC;AAC/B;KACF,KAAK;AACH,iBAAW,KAAK,UAAU,OAAO,CAAC;AAClC;;AAEJ;GAEF,KAAK;AACH,QAAI,OAAO,UAAU,SAAU;AAE/B,YAAQ,QAAR;KACE,KAAK,MAAM;MACT,MAAM,EAAE,OAAO,QAAQ,qBAAqB,MAAM;AAClD,iBAAW,KAAK,IAAI,IAAI,QAAQ,MAAM,EAAE,IAAI,QAAQ,IAAI,CAAC,CAAC;AAC1D;;KAEF,KAAK;AACH,UAAI,SAAS;OACX,MAAM,EAAE,UAAU,qBAAqB,MAAM;OAC7C,MAAM,EAAE,QAAQ,qBAAqB,QAAQ;AAC7C,kBAAW,KAAK,QAAQ,QAAQ,OAAO,IAAI,CAAC;;AAE9C;KACF,KAAK,UAAU;MACb,MAAM,EAAE,QAAQ,qBAAqB,MAAM;AAC3C,iBAAW,KAAK,IAAI,QAAQ,IAAI,CAAC;AACjC;;KAEF,KAAK,SAAS;MACZ,MAAM,EAAE,UAAU,qBAAqB,MAAM;AAC7C,iBAAW,KAAK,IAAI,QAAQ,MAAM,CAAC;AACnC;;KAEF,KAAK,aAAa;AAGhB,UAAI,CAAC,WAAW,CAAC,OAAO,YAAa;MAErC,MAAM,YAAa,MAAc,OAAO;AACxC,UAAI,CAAC,UAAW;MAEhB,MAAM,EAAE,UAAU,qBAAqB,MAAM;MAC7C,MAAM,EAAE,QAAQ,qBAAqB,QAAQ;AAE7C,iBAAW,KAAK,IAAI,IAAI,QAAQ,IAAI,EAAE,GAAG,OAAO,UAAU,EAAE,IAAI,WAAW,MAAM,CAAC,CAAC,CAAC;AACpF;;KAEF,KAAK;AACH,iBAAW,KAAK,OAAO,OAAO,CAAC;AAC/B;KACF,KAAK;AACH,iBAAW,KAAK,UAAU,OAAO,CAAC;AAClC;;AAEJ;GAEF,KAAK;AACH,YAAQ,QAAR;KACE,KAAK;AACH,UAAI,OAAO,UAAU,UACnB,YAAW,KAAK,GAAG,QAAQ,MAAM,CAAC;AAEpC;KACF,KAAK;AACH,iBAAW,KAAK,OAAO,OAAO,CAAC;AAC/B;KACF,KAAK;AACH,iBAAW,KAAK,UAAU,OAAO,CAAC;AAClC;;AAGJ;GAEF,KAAK;AACH,YAAQ,QAAR;KACE,KAAK;AACH,UAAI,MAAM,QAAQ,MAAM,IAAI,MAAM,SAAS,EACzC,YAAW,KAAK,QAAQ,QAAQ,MAAM,CAAC;AAEzC;KACF,KAAK;AACH,UAAI,OAAO,UAAU,SACnB,YAAW,KAAK,GAAG,QAAQ,MAAM,CAAC;AAEpC;KACF,KAAK;AACH,iBAAW,KAAK,OAAO,OAAO,CAAC;AAC/B;KACF,KAAK;AACH,iBAAW,KAAK,UAAU,OAAO,CAAC;AAClC;;AAEJ;;;AAIN,QAAO"}
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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"}
@@ -60,9 +60,9 @@ declare const createAuthTRPCRouter: (trpcMethods: TRPCMethods, authService: Auth
60
60
  input: void;
61
61
  output: {
62
62
  id: string;
63
+ expiresAt: Date | null;
63
64
  createdAt: Date;
64
65
  updatedAt: Date | null;
65
- expiresAt: Date | null;
66
66
  status: string;
67
67
  claimUserId: string | null;
68
68
  claimedAt: Date | null;
@@ -77,10 +77,10 @@ declare const createAuthTRPCRouter: (trpcMethods: TRPCMethods, authService: Auth
77
77
  };
78
78
  output: {
79
79
  id: string;
80
- email: string;
81
- createdAt: Date;
82
- expiresAt: Date | null;
83
80
  userId: string;
81
+ expiresAt: Date | null;
82
+ createdAt: Date;
83
+ email: string;
84
84
  claimId: string;
85
85
  url: string;
86
86
  };
@@ -92,10 +92,10 @@ declare const createAuthTRPCRouter: (trpcMethods: TRPCMethods, authService: Auth
92
92
  };
93
93
  output: {
94
94
  id: string;
95
- email: string;
96
- createdAt: Date;
97
- expiresAt: Date | null;
98
95
  userId: string;
96
+ expiresAt: Date | null;
97
+ createdAt: Date;
98
+ email: string;
99
99
  claimId: string;
100
100
  url: string;
101
101
  }[];
@@ -151,9 +151,9 @@ declare const createAuthTRPCRouter: (trpcMethods: TRPCMethods, authService: Auth
151
151
  output: {
152
152
  id: string;
153
153
  name: string | null;
154
- email: string | null;
155
154
  createdAt: Date;
156
155
  updatedAt: Date | null;
156
+ email: string | null;
157
157
  status: string;
158
158
  }[];
159
159
  meta: any;
@@ -165,9 +165,9 @@ declare const createAuthTRPCRouter: (trpcMethods: TRPCMethods, authService: Auth
165
165
  output: {
166
166
  id: string;
167
167
  name: string | null;
168
- email: string | null;
169
168
  createdAt: Date;
170
169
  updatedAt: Date | null;
170
+ email: string | null;
171
171
  status: string;
172
172
  };
173
173
  meta: any;
@@ -196,9 +196,9 @@ declare const createAuthTRPCRouter: (trpcMethods: TRPCMethods, authService: Auth
196
196
  output: {
197
197
  id: string;
198
198
  name: string | null;
199
- email: string | null;
200
199
  createdAt: Date;
201
200
  updatedAt: Date | null;
201
+ email: string | null;
202
202
  status: string;
203
203
  };
204
204
  meta: any;
@@ -210,9 +210,9 @@ declare const createAuthTRPCRouter: (trpcMethods: TRPCMethods, authService: Auth
210
210
  output: {
211
211
  id: string;
212
212
  name: string | null;
213
- email: string | null;
214
213
  createdAt: Date;
215
214
  updatedAt: Date | null;
215
+ email: string | null;
216
216
  status: string;
217
217
  };
218
218
  meta: any;
@@ -224,9 +224,9 @@ declare const createAuthTRPCRouter: (trpcMethods: TRPCMethods, authService: Auth
224
224
  output: {
225
225
  id: string;
226
226
  name: string | null;
227
- email: string | null;
228
227
  createdAt: Date;
229
228
  updatedAt: Date | null;
229
+ email: string | null;
230
230
  status: string;
231
231
  };
232
232
  meta: any;