@sentzunhat/zacatl 0.0.21 → 0.0.23
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.
- package/README.md +20 -7
- package/build/index.d.ts +3 -2
- package/build/index.d.ts.map +1 -1
- package/build/index.js +3 -2
- package/build/index.js.map +1 -1
- package/build/orm/mongoose.d.ts +3 -0
- package/build/orm/mongoose.d.ts.map +1 -0
- package/build/orm/mongoose.js +2 -0
- package/build/orm/mongoose.js.map +1 -0
- package/build/orm/sequelize.d.ts +3 -0
- package/build/orm/sequelize.d.ts.map +1 -0
- package/build/orm/sequelize.js +2 -0
- package/build/orm/sequelize.js.map +1 -0
- package/build/service/architecture/application/application.d.ts +1 -0
- package/build/service/architecture/application/application.d.ts.map +1 -1
- package/build/service/architecture/application/application.js +6 -1
- package/build/service/architecture/application/application.js.map +1 -1
- package/build/service/architecture/application/index.d.ts +1 -0
- package/build/service/architecture/application/index.d.ts.map +1 -1
- package/build/service/architecture/application/index.js +1 -0
- package/build/service/architecture/application/index.js.map +1 -1
- package/build/service/architecture/domain/domain.d.ts +1 -0
- package/build/service/architecture/domain/domain.d.ts.map +1 -1
- package/build/service/architecture/domain/domain.js +6 -1
- package/build/service/architecture/domain/domain.js.map +1 -1
- package/build/service/architecture/infrastructure/index.d.ts +0 -4
- package/build/service/architecture/infrastructure/index.d.ts.map +1 -1
- package/build/service/architecture/infrastructure/index.js +0 -2
- package/build/service/architecture/infrastructure/index.js.map +1 -1
- package/build/service/architecture/infrastructure/infrastructure.d.ts +1 -0
- package/build/service/architecture/infrastructure/infrastructure.d.ts.map +1 -1
- package/build/service/architecture/infrastructure/infrastructure.js +6 -1
- package/build/service/architecture/infrastructure/infrastructure.js.map +1 -1
- package/build/service/architecture/infrastructure/orm/adapter-loader.d.ts +2 -2
- package/build/service/architecture/infrastructure/orm/adapter-loader.d.ts.map +1 -1
- package/build/service/architecture/infrastructure/orm/adapter-loader.js +8 -6
- package/build/service/architecture/infrastructure/orm/adapter-loader.js.map +1 -1
- package/build/service/architecture/infrastructure/repositories/abstract.d.ts +5 -1
- package/build/service/architecture/infrastructure/repositories/abstract.d.ts.map +1 -1
- package/build/service/architecture/infrastructure/repositories/abstract.js +34 -5
- package/build/service/architecture/infrastructure/repositories/abstract.js.map +1 -1
- package/build/service/architecture/infrastructure/repositories/types.d.ts +2 -2
- package/build/service/architecture/infrastructure/repositories/types.d.ts.map +1 -1
- package/build/service/architecture/infrastructure/repositories/types.js.map +1 -1
- package/build/test/tsconfig.tsbuildinfo +1 -1
- package/package.json +13 -3
- package/src/index.ts +5 -11
- package/src/orm/mongoose.ts +22 -0
- package/src/orm/sequelize.ts +14 -0
- package/src/service/architecture/application/application.ts +12 -3
- package/src/service/architecture/application/index.ts +1 -0
- package/src/service/architecture/domain/domain.ts +10 -1
- package/src/service/architecture/infrastructure/index.ts +0 -46
- package/src/service/architecture/infrastructure/infrastructure.ts +10 -1
- package/src/service/architecture/infrastructure/orm/adapter-loader.ts +16 -22
- package/src/service/architecture/infrastructure/repositories/abstract.ts +61 -25
- package/src/service/architecture/infrastructure/repositories/types.ts +3 -44
package/package.json
CHANGED
|
@@ -4,13 +4,21 @@
|
|
|
4
4
|
"main": "build/index.js",
|
|
5
5
|
"module": "build/index.js",
|
|
6
6
|
"types": "build/index.d.ts",
|
|
7
|
-
"version": "0.0.
|
|
7
|
+
"version": "0.0.23",
|
|
8
8
|
"packageManager": "npm@10.9.0",
|
|
9
9
|
"exports": {
|
|
10
10
|
".": {
|
|
11
11
|
"import": "./build/index.js",
|
|
12
12
|
"types": "./build/index.d.ts"
|
|
13
13
|
},
|
|
14
|
+
"./orm/mongoose": {
|
|
15
|
+
"import": "./build/orm/mongoose.js",
|
|
16
|
+
"types": "./build/orm/mongoose.d.ts"
|
|
17
|
+
},
|
|
18
|
+
"./orm/sequelize": {
|
|
19
|
+
"import": "./build/orm/sequelize.js",
|
|
20
|
+
"types": "./build/orm/sequelize.d.ts"
|
|
21
|
+
},
|
|
14
22
|
"./infrastructure": {
|
|
15
23
|
"import": "./build/service/architecture/infrastructure/repositories/abstract.js",
|
|
16
24
|
"types": "./build/service/architecture/infrastructure/repositories/abstract.d.ts"
|
|
@@ -100,7 +108,9 @@
|
|
|
100
108
|
"test:coverage": "npm run test -- --coverage",
|
|
101
109
|
"test:bun": "bun test",
|
|
102
110
|
"test:node": "vitest run",
|
|
103
|
-
"type:check": "
|
|
111
|
+
"type:check": "npm run type:check:src && npm run type:check:test",
|
|
112
|
+
"type:check:src": "tsc --noEmit -p ./tsconfig.json",
|
|
113
|
+
"type:check:test": "tsc --noEmit -p ./test/tsconfig.json",
|
|
104
114
|
"lint": "DEBUG=eslint:cli-engine bun eslint .",
|
|
105
115
|
"prepublish": "npm run test:coverage && npm run type:check && npm run lint && npm run build",
|
|
106
116
|
"publish:latest": "npm run prepublish && npm publish --access public --tag latest",
|
|
@@ -122,6 +132,7 @@
|
|
|
122
132
|
"@vitest/coverage-istanbul": "^4.0.15",
|
|
123
133
|
"eslint": "^9.39.1",
|
|
124
134
|
"knip": "^5.71.0",
|
|
135
|
+
"mongodb-memory-server": "^10.4.1",
|
|
125
136
|
"tsx": "^4.21.0",
|
|
126
137
|
"typescript": "^5.9.3",
|
|
127
138
|
"typescript-eslint": "^8.48.1",
|
|
@@ -162,7 +173,6 @@
|
|
|
162
173
|
"i18n": "^0.15.3",
|
|
163
174
|
"i18next": "^25.8.0",
|
|
164
175
|
"js-yaml": "^4.1.1",
|
|
165
|
-
"mongodb-memory-server": "^10.4.1",
|
|
166
176
|
"mongoose": "^9.0.1",
|
|
167
177
|
"pino": "^10.3.0",
|
|
168
178
|
"pino-pretty": "^13.1.3",
|
package/src/index.ts
CHANGED
|
@@ -10,10 +10,8 @@ export * from "./logs";
|
|
|
10
10
|
export * from "./runtime";
|
|
11
11
|
export * from "./localization";
|
|
12
12
|
|
|
13
|
-
// Re-export infrastructure with ORM types
|
|
14
13
|
export * from "./service/architecture/infrastructure";
|
|
15
14
|
|
|
16
|
-
// Re-export server types for convenience
|
|
17
15
|
export {
|
|
18
16
|
ServerType,
|
|
19
17
|
ServerVendor,
|
|
@@ -22,16 +20,12 @@ export {
|
|
|
22
20
|
} from "./service/architecture/platform/server/server";
|
|
23
21
|
export type { ConfigServer } from "./service/architecture/platform/server/server";
|
|
24
22
|
|
|
25
|
-
//
|
|
26
|
-
export { container } from "tsyringe";
|
|
23
|
+
// Third-party integrations
|
|
24
|
+
export { container, singleton, inject } from "tsyringe";
|
|
27
25
|
export type { DependencyContainer } from "tsyringe";
|
|
28
|
-
|
|
29
|
-
// Re-export Zod for validation
|
|
30
26
|
export { z } from "zod";
|
|
31
27
|
export type { ZodSchema, ZodType, ZodError } from "zod";
|
|
32
28
|
|
|
33
|
-
//
|
|
34
|
-
export * from "./orm
|
|
35
|
-
|
|
36
|
-
// Note: TypeScript utility types (Partial, Required, Readonly, etc.)
|
|
37
|
-
// are globally available and don't need re-export
|
|
29
|
+
// Optional ORM exports for convenience (also available via subpath imports)
|
|
30
|
+
export * from "./orm/mongoose.js";
|
|
31
|
+
export * from "./orm/sequelize.js";
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mongoose ORM exports
|
|
3
|
+
*
|
|
4
|
+
* @example Minimal bundle (tree-shakeable)
|
|
5
|
+
* import { mongoose, Schema } from "@sentzunhat/zacatl/orm/mongoose";
|
|
6
|
+
*
|
|
7
|
+
* @example Convenience (from main package)
|
|
8
|
+
* import { mongoose, Schema } from "@sentzunhat/zacatl";
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
export {
|
|
12
|
+
default as mongoose,
|
|
13
|
+
Mongoose,
|
|
14
|
+
Schema,
|
|
15
|
+
Model,
|
|
16
|
+
Document,
|
|
17
|
+
connect,
|
|
18
|
+
connection,
|
|
19
|
+
} from "mongoose";
|
|
20
|
+
|
|
21
|
+
// Type-only exports
|
|
22
|
+
export type { Model as MongooseModel } from "mongoose";
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sequelize ORM exports
|
|
3
|
+
*
|
|
4
|
+
* @example Minimal bundle (tree-shakeable)
|
|
5
|
+
* import { Sequelize, DataTypes } from "@sentzunhat/zacatl/orm/sequelize";
|
|
6
|
+
*
|
|
7
|
+
* @example Convenience (from main package)
|
|
8
|
+
* import { Sequelize, DataTypes } from "@sentzunhat/zacatl";
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
export { Sequelize, Model as SequelizeModel, DataTypes, Op } from "sequelize";
|
|
12
|
+
|
|
13
|
+
// Type-only exports
|
|
14
|
+
export type { ModelStatic, Options as SequelizeOptions } from "sequelize";
|
|
@@ -18,6 +18,7 @@ export type ApplicationEntryPoints = {
|
|
|
18
18
|
|
|
19
19
|
export type ConfigApplication = {
|
|
20
20
|
entryPoints: ApplicationEntryPoints;
|
|
21
|
+
autoRegister?: boolean; // Auto-register on construction (default: false)
|
|
21
22
|
};
|
|
22
23
|
|
|
23
24
|
export class Application extends AbstractArchitecture {
|
|
@@ -36,6 +37,11 @@ export class Application extends AbstractArchitecture {
|
|
|
36
37
|
});
|
|
37
38
|
|
|
38
39
|
this.config = config;
|
|
40
|
+
|
|
41
|
+
// Auto-register if enabled (useful without Service)
|
|
42
|
+
if (config.autoRegister) {
|
|
43
|
+
this.registerRest();
|
|
44
|
+
}
|
|
39
45
|
}
|
|
40
46
|
|
|
41
47
|
/**
|
|
@@ -44,16 +50,19 @@ export class Application extends AbstractArchitecture {
|
|
|
44
50
|
private registerRest(): void {
|
|
45
51
|
this.registerAndStoreDependencies(
|
|
46
52
|
this.config.entryPoints.rest.hookHandlers,
|
|
47
|
-
this.hookHandlers
|
|
53
|
+
this.hookHandlers,
|
|
48
54
|
);
|
|
49
55
|
|
|
50
56
|
this.registerAndStoreDependencies(
|
|
51
57
|
this.config.entryPoints.rest.routeHandlers,
|
|
52
|
-
this.routeHandlers
|
|
58
|
+
this.routeHandlers,
|
|
53
59
|
);
|
|
54
60
|
}
|
|
55
61
|
|
|
56
62
|
public start(): void {
|
|
57
|
-
|
|
63
|
+
// Register if not already done
|
|
64
|
+
if (!this.config.autoRegister) {
|
|
65
|
+
this.registerRest();
|
|
66
|
+
}
|
|
58
67
|
}
|
|
59
68
|
}
|
|
@@ -4,6 +4,7 @@ import { container } from "tsyringe";
|
|
|
4
4
|
|
|
5
5
|
export type ConfigDomain = {
|
|
6
6
|
providers: Array<Constructor>;
|
|
7
|
+
autoRegister?: boolean; // Auto-register on construction (default: false)
|
|
7
8
|
};
|
|
8
9
|
|
|
9
10
|
export class Domain extends AbstractArchitecture {
|
|
@@ -14,10 +15,18 @@ export class Domain extends AbstractArchitecture {
|
|
|
14
15
|
super();
|
|
15
16
|
|
|
16
17
|
this.config = config;
|
|
18
|
+
|
|
19
|
+
// Auto-register if enabled (useful without Service)
|
|
20
|
+
if (config.autoRegister) {
|
|
21
|
+
this.registerDependencies(this.config.providers);
|
|
22
|
+
}
|
|
17
23
|
}
|
|
18
24
|
|
|
19
25
|
public async start(): Promise<void> {
|
|
20
|
-
|
|
26
|
+
// Register if not already done
|
|
27
|
+
if (!this.config.autoRegister) {
|
|
28
|
+
this.registerDependencies(this.config.providers);
|
|
29
|
+
}
|
|
21
30
|
|
|
22
31
|
// Auto-start providers that implement the start method
|
|
23
32
|
for (const ProviderClass of this.config.providers) {
|
|
@@ -1,48 +1,2 @@
|
|
|
1
1
|
export * from "./repositories";
|
|
2
2
|
export * from "./infrastructure";
|
|
3
|
-
|
|
4
|
-
// Re-export Mongoose for user convenience
|
|
5
|
-
// Users can import directly from @sentzunhat/zacatl instead of installing mongoose
|
|
6
|
-
export {
|
|
7
|
-
Schema,
|
|
8
|
-
Model,
|
|
9
|
-
Types,
|
|
10
|
-
connect,
|
|
11
|
-
connection,
|
|
12
|
-
createConnection,
|
|
13
|
-
} from "mongoose";
|
|
14
|
-
|
|
15
|
-
export type {
|
|
16
|
-
Document,
|
|
17
|
-
SchemaDefinition,
|
|
18
|
-
SchemaOptions,
|
|
19
|
-
SchemaTypeOptions,
|
|
20
|
-
Connection,
|
|
21
|
-
Mongoose,
|
|
22
|
-
ObjectId,
|
|
23
|
-
UpdateQuery,
|
|
24
|
-
QueryOptions,
|
|
25
|
-
PopulateOptions,
|
|
26
|
-
HydratedDocument,
|
|
27
|
-
InferSchemaType,
|
|
28
|
-
} from "mongoose";
|
|
29
|
-
|
|
30
|
-
// Re-export Sequelize for user convenience
|
|
31
|
-
// Users can import directly from @sentzunhat/zacatl instead of installing sequelize
|
|
32
|
-
export { DataTypes, Sequelize, Model as SequelizeModelClass } from "sequelize";
|
|
33
|
-
|
|
34
|
-
export type {
|
|
35
|
-
ModelStatic,
|
|
36
|
-
QueryInterface,
|
|
37
|
-
Transaction,
|
|
38
|
-
Options as SequelizeOptions,
|
|
39
|
-
ModelAttributes,
|
|
40
|
-
ModelOptions,
|
|
41
|
-
FindOptions,
|
|
42
|
-
CreateOptions,
|
|
43
|
-
UpdateOptions,
|
|
44
|
-
DestroyOptions,
|
|
45
|
-
WhereOptions,
|
|
46
|
-
Order,
|
|
47
|
-
Includeable,
|
|
48
|
-
} from "sequelize";
|
|
@@ -2,6 +2,7 @@ import { AbstractArchitecture, Constructor } from "../architecture";
|
|
|
2
2
|
|
|
3
3
|
export type ConfigInfrastructure = {
|
|
4
4
|
repositories: Array<Constructor>;
|
|
5
|
+
autoRegister?: boolean; // Auto-register on construction (default: false)
|
|
5
6
|
};
|
|
6
7
|
|
|
7
8
|
export class Infrastructure extends AbstractArchitecture {
|
|
@@ -11,9 +12,17 @@ export class Infrastructure extends AbstractArchitecture {
|
|
|
11
12
|
super();
|
|
12
13
|
|
|
13
14
|
this.config = config;
|
|
15
|
+
|
|
16
|
+
// Auto-register if enabled (useful without Service)
|
|
17
|
+
if (config.autoRegister) {
|
|
18
|
+
this.registerDependencies(this.config.repositories);
|
|
19
|
+
}
|
|
14
20
|
}
|
|
15
21
|
|
|
16
22
|
public start(): void {
|
|
17
|
-
|
|
23
|
+
// Register if not already done
|
|
24
|
+
if (!this.config.autoRegister) {
|
|
25
|
+
this.registerDependencies(this.config.repositories);
|
|
26
|
+
}
|
|
18
27
|
}
|
|
19
28
|
}
|
|
@@ -5,21 +5,18 @@ import type {
|
|
|
5
5
|
ORMAdapter,
|
|
6
6
|
} from "../repositories/types";
|
|
7
7
|
|
|
8
|
-
/**
|
|
9
|
-
|
|
10
|
-
* Throws helpful error if mongoose is not installed
|
|
11
|
-
*/
|
|
12
|
-
export function loadMongooseAdapter<D, I, O>(
|
|
8
|
+
/** Lazy-loads MongooseAdapter when needed */
|
|
9
|
+
export async function loadMongooseAdapter<D, I, O>(
|
|
13
10
|
config: MongooseRepositoryConfig<D>,
|
|
14
|
-
): ORMAdapter<D, I, O
|
|
11
|
+
): Promise<ORMAdapter<D, I, O>> {
|
|
15
12
|
try {
|
|
16
|
-
|
|
17
|
-
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
18
|
-
const adapters =
|
|
19
|
-
require("./adapters/mongoose-adapter") as typeof import("./adapters/mongoose-adapter");
|
|
13
|
+
const adapters = await import("./adapters/mongoose-adapter");
|
|
20
14
|
return new adapters.MongooseAdapter<D, I, O>(config);
|
|
21
15
|
} catch (error: any) {
|
|
22
|
-
if (
|
|
16
|
+
if (
|
|
17
|
+
error.code === "ERR_MODULE_NOT_FOUND" ||
|
|
18
|
+
error.code === "MODULE_NOT_FOUND"
|
|
19
|
+
) {
|
|
23
20
|
throw new Error(
|
|
24
21
|
"Mongoose is not installed. Install it with: npm install mongoose",
|
|
25
22
|
);
|
|
@@ -28,21 +25,18 @@ export function loadMongooseAdapter<D, I, O>(
|
|
|
28
25
|
}
|
|
29
26
|
}
|
|
30
27
|
|
|
31
|
-
/**
|
|
32
|
-
|
|
33
|
-
* Throws helpful error if sequelize is not installed
|
|
34
|
-
*/
|
|
35
|
-
export function loadSequelizeAdapter<D extends Model, I, O>(
|
|
28
|
+
/** Lazy-loads SequelizeAdapter when needed */
|
|
29
|
+
export async function loadSequelizeAdapter<D extends Model, I, O>(
|
|
36
30
|
config: SequelizeRepositoryConfig<D>,
|
|
37
|
-
): ORMAdapter<D, I, O
|
|
31
|
+
): Promise<ORMAdapter<D, I, O>> {
|
|
38
32
|
try {
|
|
39
|
-
|
|
40
|
-
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
41
|
-
const adapters =
|
|
42
|
-
require("./adapters/sequelize-adapter") as typeof import("./adapters/sequelize-adapter");
|
|
33
|
+
const adapters = await import("./adapters/sequelize-adapter");
|
|
43
34
|
return new adapters.SequelizeAdapter<D, I, O>(config);
|
|
44
35
|
} catch (error: any) {
|
|
45
|
-
if (
|
|
36
|
+
if (
|
|
37
|
+
error.code === "ERR_MODULE_NOT_FOUND" ||
|
|
38
|
+
error.code === "MODULE_NOT_FOUND"
|
|
39
|
+
) {
|
|
46
40
|
throw new Error(
|
|
47
41
|
"Sequelize is not installed. Install it with: npm install sequelize",
|
|
48
42
|
);
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
// Type-only imports prevent eager loading in ESM
|
|
1
2
|
import type { Model as MongooseModel } from "mongoose";
|
|
2
3
|
import type { Model, ModelStatic } from "sequelize";
|
|
3
4
|
import {
|
|
@@ -15,18 +16,12 @@ import {
|
|
|
15
16
|
|
|
16
17
|
export * from "./types";
|
|
17
18
|
|
|
18
|
-
/**
|
|
19
|
-
* Type guard to check if config is for Mongoose
|
|
20
|
-
*/
|
|
21
19
|
const isMongooseConfig = <D>(
|
|
22
20
|
config: BaseRepositoryConfig<D>,
|
|
23
21
|
): config is MongooseRepositoryConfig<D> => {
|
|
24
22
|
return config.type === ORMType.Mongoose;
|
|
25
23
|
};
|
|
26
24
|
|
|
27
|
-
/**
|
|
28
|
-
* Type guard to check if config is for Sequelize
|
|
29
|
-
*/
|
|
30
25
|
const isSequelizeConfig = <D extends Model>(
|
|
31
26
|
config: BaseRepositoryConfig<D>,
|
|
32
27
|
): config is SequelizeRepositoryConfig<D> => {
|
|
@@ -34,30 +29,47 @@ const isSequelizeConfig = <D extends Model>(
|
|
|
34
29
|
};
|
|
35
30
|
|
|
36
31
|
/**
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
* Supports multiple ORMs (Mongoose, Sequelize) through adapter pattern.
|
|
40
|
-
* Adapters are lazy-loaded - only the ORM you use gets imported.
|
|
41
|
-
* This allows projects to install only one ORM without unused dependencies.
|
|
32
|
+
* Abstract base repository supporting multiple ORMs via adapter pattern.
|
|
33
|
+
* Adapters are lazy-loaded for optimal bundle size.
|
|
42
34
|
*/
|
|
43
35
|
export abstract class BaseRepository<D, I, O> implements Repository<D, I, O> {
|
|
44
|
-
private adapter
|
|
36
|
+
private adapter?: ORMAdapter<D, I, O>;
|
|
45
37
|
private readonly ormType: ORMType;
|
|
38
|
+
private readonly config: BaseRepositoryConfig<D>;
|
|
39
|
+
private initPromise?: Promise<void>;
|
|
46
40
|
|
|
47
41
|
constructor(config: BaseRepositoryConfig<D>) {
|
|
48
42
|
this.ormType = config.type;
|
|
43
|
+
this.config = config;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Ensures the adapter is initialized before any operation
|
|
48
|
+
* Uses a promise to prevent multiple concurrent initializations
|
|
49
|
+
*/
|
|
50
|
+
private async ensureInitialized(): Promise<void> {
|
|
51
|
+
if (this.adapter) return;
|
|
49
52
|
|
|
50
|
-
if (
|
|
51
|
-
this.
|
|
52
|
-
}
|
|
53
|
+
if (!this.initPromise) {
|
|
54
|
+
this.initPromise = this.loadAdapter();
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
await this.initPromise;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Loads the appropriate ORM adapter based on configuration
|
|
62
|
+
*/
|
|
63
|
+
private async loadAdapter(): Promise<void> {
|
|
64
|
+
if (isMongooseConfig<D>(this.config)) {
|
|
65
|
+
this.adapter = await loadMongooseAdapter<D, I, O>(this.config);
|
|
66
|
+
} else if (isSequelizeConfig(this.config)) {
|
|
53
67
|
// Type assertion needed here because D could be either Mongoose or Sequelize model
|
|
54
|
-
this.adapter = loadSequelizeAdapter<Model, I, O>(
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
O
|
|
58
|
-
>;
|
|
68
|
+
this.adapter = (await loadSequelizeAdapter<Model, I, O>(
|
|
69
|
+
this.config,
|
|
70
|
+
)) as ORMAdapter<D, I, O>;
|
|
59
71
|
} else {
|
|
60
|
-
const exhaustive: never = config;
|
|
72
|
+
const exhaustive: never = this.config;
|
|
61
73
|
throw new Error(
|
|
62
74
|
`Invalid repository configuration. Received: ${JSON.stringify(exhaustive)}`,
|
|
63
75
|
);
|
|
@@ -65,6 +77,11 @@ export abstract class BaseRepository<D, I, O> implements Repository<D, I, O> {
|
|
|
65
77
|
}
|
|
66
78
|
|
|
67
79
|
get model(): MongooseModel<D> | ModelStatic<any> {
|
|
80
|
+
if (!this.adapter) {
|
|
81
|
+
throw new Error(
|
|
82
|
+
"Repository not initialized. Call an async method first or await repository.ensureInitialized()",
|
|
83
|
+
);
|
|
84
|
+
}
|
|
68
85
|
return this.adapter.model;
|
|
69
86
|
}
|
|
70
87
|
|
|
@@ -77,6 +94,11 @@ export abstract class BaseRepository<D, I, O> implements Repository<D, I, O> {
|
|
|
77
94
|
}
|
|
78
95
|
|
|
79
96
|
public getMongooseModel(): MongooseModel<D> {
|
|
97
|
+
if (!this.adapter) {
|
|
98
|
+
throw new Error(
|
|
99
|
+
"Repository not initialized. Call an async method first or await repository.ensureInitialized()",
|
|
100
|
+
);
|
|
101
|
+
}
|
|
80
102
|
if (!this.isMongoose()) {
|
|
81
103
|
throw new Error("Repository is not using Mongoose");
|
|
82
104
|
}
|
|
@@ -84,6 +106,11 @@ export abstract class BaseRepository<D, I, O> implements Repository<D, I, O> {
|
|
|
84
106
|
}
|
|
85
107
|
|
|
86
108
|
public getSequelizeModel(): ModelStatic<any> {
|
|
109
|
+
if (!this.adapter) {
|
|
110
|
+
throw new Error(
|
|
111
|
+
"Repository not initialized. Call an async method first or await repository.ensureInitialized()",
|
|
112
|
+
);
|
|
113
|
+
}
|
|
87
114
|
if (!this.isSequelize()) {
|
|
88
115
|
throw new Error("Repository is not using Sequelize");
|
|
89
116
|
}
|
|
@@ -91,22 +118,31 @@ export abstract class BaseRepository<D, I, O> implements Repository<D, I, O> {
|
|
|
91
118
|
}
|
|
92
119
|
|
|
93
120
|
public toLean(input: unknown): O | null {
|
|
121
|
+
if (!this.adapter) {
|
|
122
|
+
throw new Error(
|
|
123
|
+
"Repository not initialized. Call an async method first or await repository.ensureInitialized()",
|
|
124
|
+
);
|
|
125
|
+
}
|
|
94
126
|
return this.adapter.toLean(input);
|
|
95
127
|
}
|
|
96
128
|
|
|
97
129
|
async findById(id: string): Promise<O | null> {
|
|
98
|
-
|
|
130
|
+
await this.ensureInitialized();
|
|
131
|
+
return this.adapter!.findById(id);
|
|
99
132
|
}
|
|
100
133
|
|
|
101
134
|
async create(entity: I): Promise<O> {
|
|
102
|
-
|
|
135
|
+
await this.ensureInitialized();
|
|
136
|
+
return this.adapter!.create(entity);
|
|
103
137
|
}
|
|
104
138
|
|
|
105
139
|
async update(id: string, update: Partial<I>): Promise<O | null> {
|
|
106
|
-
|
|
140
|
+
await this.ensureInitialized();
|
|
141
|
+
return this.adapter!.update(id, update);
|
|
107
142
|
}
|
|
108
143
|
|
|
109
144
|
async delete(id: string): Promise<O | null> {
|
|
110
|
-
|
|
145
|
+
await this.ensureInitialized();
|
|
146
|
+
return this.adapter!.delete(id);
|
|
111
147
|
}
|
|
112
148
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type {
|
|
2
2
|
Document,
|
|
3
3
|
Model as MongooseModel,
|
|
4
4
|
Schema,
|
|
@@ -7,11 +7,8 @@ import {
|
|
|
7
7
|
ObjectId,
|
|
8
8
|
IfAny,
|
|
9
9
|
} from "mongoose";
|
|
10
|
-
import { Model as SequelizeModel, ModelStatic, Model } from "sequelize";
|
|
10
|
+
import type { Model as SequelizeModel, ModelStatic, Model } from "sequelize";
|
|
11
11
|
|
|
12
|
-
/**
|
|
13
|
-
* Enum for supported ORM types
|
|
14
|
-
*/
|
|
15
12
|
export enum ORMType {
|
|
16
13
|
Mongoose = "mongoose",
|
|
17
14
|
Sequelize = "sequelize",
|
|
@@ -51,29 +48,17 @@ export type ToLeanInput<D, T> =
|
|
|
51
48
|
| null
|
|
52
49
|
| undefined;
|
|
53
50
|
|
|
54
|
-
/**
|
|
55
|
-
* Configuration for Mongoose-based repository
|
|
56
|
-
* @template D - Database document type
|
|
57
|
-
*/
|
|
58
51
|
export type MongooseRepositoryConfig<D = unknown> = {
|
|
59
52
|
readonly type: ORMType.Mongoose;
|
|
60
53
|
readonly name?: string;
|
|
61
54
|
readonly schema: Schema<D>;
|
|
62
55
|
};
|
|
63
56
|
|
|
64
|
-
/**
|
|
65
|
-
* Configuration for Sequelize-based repository
|
|
66
|
-
* @template D - Sequelize Model type (must extend Model)
|
|
67
|
-
*/
|
|
68
57
|
export type SequelizeRepositoryConfig<D extends Model = Model> = {
|
|
69
58
|
readonly type: ORMType.Sequelize;
|
|
70
59
|
readonly model: ModelStatic<D>;
|
|
71
60
|
};
|
|
72
61
|
|
|
73
|
-
/**
|
|
74
|
-
* Discriminated union of all repository configuration types
|
|
75
|
-
* @template D - Database/Model type
|
|
76
|
-
*/
|
|
77
62
|
export type BaseRepositoryConfig<D = unknown> =
|
|
78
63
|
| MongooseRepositoryConfig<D>
|
|
79
64
|
| SequelizeRepositoryConfig<Model>;
|
|
@@ -88,38 +73,12 @@ export type Repository<D, I, O> = {
|
|
|
88
73
|
delete(id: string): Promise<O | null>;
|
|
89
74
|
};
|
|
90
75
|
|
|
91
|
-
/**
|
|
92
|
-
* ORM Adapter Interface - Defines the contract for ORM-specific implementations
|
|
93
|
-
* This enables pluggable ORM support without circular dependencies
|
|
94
|
-
*/
|
|
76
|
+
/** ORM adapter interface for pluggable ORM implementations */
|
|
95
77
|
export interface ORMAdapter<D, I, O> {
|
|
96
|
-
/**
|
|
97
|
-
* Get the underlying ORM model
|
|
98
|
-
*/
|
|
99
78
|
readonly model: MongooseModel<D> | ModelStatic<any>;
|
|
100
|
-
|
|
101
|
-
/**
|
|
102
|
-
* Transform database entity to plain lean object
|
|
103
|
-
*/
|
|
104
79
|
toLean(input: unknown): O | null;
|
|
105
|
-
|
|
106
|
-
/**
|
|
107
|
-
* Find entity by ID
|
|
108
|
-
*/
|
|
109
80
|
findById(id: string): Promise<O | null>;
|
|
110
|
-
|
|
111
|
-
/**
|
|
112
|
-
* Create new entity
|
|
113
|
-
*/
|
|
114
81
|
create(entity: I): Promise<O>;
|
|
115
|
-
|
|
116
|
-
/**
|
|
117
|
-
* Update existing entity
|
|
118
|
-
*/
|
|
119
82
|
update(id: string, update: Partial<I>): Promise<O | null>;
|
|
120
|
-
|
|
121
|
-
/**
|
|
122
|
-
* Delete entity by ID
|
|
123
|
-
*/
|
|
124
83
|
delete(id: string): Promise<O | null>;
|
|
125
84
|
}
|