@avytrix/nestjs-drizzle-crud 0.0.0-stage → 3.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. package/AGENT.md +513 -0
  2. package/AGENTS.template.md +31 -0
  3. package/CHANGELOG.md +565 -0
  4. package/CLAUDE.template.md +18 -0
  5. package/LICENSE +21 -0
  6. package/README.md +1307 -2
  7. package/dist/controller/crud-controller.factory.d.ts +28 -0
  8. package/dist/controller/crud-controller.factory.js +279 -0
  9. package/dist/controller/crud-controller.factory.js.map +1 -0
  10. package/dist/core/abstract/sql-base-crud.service.d.ts +230 -0
  11. package/dist/core/abstract/sql-base-crud.service.js +2899 -0
  12. package/dist/core/abstract/sql-base-crud.service.js.map +1 -0
  13. package/dist/core/context/crud-context.d.ts +6 -0
  14. package/dist/core/context/crud-context.js +27 -0
  15. package/dist/core/context/crud-context.js.map +1 -0
  16. package/dist/core/events/crud-event-bus.d.ts +7 -0
  17. package/dist/core/events/crud-event-bus.js +30 -0
  18. package/dist/core/events/crud-event-bus.js.map +1 -0
  19. package/dist/core/interfaces/crud-service.interface.d.ts +54 -0
  20. package/dist/core/interfaces/crud-service.interface.js +3 -0
  21. package/dist/core/interfaces/crud-service.interface.js.map +1 -0
  22. package/dist/core/interfaces/drizzle-crud-config.interface.d.ts +39 -0
  23. package/dist/core/interfaces/drizzle-crud-config.interface.js +3 -0
  24. package/dist/core/interfaces/drizzle-crud-config.interface.js.map +1 -0
  25. package/dist/core/interfaces/events.interface.d.ts +39 -0
  26. package/dist/core/interfaces/events.interface.js +3 -0
  27. package/dist/core/interfaces/events.interface.js.map +1 -0
  28. package/dist/core/interfaces/query.interface.d.ts +112 -0
  29. package/dist/core/interfaces/query.interface.js +3 -0
  30. package/dist/core/interfaces/query.interface.js.map +1 -0
  31. package/dist/core/interfaces/scope.interface.d.ts +3 -0
  32. package/dist/core/interfaces/scope.interface.js +3 -0
  33. package/dist/core/interfaces/scope.interface.js.map +1 -0
  34. package/dist/core/interfaces/sql-crud-config.interface.d.ts +87 -0
  35. package/dist/core/interfaces/sql-crud-config.interface.js +3 -0
  36. package/dist/core/interfaces/sql-crud-config.interface.js.map +1 -0
  37. package/dist/core/types/sql.types.d.ts +7 -0
  38. package/dist/core/types/sql.types.js +3 -0
  39. package/dist/core/types/sql.types.js.map +1 -0
  40. package/dist/core/utils/cursor.d.ts +2 -0
  41. package/dist/core/utils/cursor.js +44 -0
  42. package/dist/core/utils/cursor.js.map +1 -0
  43. package/dist/core/utils/merge-config.d.ts +2 -0
  44. package/dist/core/utils/merge-config.js +22 -0
  45. package/dist/core/utils/merge-config.js.map +1 -0
  46. package/dist/core/utils/query-parser.d.ts +4 -0
  47. package/dist/core/utils/query-parser.js +538 -0
  48. package/dist/core/utils/query-parser.js.map +1 -0
  49. package/dist/decorators/crud-service.decorator.d.ts +4 -0
  50. package/dist/decorators/crud-service.decorator.js +10 -0
  51. package/dist/decorators/crud-service.decorator.js.map +1 -0
  52. package/dist/decorators/index.d.ts +1 -0
  53. package/dist/decorators/index.js +6 -0
  54. package/dist/decorators/index.js.map +1 -0
  55. package/dist/exceptions/crud.exceptions.d.ts +46 -0
  56. package/dist/exceptions/crud.exceptions.js +93 -0
  57. package/dist/exceptions/crud.exceptions.js.map +1 -0
  58. package/dist/index.d.ts +23 -0
  59. package/dist/index.js +61 -0
  60. package/dist/index.js.map +1 -0
  61. package/dist/mcp/server.d.ts +8 -0
  62. package/dist/mcp/server.js +236 -0
  63. package/dist/mcp/server.js.map +1 -0
  64. package/dist/modules/drizzle-connection.d.ts +12 -0
  65. package/dist/modules/drizzle-connection.js +73 -0
  66. package/dist/modules/drizzle-connection.js.map +1 -0
  67. package/dist/modules/drizzle-crud.module.d.ts +11 -0
  68. package/dist/modules/drizzle-crud.module.js +165 -0
  69. package/dist/modules/drizzle-crud.module.js.map +1 -0
  70. package/dist/openapi/api-crud.decorators.d.ts +10 -0
  71. package/dist/openapi/api-crud.decorators.js +216 -0
  72. package/dist/openapi/api-crud.decorators.js.map +1 -0
  73. package/dist/test-utils/base-crud.spec-helper.d.ts +64 -0
  74. package/dist/test-utils/base-crud.spec-helper.js +119 -0
  75. package/dist/test-utils/base-crud.spec-helper.js.map +1 -0
  76. package/dist/test-utils/index.d.ts +2 -0
  77. package/dist/test-utils/index.js +8 -0
  78. package/dist/test-utils/index.js.map +1 -0
  79. package/dist/test-utils/test-factory.d.ts +29 -0
  80. package/dist/test-utils/test-factory.js +81 -0
  81. package/dist/test-utils/test-factory.js.map +1 -0
  82. package/package.json +110 -5
@@ -0,0 +1,112 @@
1
+ import type { SortColumn, SortOrder } from "../types/sql.types";
2
+ import type { RelationsConfig, SqlOperationOptions, SqlSearchOptions } from "./sql-crud-config.interface";
3
+ export interface FilterOperators {
4
+ eq?: unknown;
5
+ neq?: unknown;
6
+ gt?: unknown;
7
+ gte?: unknown;
8
+ lt?: unknown;
9
+ lte?: unknown;
10
+ like?: string;
11
+ ilike?: string;
12
+ in?: unknown[];
13
+ notIn?: unknown[];
14
+ between?: [unknown, unknown];
15
+ isNull?: boolean | "true" | "false";
16
+ isNotNull?: boolean | "true" | "false";
17
+ startsWith?: string;
18
+ endsWith?: string;
19
+ contains?: string;
20
+ iStartsWith?: string;
21
+ iEndsWith?: string;
22
+ iContains?: string;
23
+ arrayContains?: unknown[];
24
+ arrayOverlaps?: unknown[];
25
+ jsonContains?: unknown;
26
+ }
27
+ export type FilterOperator = keyof FilterOperators;
28
+ export type FilterScalar = string | number | boolean | bigint | Date;
29
+ export type ColumnFilter = FilterScalar | FilterScalar[] | FilterOperators | null | undefined;
30
+ export interface FilterGroup {
31
+ and?: CrudFilter[];
32
+ or?: CrudFilter[];
33
+ not?: CrudFilter;
34
+ }
35
+ export type CrudFilter = FilterGroup & {
36
+ [key: string]: ColumnFilter | CrudFilter | CrudFilter[] | CollectionFilter;
37
+ };
38
+ export interface CollectionFilter {
39
+ some?: CrudFilter;
40
+ none?: CrudFilter;
41
+ every?: CrudFilter;
42
+ }
43
+ export type CollectionQuantifier = keyof CollectionFilter;
44
+ export type SortInput = string | Array<string | SortColumn>;
45
+ export interface CursorPaginationOptions {
46
+ cursor?: string | null;
47
+ after?: string | null;
48
+ limit?: number;
49
+ sortBy?: SortInput;
50
+ sortOrder?: SortOrder;
51
+ count?: boolean;
52
+ }
53
+ export interface CrudPage<T, Total extends number | null = number> {
54
+ data: T[];
55
+ total: Total;
56
+ page: number;
57
+ limit: number;
58
+ hasMore?: boolean;
59
+ }
60
+ export interface UncountedCrudPage<T> extends CrudPage<T, null> {
61
+ hasMore: boolean;
62
+ }
63
+ export type RelationCounts = string[] | Record<string, true | CrudFilter>;
64
+ export interface CountByRow<V = unknown> {
65
+ value: V;
66
+ count: number;
67
+ }
68
+ export interface CursorPage<T> {
69
+ data: T[];
70
+ limit: number;
71
+ nextCursor: string | null;
72
+ total?: number;
73
+ }
74
+ export interface CrudAllowlists {
75
+ filterableColumns?: string[];
76
+ sortableColumns?: string[];
77
+ selectableColumns?: string[];
78
+ searchableColumns?: string[];
79
+ loadableRelations?: string[];
80
+ writableRelations?: string[];
81
+ writableColumns?: string[];
82
+ }
83
+ export type BulkMode = "set" | "perItem";
84
+ export interface UpsertOptions {
85
+ conflictTarget?: string | string[];
86
+ update?: string[];
87
+ }
88
+ export interface ParseCrudQueryOptions extends CrudAllowlists {
89
+ relations?: RelationsConfig;
90
+ primaryKey?: string;
91
+ searchColumns?: string[];
92
+ allowTrash?: boolean;
93
+ ignore?: string[];
94
+ }
95
+ export interface ParsedCrudQuery {
96
+ filters: CrudFilter;
97
+ pagination: {
98
+ page?: number;
99
+ limit?: number;
100
+ sortBy?: SortColumn[];
101
+ cursor?: string | null;
102
+ count?: boolean;
103
+ withCount?: boolean;
104
+ };
105
+ sort: SortColumn[];
106
+ select?: string[];
107
+ relations?: string[];
108
+ search?: SqlSearchOptions;
109
+ counts?: string[];
110
+ options: SqlOperationOptions;
111
+ isCursor: boolean;
112
+ }
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=query.interface.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"query.interface.js","sourceRoot":"","sources":["../../../src/core/interfaces/query.interface.ts"],"names":[],"mappings":""}
@@ -0,0 +1,3 @@
1
+ export type CrudContextValue = Record<string, unknown>;
2
+ export type CrudScopeValues = Record<string, unknown>;
3
+ export type CrudScope = CrudScopeValues | ((context: CrudContextValue) => CrudScopeValues | null);
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=scope.interface.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scope.interface.js","sourceRoot":"","sources":["../../../src/core/interfaces/scope.interface.ts"],"names":[],"mappings":""}
@@ -0,0 +1,87 @@
1
+ import type { PrimaryKeyType, SortColumn, SqlDialect } from "../types/sql.types";
2
+ import type { CrudEventBus } from "../events/crud-event-bus";
3
+ import type { BulkMode, CrudAllowlists, RelationCounts } from "./query.interface";
4
+ import type { CrudContextValue, CrudScope } from "./scope.interface";
5
+ export type RelationType = "belongsTo" | "hasMany" | "manyToMany";
6
+ export interface RelationConfig {
7
+ table: any;
8
+ type?: RelationType;
9
+ localKey?: string;
10
+ references?: string;
11
+ foreignKey?: string;
12
+ parentKey?: string;
13
+ through?: any;
14
+ throughLocalKey?: string;
15
+ throughForeignKey?: string;
16
+ orderBy?: SortColumn[];
17
+ relations?: RelationsConfig;
18
+ }
19
+ export interface RelationNode {
20
+ name: string;
21
+ config: RelationConfig;
22
+ children: RelationNode[];
23
+ joined?: boolean;
24
+ }
25
+ export interface SelectTree {
26
+ base: string[];
27
+ relations: Record<string, SelectTree>;
28
+ }
29
+ export type RelationsConfig = Record<string, RelationConfig>;
30
+ export type SqlSearchMode = "ilike" | "fullText";
31
+ export interface SqlSearchOptions {
32
+ term: string;
33
+ columns: string[];
34
+ mode?: SqlSearchMode;
35
+ }
36
+ export interface SqlCrudConfig extends CrudAllowlists {
37
+ dialect: SqlDialect;
38
+ db: any;
39
+ table: any;
40
+ primaryKey: string;
41
+ primaryKeyType?: PrimaryKeyType;
42
+ softDelete?: {
43
+ enabled: boolean;
44
+ column: string;
45
+ };
46
+ timestamps?: {
47
+ createdAt: string;
48
+ updatedAt: string;
49
+ };
50
+ pagination?: {
51
+ defaultLimit: number;
52
+ maxLimit: number;
53
+ };
54
+ defaultSort?: SortColumn[];
55
+ sql?: {
56
+ caseSensitive: boolean;
57
+ useReturning: boolean;
58
+ jsonSupport: boolean;
59
+ enableFullTextSearch: boolean;
60
+ };
61
+ relations?: RelationsConfig;
62
+ scope?: CrudScope;
63
+ versionColumn?: string;
64
+ events?: CrudEventBus;
65
+ }
66
+ export interface SqlOperationOptions {
67
+ transaction?: any;
68
+ relations?: string[];
69
+ select?: string[];
70
+ search?: SqlSearchOptions;
71
+ hooks?: {
72
+ skipBefore?: boolean;
73
+ skipAfter?: boolean;
74
+ };
75
+ lock?: "update" | "share" | "none";
76
+ forNoKeyUpdate?: boolean;
77
+ withDeleted?: boolean;
78
+ onlyDeleted?: boolean;
79
+ skipAllowlists?: boolean;
80
+ bulkMode?: BulkMode;
81
+ counts?: RelationCounts;
82
+ context?: CrudContextValue;
83
+ skipScope?: boolean;
84
+ skipEvents?: boolean;
85
+ expectedVersion?: number;
86
+ expectedVersions?: Record<string, number>;
87
+ }
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=sql-crud-config.interface.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sql-crud-config.interface.js","sourceRoot":"","sources":["../../../src/core/interfaces/sql-crud-config.interface.ts"],"names":[],"mappings":""}
@@ -0,0 +1,7 @@
1
+ export type SqlDialect = "postgresql" | "mysql";
2
+ export type PrimaryKeyType = "serial" | "bigserial" | "int" | "bigint" | "uuid";
3
+ export type SortOrder = "asc" | "desc";
4
+ export interface SortColumn {
5
+ column: string;
6
+ order?: SortOrder;
7
+ }
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=sql.types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sql.types.js","sourceRoot":"","sources":["../../../src/core/types/sql.types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,2 @@
1
+ export declare function encodeCursor(values: unknown[], signature: string): string;
2
+ export declare function decodeCursor(cursor: string, signature: string, length: number): unknown[];
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.encodeCursor = encodeCursor;
4
+ exports.decodeCursor = decodeCursor;
5
+ const common_1 = require("@nestjs/common");
6
+ function encodeCursor(values, signature) {
7
+ const body = {
8
+ s: signature,
9
+ v: values.map((value) => typeof value === "bigint" ? { $b: value.toString() } : value),
10
+ };
11
+ return Buffer.from(JSON.stringify(body)).toString("base64url");
12
+ }
13
+ function decodeCursor(cursor, signature, length) {
14
+ let body;
15
+ try {
16
+ body = JSON.parse(Buffer.from(cursor, "base64url").toString("utf8"));
17
+ }
18
+ catch {
19
+ throw new common_1.BadRequestException("Invalid cursor");
20
+ }
21
+ if (!body ||
22
+ typeof body !== "object" ||
23
+ !Array.isArray(body.v) ||
24
+ body.v.length !== length) {
25
+ throw new common_1.BadRequestException("Invalid cursor");
26
+ }
27
+ if (body.s !== signature) {
28
+ throw new common_1.BadRequestException("The cursor was made for a different sort; start again without one");
29
+ }
30
+ return body.v.map((value) => {
31
+ if (!value || typeof value !== "object")
32
+ return value;
33
+ if (typeof value.$b !== "string") {
34
+ throw new common_1.BadRequestException("Invalid cursor");
35
+ }
36
+ try {
37
+ return BigInt(value.$b);
38
+ }
39
+ catch {
40
+ throw new common_1.BadRequestException("Invalid cursor");
41
+ }
42
+ });
43
+ }
44
+ //# sourceMappingURL=cursor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cursor.js","sourceRoot":"","sources":["../../../src/core/utils/cursor.ts"],"names":[],"mappings":";;;;AAAA,2CAAqD;AAYrD,sBAA6B,MAAiB,EAAE,SAAiB;IAChE,MAAM,IAAI,GAAe;QACxB,CAAC,EAAE,SAAS;QACZ,CAAC,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CACvB,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,KAAK,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAC5D;KACD,CAAC;IACF,OAAO,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;AAChE,CAAC;AAID,sBACC,MAAc,EACd,SAAiB,EACjB,MAAc;IAEd,IAAI,IAAgB,CAAC;IACrB,IAAI,CAAC;QACJ,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;IACtE,CAAC;IAAC,MAAM,CAAC;QACR,MAAM,IAAI,4BAAmB,CAAC,gBAAgB,CAAC,CAAC;IACjD,CAAC;IACD,IACC,CAAC,IAAI;QACL,OAAO,IAAI,KAAK,QAAQ;QACxB,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;QACtB,IAAI,CAAC,CAAC,CAAC,MAAM,KAAK,MAAM,EACvB,CAAC;QACF,MAAM,IAAI,4BAAmB,CAAC,gBAAgB,CAAC,CAAC;IACjD,CAAC;IACD,IAAI,IAAI,CAAC,CAAC,KAAK,SAAS,EAAE,CAAC;QAC1B,MAAM,IAAI,4BAAmB,CAC5B,mEAAmE,CACnE,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,KAAU,EAAE,EAAE;QAChC,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ;YAAE,OAAO,KAAK,CAAC;QACtD,IAAI,OAAO,KAAK,CAAC,EAAE,KAAK,QAAQ,EAAE,CAAC;YAClC,MAAM,IAAI,4BAAmB,CAAC,gBAAgB,CAAC,CAAC;QACjD,CAAC;QACD,IAAI,CAAC;YACJ,OAAO,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QACzB,CAAC;QAAC,MAAM,CAAC;YACR,MAAM,IAAI,4BAAmB,CAAC,gBAAgB,CAAC,CAAC;QACjD,CAAC;IACF,CAAC,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function isPlainObject(value: unknown): value is Record<string, any>;
2
+ export declare function mergeCrudConfig<C extends Record<string, any>>(base: C, override: Record<string, any> | undefined): C;
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isPlainObject = isPlainObject;
4
+ exports.mergeCrudConfig = mergeCrudConfig;
5
+ const NESTED_KEYS = ["softDelete", "timestamps", "pagination", "sql"];
6
+ function isPlainObject(value) {
7
+ return (typeof value === "object" &&
8
+ value !== null &&
9
+ !Array.isArray(value) &&
10
+ !(value instanceof Date));
11
+ }
12
+ function mergeCrudConfig(base, override) {
13
+ const out = { ...base, ...(override ?? {}) };
14
+ for (const key of NESTED_KEYS) {
15
+ const a = base?.[key];
16
+ const b = override?.[key];
17
+ if (isPlainObject(a) && isPlainObject(b))
18
+ out[key] = { ...a, ...b };
19
+ }
20
+ return out;
21
+ }
22
+ //# sourceMappingURL=merge-config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"merge-config.js","sourceRoot":"","sources":["../../../src/core/utils/merge-config.ts"],"names":[],"mappings":";;;;AAGA,MAAM,WAAW,GAAG,CAAC,YAAY,EAAE,YAAY,EAAE,YAAY,EAAE,KAAK,CAAU,CAAC;AAE/E,uBAA8B,KAAc;IAC3C,OAAO,CACN,OAAO,KAAK,KAAK,QAAQ;QACzB,KAAK,KAAK,IAAI;QACd,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QACrB,CAAC,CAAC,KAAK,YAAY,IAAI,CAAC,CACxB,CAAC;AACH,CAAC;AAKD,yBACC,IAAO,EACP,QAAyC;IAEzC,MAAM,GAAG,GAAwB,EAAE,GAAG,IAAI,EAAE,GAAG,CAAC,QAAQ,IAAI,EAAE,CAAC,EAAE,CAAC;IAClE,KAAK,MAAM,GAAG,IAAI,WAAW,EAAE,CAAC;QAC/B,MAAM,CAAC,GAAG,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC;QACtB,MAAM,CAAC,GAAG,QAAQ,EAAE,CAAC,GAAG,CAAC,CAAC;QAC1B,IAAI,aAAa,CAAC,CAAC,CAAC,IAAI,aAAa,CAAC,CAAC,CAAC;YAAE,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC;IACrE,CAAC;IACD,OAAO,GAAQ,CAAC;AACjB,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { ParseCrudQueryOptions, ParsedCrudQuery } from "../interfaces/query.interface";
2
+ export declare const MAX_FILTER_DEPTH = 32;
3
+ export declare function assertFilterDepth(filters: unknown): void;
4
+ export declare function parseCrudQuery(query: Record<string, unknown> | null | undefined, table: any, options?: ParseCrudQueryOptions): ParsedCrudQuery;