@arcaelas/dynamite 1.0.19 → 1.0.24

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 (35) hide show
  1. package/README.md +240 -1051
  2. package/package.json +11 -42
  3. package/src/scripts/load_seed.d.ts +5 -0
  4. package/src/scripts/load_seed.js +54 -0
  5. package/src/src/@types/index.d.ts +188 -0
  6. package/src/src/@types/index.js +9 -0
  7. package/src/{core → src/core}/client.d.ts +4 -16
  8. package/src/{core → src/core}/client.js +115 -38
  9. package/src/{core → src/core}/decorator.d.ts +0 -15
  10. package/src/{core → src/core}/decorator.js +5 -35
  11. package/src/src/core/table.d.ts +81 -0
  12. package/src/src/core/table.js +892 -0
  13. package/src/{decorators → src/decorators}/indexes.d.ts +1 -1
  14. package/src/{decorators → src/decorators}/indexes.js +12 -20
  15. package/src/{decorators → src/decorators}/relations.d.ts +20 -1
  16. package/src/{decorators → src/decorators}/relations.js +32 -2
  17. package/src/{decorators → src/decorators}/timestamps.d.ts +4 -4
  18. package/src/{decorators → src/decorators}/timestamps.js +11 -6
  19. package/src/{decorators → src/decorators}/transforms.d.ts +17 -4
  20. package/src/{decorators → src/decorators}/transforms.js +40 -28
  21. package/src/src/index.d.ts +15 -0
  22. package/src/{index.js → src/index.js} +8 -22
  23. package/src/src/index.test.d.ts +6 -0
  24. package/src/src/index.test.js +789 -0
  25. package/src/{utils → src/utils}/relations.d.ts +5 -3
  26. package/src/src/utils/relations.js +216 -0
  27. package/src/@types/index.d.ts +0 -137
  28. package/src/core/method.d.ts +0 -73
  29. package/src/core/method.js +0 -140
  30. package/src/core/table.d.ts +0 -56
  31. package/src/core/table.js +0 -659
  32. package/src/index.d.ts +0 -16
  33. package/src/index.test.d.ts +0 -13
  34. package/src/index.test.js +0 -1992
  35. package/src/utils/relations.js +0 -141
package/package.json CHANGED
@@ -9,22 +9,20 @@
9
9
  "url": "https://github.com/arcaelas/dynamite/issues"
10
10
  },
11
11
  "dependencies": {
12
+ "@arcaelas/utils": "^2.0.8",
12
13
  "@aws-sdk/client-dynamodb": "3.329.0",
13
14
  "@aws-sdk/lib-dynamodb": "3.329.0",
14
15
  "pluralize": "^8.0.0",
15
16
  "uuid": "^11.1.0"
16
17
  },
17
18
  "devDependencies": {
18
- "@types/jest": "^30.0.0",
19
+ "@eslint/js": "^9.39.1",
19
20
  "@types/node": "^24.0.6",
20
- "jest": "^30.0.3",
21
- "reflect-metadata": "^0.2.2",
22
- "ts-jest": "^29.4.0",
23
- "ts-node": "^10.9.2",
21
+ "globals": "^16.5.0",
24
22
  "tsc-alias": "^1.8.16",
25
- "tsconfig-paths": "^4.2.0",
26
23
  "tsx": "^4.20.3",
27
- "typescript": "^5.8.3"
24
+ "typescript": "^5.8.3",
25
+ "typescript-eslint": "^8.49.0"
28
26
  },
29
27
  "files": [
30
28
  "src/**/*.js",
@@ -48,44 +46,15 @@
48
46
  "deploy": "npm version patch && npm publish --access=public",
49
47
  "prepublishOnly": "yarn build",
50
48
  "postpublish": "find src -type f \\( -name '*.js' -o -name '*.d.ts' -o -name '*.map' \\) -delete",
49
+ "seed:generate": "tsx scripts/generate_seed.ts",
50
+ "seed:load": "tsx scripts/load_seed.ts",
51
+ "seed:full": "yarn seed:generate && yarn seed:load",
51
52
  "test": "yarn test:db:start && yarn test:run; yarn test:db:stop",
52
- "test:run": "node --expose-gc ./node_modules/.bin/jest src/index.test.ts --runInBand --verbose",
53
- "test:watch": "yarn test:db:start && node --expose-gc ./node_modules/.bin/jest src/index.test.ts --watch --runInBand",
53
+ "test:run": "NODE_OPTIONS='--expose-gc' tsx --tsconfig tsx.config.json src/index.test.ts",
54
+ "test:watch": "yarn test:db:start && NODE_OPTIONS='--expose-gc' tsx watch src/index.test.ts",
54
55
  "test:db:start": "docker run -d -p 8000:8000 --name dynamite-test-db amazon/dynamodb-local -jar DynamoDBLocal.jar -sharedDb || echo 'DynamoDB ya está corriendo'",
55
56
  "test:db:stop": "docker stop dynamite-test-db && docker rm dynamite-test-db || true",
56
57
  "test:db:clean": "docker stop dynamite-test-db && docker rm dynamite-test-db; docker run -d -p 8000:8000 --name dynamite-test-db amazon/dynamodb-local -jar DynamoDBLocal.jar -sharedDb"
57
58
  },
58
- "version": "1.0.19",
59
- "jest": {
60
- "preset": "ts-jest",
61
- "testEnvironment": "node",
62
- "roots": [
63
- "<rootDir>/src"
64
- ],
65
- "testMatch": [
66
- "**/*.test.ts"
67
- ],
68
- "moduleNameMapper": {
69
- "^~/(.*)$": "<rootDir>/src/$1",
70
- "^@type/(.*)$": "<rootDir>/src/@types/$1"
71
- },
72
- "transform": {
73
- "^.+\\.ts$": [
74
- "ts-jest",
75
- {
76
- "tsconfig": {
77
- "experimentalDecorators": true,
78
- "emitDecoratorMetadata": true,
79
- "esModuleInterop": true,
80
- "target": "ES2022",
81
- "module": "commonjs"
82
- }
83
- }
84
- ]
85
- },
86
- "testTimeout": 60000,
87
- "maxWorkers": 1,
88
- "detectOpenHandles": false,
89
- "forceExit": true
90
- }
59
+ "version": "1.0.24"
91
60
  }
@@ -0,0 +1,5 @@
1
+ /**
2
+ * @file load_seed.ts
3
+ * @description Carga archivos JSON de seed en DynamoDB con inserción por lotes
4
+ */
5
+ export declare function load_all(): Promise<void>;
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+ /**
3
+ * @file load_seed.ts
4
+ * @description Carga archivos JSON de seed en DynamoDB con inserción por lotes
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.load_all = load_all;
8
+ const promises_1 = require("fs/promises");
9
+ const client_dynamodb_1 = require("@aws-sdk/client-dynamodb");
10
+ const util_dynamodb_1 = require("@aws-sdk/util-dynamodb");
11
+ const client_1 = require("../src/core/client");
12
+ async function load_file(filepath, table_name) {
13
+ const file_content = await (0, promises_1.readFile)(filepath, "utf-8");
14
+ const json = JSON.parse(file_content);
15
+ const client = (0, client_1.requireClient)();
16
+ console.log(` Total records: ${json.count}`);
17
+ for (let i = 0; i < json.data.length; i += 25) {
18
+ const chunk = json.data.slice(i, i + 25);
19
+ await Promise.all(chunk.map((item) => client.send(new client_dynamodb_1.PutItemCommand({
20
+ TableName: table_name,
21
+ Item: (0, util_dynamodb_1.marshall)(item, { removeUndefinedValues: true }),
22
+ }))));
23
+ if ((i + 25) % 1000 === 0 || i + 25 >= json.data.length) {
24
+ const loaded = Math.min(i + 25, json.data.length);
25
+ console.log(` Loaded ${loaded}/${json.count} records...`);
26
+ }
27
+ }
28
+ return json.count;
29
+ }
30
+ async function load_all() {
31
+ console.log("📦 Loading seed data into DynamoDB...\n");
32
+ const start_time = Date.now();
33
+ const loads = [
34
+ { file: "/tmp/dynamite_seed_users.json", table: "test_users" },
35
+ { file: "/tmp/dynamite_seed_categories.json", table: "test_categories" },
36
+ { file: "/tmp/dynamite_seed_roles.json", table: "test_roles" },
37
+ { file: "/tmp/dynamite_seed_products.json", table: "test_products" },
38
+ { file: "/tmp/dynamite_seed_orders.json", table: "test_orders" },
39
+ ];
40
+ for (const { file, table } of loads) {
41
+ console.log(`\n📄 Loading ${file}...`);
42
+ const count = await load_file(file, table);
43
+ console.log(`✅ Loaded ${count} records into ${table}`);
44
+ }
45
+ const elapsed = ((Date.now() - start_time) / 1000).toFixed(2);
46
+ console.log(`\n✅ Seed loading complete in ${elapsed}s`);
47
+ }
48
+ if (require.main === module) {
49
+ load_all().catch((error) => {
50
+ console.error("❌ Error loading seed data:", error);
51
+ process.exit(1);
52
+ });
53
+ }
54
+ //# sourceMappingURL=load_seed.js.map
@@ -0,0 +1,188 @@
1
+ /**
2
+ * @file index.ts
3
+ * @description Sistema de tipos para Dynamite ORM - Arquitectura con type-safety completo
4
+ * @autor Miguel Alejandro
5
+ * @fecha 2025-01-28
6
+ */
7
+ /**
8
+ * Marca para identificar campos que no son atributos de BD (relaciones, métodos).
9
+ */
10
+ export declare const NonAttributeBrand: unique symbol;
11
+ /**
12
+ * Marca para identificar campos opcionales en create() pero presentes en el modelo.
13
+ */
14
+ export declare const CreationOptionalBrand: unique symbol;
15
+ /**
16
+ * Wrapper para marcar relaciones y campos virtuales que no se persisten en BD.
17
+ * @example
18
+ * ```typescript
19
+ * class User extends Table<User> {
20
+ * @HasMany(() => Post, 'user_id')
21
+ * declare posts: NonAttribute<Post[]>;
22
+ * }
23
+ * ```
24
+ */
25
+ export type NonAttribute<T> = T & {
26
+ [NonAttributeBrand]?: true;
27
+ };
28
+ /**
29
+ * Wrapper para marcar campos opcionales en create() (auto-generados: id, timestamps).
30
+ * @example
31
+ * ```typescript
32
+ * class User extends Table<User> {
33
+ * @PrimaryKey() id: CreationOptional<string>;
34
+ * @CreatedAt() created_at: CreationOptional<number>;
35
+ * name: string;
36
+ * }
37
+ * await User.create({ name: 'Juan' }); // id y created_at opcionales
38
+ * ```
39
+ */
40
+ export type CreationOptional<T> = T & {
41
+ [CreationOptionalBrand]?: true;
42
+ };
43
+ /**
44
+ * Extrae atributos de BD usando intersección:
45
+ * - Primera parte: atributos REQUERIDOS con modificador `-?`
46
+ * - Segunda parte: atributos OPCIONALES (solo CreationOptional)
47
+ * - Ambos excluyen: never, undefined, null, NonAttribute, métodos
48
+ * @example
49
+ * ```typescript
50
+ * class User {
51
+ * id: CreationOptional<string>;
52
+ * created_at: CreationOptional<number>;
53
+ * name: string;
54
+ * email: string;
55
+ * posts: NonAttribute<Post[]>;
56
+ * save(): void;
57
+ * }
58
+ * // InferAttributes<User> = { name: string, email: string } & { id?: string, created_at?: number }
59
+ * // = { name: string, email: string, id?: string, created_at?: number }
60
+ * ```
61
+ */
62
+ export type InferAttributes<T> = {
63
+ [K in keyof T as T[K] extends ((...args: any[]) => any) | {
64
+ [NonAttributeBrand]?: true;
65
+ } | {
66
+ [CreationOptionalBrand]?: true;
67
+ } ? never : K]-?: Exclude<T[K], null | undefined | never>;
68
+ } & {
69
+ [K in keyof T as T[K] extends {
70
+ [CreationOptionalBrand]?: true;
71
+ } ? K : never]?: Exclude<T[K], null | undefined | never>;
72
+ };
73
+ /**
74
+ * Extrae solo relaciones (NonAttribute) preservando tipo Model | Model[]
75
+ * Excluye propiedades de Object.prototype para evitar conflictos
76
+ * @example
77
+ * ```typescript
78
+ * class User extends Table<User> {
79
+ * id: string;
80
+ * posts: NonAttribute<Post[]>; // Array
81
+ * profile: NonAttribute<Profile>; // Individual
82
+ * settings: NonAttribute<Settings | null>; // Nullable
83
+ * }
84
+ * // InferRelations<User> = { posts: Post[], profile: Profile, settings: Settings | null }
85
+ * ```
86
+ */
87
+ type ObjectBuiltinKeys = keyof Record<string, never> | 'toString' | 'valueOf' | 'hasOwnProperty' | 'isPrototypeOf' | 'propertyIsEnumerable' | 'toLocaleString' | 'constructor';
88
+ export type InferRelations<T> = {
89
+ [K in keyof T as T[K] extends NonAttribute<any> ? K extends ObjectBuiltinKeys ? never : K : never]: T[K] extends NonAttribute<infer P> ? P : never;
90
+ };
91
+ /**
92
+ * Extrae solo relaciones (campos NonAttribute).
93
+ * Usado internamente para validación.
94
+ * @example
95
+ * ```typescript
96
+ * class User {
97
+ * id: string;
98
+ * name: string;
99
+ * posts: NonAttribute<Post[]>;
100
+ * profile: NonAttribute<Profile>;
101
+ * }
102
+ * // PickRelations<User> = { posts: Post[], profile: Profile }
103
+ * ```
104
+ */
105
+ export type PickRelations<T> = {
106
+ [K in keyof T as T[K] extends NonAttribute<any> ? K : never]: T[K] extends NonAttribute<infer U> ? U : never;
107
+ };
108
+ /**
109
+ * Operadores de comparación soportados.
110
+ * Solo 8 operadores permitidos según especificación del usuario.
111
+ */
112
+ export type QueryOperator = "=" | "$eq" | "<>" | "!=" | "$ne" | "<" | "$lt" | "<=" | "$lte" | ">" | "$gt" | ">=" | "$gte" | "in" | "$in" | "include" | "$include";
113
+ /**
114
+ * Opciones de query con pre-cache de atributos (A) y relaciones (R)
115
+ * @template T - Modelo de tabla
116
+ * @template A - Cache de InferAttributes<T>
117
+ * @template R - Cache de InferRelations<T>
118
+ * @example
119
+ * ```typescript
120
+ * await User.where({}, {
121
+ * where: {
122
+ * name: 'Juan',
123
+ * age: { $gte: 18, $lte: 65 }
124
+ * },
125
+ * order: 'DESC',
126
+ * limit: 10,
127
+ * attributes: ['name', 'email'],
128
+ * include: {
129
+ * posts: {
130
+ * where: { published: true },
131
+ * limit: 5,
132
+ * include: { comments: true }
133
+ * },
134
+ * profile: {
135
+ * attributes: ['bio', 'avatar']
136
+ * }
137
+ * }
138
+ * });
139
+ * ```
140
+ */
141
+ export interface WhereOptions<T, A = InferAttributes<T>, R = InferRelations<T>> {
142
+ /** Filtros de búsqueda */
143
+ where?: {
144
+ [K in keyof A]?: A[K] | {
145
+ [N in QueryOperator]?: A[K];
146
+ };
147
+ };
148
+ /** Orden de resultados */
149
+ order?: "ASC" | "DESC";
150
+ /** Número de items a saltar */
151
+ offset?: number;
152
+ /** Alias de offset */
153
+ skip?: number;
154
+ /** Número máximo de items a retornar */
155
+ limit?: number;
156
+ /** Campos a seleccionar */
157
+ attributes?: Array<keyof A>;
158
+ /** Relaciones a cargar (recursivo) */
159
+ include?: {
160
+ [K in keyof R]?: NonNullable<R[K]> extends Array<infer U> ? true | WhereOptions<U> : true | Pick<WhereOptions<NonNullable<R[K]>>, "attributes" | "include">;
161
+ };
162
+ /** Incluir registros soft-deleted */
163
+ _includeTrashed?: boolean;
164
+ }
165
+ /**
166
+ * Input para create() - InferAttributes ya maneja opcional/requerido con intersección
167
+ * @example
168
+ * ```typescript
169
+ * class User extends Table<User> {
170
+ * id: CreationOptional<string>;
171
+ * created_at: CreationOptional<number>;
172
+ * name: string;
173
+ * email: string;
174
+ * }
175
+ * // CreateInput<User> = { name: string, email: string, id?: string, created_at?: number }
176
+ * await User.create({ name: 'Juan', email: 'juan@example.com' }); // id y created_at opcionales
177
+ * ```
178
+ */
179
+ export type CreateInput<T> = InferAttributes<T>;
180
+ /**
181
+ * Tipo para update() - todos los campos parciales.
182
+ * @example
183
+ * ```typescript
184
+ * await user.update({ name: 'Ana' }); // Todos los campos opcionales
185
+ * ```
186
+ */
187
+ export type UpdateInput<T> = Partial<InferAttributes<T>>;
188
+ export {};
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ /**
3
+ * @file index.ts
4
+ * @description Sistema de tipos para Dynamite ORM - Arquitectura con type-safety completo
5
+ * @autor Miguel Alejandro
6
+ * @fecha 2025-01-28
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ //# sourceMappingURL=index.js.map
@@ -25,25 +25,13 @@ export declare class Dynamite {
25
25
  */
26
26
  constructor(config: DynamiteConfig);
27
27
  /**
28
- * Synchronize all declared tables and their GSIs
28
+ * Connect client and synchronize all declared tables and their GSIs (upsert pattern)
29
29
  */
30
- sync(): Promise<void>;
30
+ connect(): Promise<void>;
31
31
  /**
32
- * Connect the client for Table operations
32
+ * Auto-crear pivot tables para relaciones ManyToMany
33
33
  */
34
- connect(): void;
35
- /**
36
- * Get the underlying DynamoDB client
37
- */
38
- getClient(): DynamoDBClient;
39
- /**
40
- * Check if client is connected and tables are synced
41
- */
42
- isReady(): boolean;
43
- /**
44
- * Disconnect and cleanup DynamoDB client
45
- */
46
- disconnect(): void;
34
+ private createPivotTables;
47
35
  /**
48
36
  * Ejecutar operaciones en una transacción atómica.
49
37
  * Si cualquier operación falla, todas se revierten automáticamente.
@@ -5,6 +5,39 @@
5
5
  * @autor Miguel Alejandro
6
6
  * @fecha 2025-01-27
7
7
  */
8
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
9
+ if (k2 === undefined) k2 = k;
10
+ var desc = Object.getOwnPropertyDescriptor(m, k);
11
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
12
+ desc = { enumerable: true, get: function() { return m[k]; } };
13
+ }
14
+ Object.defineProperty(o, k2, desc);
15
+ }) : (function(o, m, k, k2) {
16
+ if (k2 === undefined) k2 = k;
17
+ o[k2] = m[k];
18
+ }));
19
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
20
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
21
+ }) : function(o, v) {
22
+ o["default"] = v;
23
+ });
24
+ var __importStar = (this && this.__importStar) || (function () {
25
+ var ownKeys = function(o) {
26
+ ownKeys = Object.getOwnPropertyNames || function (o) {
27
+ var ar = [];
28
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
29
+ return ar;
30
+ };
31
+ return ownKeys(o);
32
+ };
33
+ return function (mod) {
34
+ if (mod && mod.__esModule) return mod;
35
+ var result = {};
36
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
37
+ __setModuleDefault(result, mod);
38
+ return result;
39
+ };
40
+ })();
8
41
  Object.defineProperty(exports, "__esModule", { value: true });
9
42
  exports.TransactionContext = exports.requireClient = exports.hasGlobalClient = exports.getGlobalClient = exports.setGlobalClient = exports.Dynamite = void 0;
10
43
  const client_dynamodb_1 = require("@aws-sdk/client-dynamodb");
@@ -26,49 +59,90 @@ class Dynamite {
26
59
  this.tables = tables;
27
60
  }
28
61
  /**
29
- * Synchronize all declared tables and their GSIs
62
+ * Connect client and synchronize all declared tables and their GSIs (upsert pattern)
30
63
  */
31
- async sync() {
64
+ async connect() {
32
65
  if (this.synced && this.connected)
33
66
  return;
34
- await Promise.all(this.tables.map((table) => this.createTableWithGSI(table)));
35
- this.synced = true;
36
- }
37
- /**
38
- * Connect the client for Table operations
39
- */
40
- connect() {
41
- if (this.connected)
42
- return;
67
+ // Set global client for Table operations
43
68
  (0, exports.setGlobalClient)(this.client);
44
69
  this.connected = true;
70
+ // Crear tablas principales con GSIs
71
+ await Promise.all(this.tables.map((table) => this.createTableWithGSI(table)));
72
+ // Crear pivot tables para relaciones ManyToMany
73
+ await this.createPivotTables();
74
+ this.synced = true;
45
75
  }
46
76
  /**
47
- * Get the underlying DynamoDB client
48
- */
49
- getClient() {
50
- return this.client;
51
- }
52
- /**
53
- * Check if client is connected and tables are synced
54
- */
55
- isReady() {
56
- return this.connected && this.synced;
57
- }
58
- /**
59
- * Disconnect and cleanup DynamoDB client
77
+ * Auto-crear pivot tables para relaciones ManyToMany
60
78
  */
61
- disconnect() {
62
- try {
63
- this.client.destroy();
64
- this.connected = false;
65
- this.synced = false;
66
- if (globalClient === this.client)
67
- globalClient = undefined;
68
- }
69
- catch (error) {
70
- console.warn("Error during Dynamite disconnect:", error);
79
+ async createPivotTables() {
80
+ const pivot_tables = new Map();
81
+ // Recolectar nombres de pivot tables con metadata
82
+ for (const table_class of this.tables) {
83
+ const schema = table_class[decorator_1.SCHEMA];
84
+ if (!schema)
85
+ continue;
86
+ for (const col_name in schema.columns) {
87
+ const col = schema.columns[col_name];
88
+ const relation = col.store?.relation;
89
+ if (relation?.type === "ManyToMany" && relation.pivotTable) {
90
+ pivot_tables.set(relation.pivotTable, {
91
+ foreignKey: relation.foreignKey || "source_id",
92
+ relatedKey: relation.relatedKey || "target_id"
93
+ });
94
+ }
95
+ }
71
96
  }
97
+ // Crear cada pivot table con GSIs usando los nombres de columna correctos
98
+ const { CreateTableCommand } = await Promise.resolve().then(() => __importStar(require("@aws-sdk/client-dynamodb")));
99
+ await Promise.all(Array.from(pivot_tables.entries()).map(async ([pivot_name, metadata]) => {
100
+ const { foreignKey, relatedKey } = metadata;
101
+ try {
102
+ await this.client.send(new CreateTableCommand({
103
+ TableName: pivot_name,
104
+ KeySchema: [{ AttributeName: "id", KeyType: "HASH" }],
105
+ AttributeDefinitions: [
106
+ { AttributeName: "id", AttributeType: "S" },
107
+ { AttributeName: foreignKey, AttributeType: "S" },
108
+ { AttributeName: relatedKey, AttributeType: "S" },
109
+ ],
110
+ GlobalSecondaryIndexes: [
111
+ {
112
+ IndexName: `${foreignKey}_index`,
113
+ KeySchema: [{ AttributeName: foreignKey, KeyType: "HASH" }],
114
+ Projection: { ProjectionType: "ALL" },
115
+ ProvisionedThroughput: {
116
+ ReadCapacityUnits: 5,
117
+ WriteCapacityUnits: 5,
118
+ },
119
+ },
120
+ {
121
+ IndexName: `${relatedKey}_index`,
122
+ KeySchema: [{ AttributeName: relatedKey, KeyType: "HASH" }],
123
+ Projection: { ProjectionType: "ALL" },
124
+ ProvisionedThroughput: {
125
+ ReadCapacityUnits: 5,
126
+ WriteCapacityUnits: 5,
127
+ },
128
+ },
129
+ ],
130
+ ProvisionedThroughput: {
131
+ ReadCapacityUnits: 5,
132
+ WriteCapacityUnits: 5,
133
+ },
134
+ }));
135
+ console.log(`✓ Pivot table '${pivot_name}' created`);
136
+ }
137
+ catch (error) {
138
+ if (error.name === "ResourceInUseException") {
139
+ console.log(`✓ Pivot table '${pivot_name}' already exists`);
140
+ }
141
+ else {
142
+ throw error;
143
+ }
144
+ }
145
+ }));
72
146
  }
73
147
  /**
74
148
  * Ejecutar operaciones en una transacción atómica.
@@ -103,14 +177,17 @@ class Dynamite {
103
177
  throw new Error(`PartitionKey missing in ${ctor.name}`);
104
178
  const sk = cols.find((c) => c.store?.indexSort);
105
179
  const attr = new Map();
106
- attr.set(pk.name || 'id', "S");
180
+ attr.set(pk.name || "id", "S");
107
181
  if (sk)
108
- attr.set(sk.name || 'id', "S");
182
+ attr.set(sk.name || "id", "S");
109
183
  // Temporalmente deshabilitamos la creación automática de GSI hasta implementar relaciones
110
184
  const gsiDefinitions = [];
111
- const schema = [{ AttributeName: pk.name || 'id', KeyType: "HASH" }];
185
+ const schema = [{ AttributeName: pk.name || "id", KeyType: "HASH" }];
112
186
  if (sk && sk.name !== pk.name)
113
- schema.push({ AttributeName: sk.name || 'id', KeyType: "RANGE" });
187
+ schema.push({
188
+ AttributeName: sk.name || "id",
189
+ KeyType: "RANGE",
190
+ });
114
191
  try {
115
192
  await this.client.send(new client_dynamodb_1.CreateTableCommand({
116
193
  TableName: meta.name,
@@ -5,8 +5,6 @@
5
5
  * @fecha 2025-01-28
6
6
  */
7
7
  export declare const SCHEMA: unique symbol;
8
- export declare const VALUES: unique symbol;
9
- declare function toSnakePlural(str: string): string;
10
8
  /**
11
9
  * @description Factory para crear decoradores con soporte de argumentos y composición
12
10
  * @param callback Función que recibe (schema, col, params) para configurar la columna
@@ -29,16 +27,3 @@ export declare function decorator(callback: (schema: any, col: any, params: any[
29
27
  * @returns PropertyDecorator
30
28
  */
31
29
  export declare function relationDecorator(relation_type: string, RelatedTable: any, options?: any): (target: any, propertyKey: string | symbol) => void;
32
- /**
33
- * @description Función helper para obtener metadatos del esquema
34
- * @param ctor Constructor de la clase
35
- * @returns SchemaEntry
36
- */
37
- export declare function getSchema(ctor: Function): any;
38
- /**
39
- * @description Función helper para verificar que existe esquema
40
- * @param ctor Constructor de la clase
41
- * @returns SchemaEntry
42
- */
43
- export declare function ensureSchema(ctor: Function): any;
44
- export { toSnakePlural };
@@ -6,15 +6,11 @@
6
6
  * @fecha 2025-01-28
7
7
  */
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
- exports.VALUES = exports.SCHEMA = void 0;
9
+ exports.SCHEMA = void 0;
10
10
  exports.decorator = decorator;
11
11
  exports.relationDecorator = relationDecorator;
12
- exports.getSchema = getSchema;
13
- exports.ensureSchema = ensureSchema;
14
- exports.toSnakePlural = toSnakePlural;
15
12
  // Symbols para autocontención (exportados desde table.ts pero también aquí compatibilidad)
16
13
  exports.SCHEMA = Symbol('dynamite:schema');
17
- exports.VALUES = Symbol('dynamite:values');
18
14
  // Helper simple para snake_case plural
19
15
  function toSnakePlural(str) {
20
16
  const snake = str
@@ -41,8 +37,8 @@ function decorator(callback) {
41
37
  return function (target, propertyKey) {
42
38
  const table_class = target.constructor;
43
39
  const column_name = String(propertyKey);
44
- // Inicializar SCHEMA si no existe
45
- if (!table_class[exports.SCHEMA]) {
40
+ // Inicializar SCHEMA SI NO TIENE UNO PROPIO (no heredado)
41
+ if (!Object.prototype.hasOwnProperty.call(table_class, exports.SCHEMA)) {
46
42
  table_class[exports.SCHEMA] = {
47
43
  name: toSnakePlural(table_class.name),
48
44
  primary_key: 'id',
@@ -75,7 +71,8 @@ function relationDecorator(relation_type, RelatedTable, options = {}) {
75
71
  return function (target, propertyKey) {
76
72
  const table_class = target.constructor;
77
73
  const column_name = String(propertyKey);
78
- if (!table_class[exports.SCHEMA]) {
74
+ // Inicializar SCHEMA SI NO TIENE UNO PROPIO (no heredado)
75
+ if (!Object.prototype.hasOwnProperty.call(table_class, exports.SCHEMA)) {
79
76
  table_class[exports.SCHEMA] = {
80
77
  name: toSnakePlural(table_class.name),
81
78
  primary_key: 'id',
@@ -103,31 +100,4 @@ function relationDecorator(relation_type, RelatedTable, options = {}) {
103
100
  };
104
101
  };
105
102
  }
106
- /**
107
- * @description Función helper para obtener metadatos del esquema
108
- * @param ctor Constructor de la clase
109
- * @returns SchemaEntry
110
- */
111
- function getSchema(ctor) {
112
- const schema = ctor[exports.SCHEMA];
113
- if (!schema) {
114
- throw new Error(`Schema not found for ${ctor.name}. Use decorators first.`);
115
- }
116
- return schema;
117
- }
118
- /**
119
- * @description Función helper para verificar que existe esquema
120
- * @param ctor Constructor de la clase
121
- * @returns SchemaEntry
122
- */
123
- function ensureSchema(ctor) {
124
- if (!ctor[exports.SCHEMA]) {
125
- ctor[exports.SCHEMA] = {
126
- name: toSnakePlural(ctor.name),
127
- primary_key: 'id',
128
- columns: {}
129
- };
130
- }
131
- return ctor[exports.SCHEMA];
132
- }
133
103
  //# sourceMappingURL=decorator.js.map