@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.
- package/README.md +240 -1051
- package/package.json +11 -42
- package/src/scripts/load_seed.d.ts +5 -0
- package/src/scripts/load_seed.js +54 -0
- package/src/src/@types/index.d.ts +188 -0
- package/src/src/@types/index.js +9 -0
- package/src/{core → src/core}/client.d.ts +4 -16
- package/src/{core → src/core}/client.js +115 -38
- package/src/{core → src/core}/decorator.d.ts +0 -15
- package/src/{core → src/core}/decorator.js +5 -35
- package/src/src/core/table.d.ts +81 -0
- package/src/src/core/table.js +892 -0
- package/src/{decorators → src/decorators}/indexes.d.ts +1 -1
- package/src/{decorators → src/decorators}/indexes.js +12 -20
- package/src/{decorators → src/decorators}/relations.d.ts +20 -1
- package/src/{decorators → src/decorators}/relations.js +32 -2
- package/src/{decorators → src/decorators}/timestamps.d.ts +4 -4
- package/src/{decorators → src/decorators}/timestamps.js +11 -6
- package/src/{decorators → src/decorators}/transforms.d.ts +17 -4
- package/src/{decorators → src/decorators}/transforms.js +40 -28
- package/src/src/index.d.ts +15 -0
- package/src/{index.js → src/index.js} +8 -22
- package/src/src/index.test.d.ts +6 -0
- package/src/src/index.test.js +789 -0
- package/src/{utils → src/utils}/relations.d.ts +5 -3
- package/src/src/utils/relations.js +216 -0
- package/src/@types/index.d.ts +0 -137
- package/src/core/method.d.ts +0 -73
- package/src/core/method.js +0 -140
- package/src/core/table.d.ts +0 -56
- package/src/core/table.js +0 -659
- package/src/index.d.ts +0 -16
- package/src/index.test.d.ts +0 -13
- package/src/index.test.js +0 -1992
- package/src/utils/relations.js +0 -141
|
@@ -9,17 +9,19 @@
|
|
|
9
9
|
*/
|
|
10
10
|
interface IncludeOptions {
|
|
11
11
|
where?: Record<string, any>;
|
|
12
|
+
attributes?: string[];
|
|
12
13
|
limit?: number;
|
|
13
14
|
offset?: number;
|
|
14
15
|
order?: 'asc' | 'desc';
|
|
15
16
|
include?: Record<string, IncludeOptions | boolean>;
|
|
16
17
|
}
|
|
17
18
|
/**
|
|
18
|
-
* @description Procesa includes recursivamente para cargar relaciones
|
|
19
|
+
* @description Procesa includes recursivamente para cargar relaciones con caché
|
|
19
20
|
* @param items Array de instancias a poblar
|
|
20
21
|
* @param include Objeto con relaciones a incluir
|
|
21
22
|
* @param TableClass Clase de la tabla actual
|
|
22
|
-
* @param depth Profundidad actual (máximo
|
|
23
|
+
* @param depth Profundidad actual (máximo 5 para prevenir deep nesting)
|
|
24
|
+
* @param queryCache Caché de queries para evitar duplicados (opcional)
|
|
23
25
|
* @returns Items con relaciones pobladas
|
|
24
26
|
* @example
|
|
25
27
|
* ```typescript
|
|
@@ -35,5 +37,5 @@ interface IncludeOptions {
|
|
|
35
37
|
* }, User);
|
|
36
38
|
* ```
|
|
37
39
|
*/
|
|
38
|
-
export declare const processIncludes: (items: any[], include: Record<string, IncludeOptions | boolean>, TableClass: any, depth?: number) => Promise<any[]>;
|
|
40
|
+
export declare const processIncludes: (items: any[], include: Record<string, IncludeOptions | boolean>, TableClass: any, depth?: number, queryCache?: Map<string, Map<string, any>>) => Promise<any[]>;
|
|
39
41
|
export {};
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @file relations.ts
|
|
4
|
+
* @description Sistema de carga de relaciones con batch loading
|
|
5
|
+
* @autor Miguel Alejandro
|
|
6
|
+
* @fecha 2025-01-28
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.processIncludes = void 0;
|
|
10
|
+
const client_dynamodb_1 = require("@aws-sdk/client-dynamodb");
|
|
11
|
+
const util_dynamodb_1 = require("@aws-sdk/util-dynamodb");
|
|
12
|
+
const client_1 = require("../core/client");
|
|
13
|
+
const decorator_1 = require("../core/decorator");
|
|
14
|
+
/**
|
|
15
|
+
* @description Batch load para HasMany/HasOne
|
|
16
|
+
* Obtiene items relacionados donde foreignKey IN parent_ids
|
|
17
|
+
*/
|
|
18
|
+
const batchLoadHasMany = async (items, relation, options = {}) => {
|
|
19
|
+
const parent_ids = items.map(i => i[relation.localKey]).filter(Boolean);
|
|
20
|
+
if (!parent_ids.length)
|
|
21
|
+
return new Map();
|
|
22
|
+
// Obtener clase del modelo relacionado
|
|
23
|
+
const RelatedModel = relation.model();
|
|
24
|
+
// Construir filtros combinados
|
|
25
|
+
const filters = {
|
|
26
|
+
[relation.foreignKey]: { $in: parent_ids },
|
|
27
|
+
...options.where
|
|
28
|
+
};
|
|
29
|
+
// Query con todas las opciones aplicadas
|
|
30
|
+
const related = await RelatedModel.where(filters, {
|
|
31
|
+
attributes: options.attributes,
|
|
32
|
+
order: options.order?.toUpperCase(),
|
|
33
|
+
limit: undefined, // Se aplica después de agrupar
|
|
34
|
+
offset: undefined,
|
|
35
|
+
});
|
|
36
|
+
// Agrupar por foreignKey
|
|
37
|
+
const grouped = new Map();
|
|
38
|
+
for (const item of related) {
|
|
39
|
+
const key = String(item[relation.foreignKey]);
|
|
40
|
+
if (!grouped.has(key))
|
|
41
|
+
grouped.set(key, []);
|
|
42
|
+
grouped.get(key).push(item);
|
|
43
|
+
}
|
|
44
|
+
// Aplicar limit por grupo
|
|
45
|
+
if (options.limit) {
|
|
46
|
+
for (const [key, groupItems] of grouped) {
|
|
47
|
+
grouped.set(key, groupItems.slice(options.offset ?? 0, (options.offset ?? 0) + options.limit));
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return grouped;
|
|
51
|
+
};
|
|
52
|
+
/**
|
|
53
|
+
* @description Batch load para BelongsTo
|
|
54
|
+
* Obtiene items donde id IN local_keys
|
|
55
|
+
*/
|
|
56
|
+
const batchLoadBelongsTo = async (items, relation, options = {}) => {
|
|
57
|
+
const local_keys = items.map(i => i[relation.localKey]).filter(Boolean);
|
|
58
|
+
if (!local_keys.length)
|
|
59
|
+
return new Map();
|
|
60
|
+
const RelatedModel = relation.model();
|
|
61
|
+
// Query con opciones aplicadas
|
|
62
|
+
const related = await RelatedModel.where({ [relation.foreignKey]: { $in: local_keys } }, { attributes: options.attributes });
|
|
63
|
+
const result = new Map();
|
|
64
|
+
for (const item of related) {
|
|
65
|
+
result.set(String(item[relation.foreignKey]), item);
|
|
66
|
+
}
|
|
67
|
+
return result;
|
|
68
|
+
};
|
|
69
|
+
/**
|
|
70
|
+
* @description Batch load para ManyToMany
|
|
71
|
+
* Obtiene items relacionados usando tabla pivot
|
|
72
|
+
*/
|
|
73
|
+
const batchLoadManyToMany = async (items, relation, options = {}) => {
|
|
74
|
+
const parent_ids = items.map(i => i[relation.localKey]).filter(Boolean);
|
|
75
|
+
if (!parent_ids.length)
|
|
76
|
+
return new Map();
|
|
77
|
+
const client = (0, client_1.requireClient)();
|
|
78
|
+
// [1] Query pivot table usando OR chain (DynamoDB no soporta IN nativo)
|
|
79
|
+
const or_conditions = parent_ids.map((_, i) => `#fk = :id${i}`).join(' OR ');
|
|
80
|
+
const pivot_result = await client.send(new client_dynamodb_1.ScanCommand({
|
|
81
|
+
TableName: relation.pivotTable,
|
|
82
|
+
FilterExpression: parent_ids.length > 0 ? `(${or_conditions})` : undefined,
|
|
83
|
+
ExpressionAttributeNames: { '#fk': relation.foreignKey },
|
|
84
|
+
ExpressionAttributeValues: (0, util_dynamodb_1.marshall)(parent_ids.reduce((acc, id, i) => ({ ...acc, [`:id${i}`]: id }), {}))
|
|
85
|
+
}));
|
|
86
|
+
const pivot_rows = (pivot_result.Items ?? []).map(item => (0, util_dynamodb_1.unmarshall)(item));
|
|
87
|
+
if (pivot_rows.length === 0)
|
|
88
|
+
return new Map();
|
|
89
|
+
// [2] Extract unique related IDs
|
|
90
|
+
const related_ids = [...new Set(pivot_rows.map(row => row[relation.relatedKey]))];
|
|
91
|
+
// [3] Batch load related models con opciones aplicadas
|
|
92
|
+
const RelatedModel = relation.model();
|
|
93
|
+
// Construir filtros combinados
|
|
94
|
+
const filters = {
|
|
95
|
+
[relation.relatedPK]: { $in: related_ids },
|
|
96
|
+
...options.where
|
|
97
|
+
};
|
|
98
|
+
const related_items = await RelatedModel.where(filters, {
|
|
99
|
+
attributes: options.attributes,
|
|
100
|
+
order: options.order?.toUpperCase(),
|
|
101
|
+
});
|
|
102
|
+
// [5] Map related items by ID
|
|
103
|
+
const related_map = new Map(related_items.map((item) => [String(item[relation.relatedPK]), item]));
|
|
104
|
+
// [6] Group by parent ID using pivot as bridge
|
|
105
|
+
const grouped = new Map();
|
|
106
|
+
for (const pivot of pivot_rows) {
|
|
107
|
+
const parent_id = String(pivot[relation.foreignKey]);
|
|
108
|
+
const related_id = String(pivot[relation.relatedKey]);
|
|
109
|
+
const related_item = related_map.get(related_id);
|
|
110
|
+
if (related_item) {
|
|
111
|
+
if (!grouped.has(parent_id))
|
|
112
|
+
grouped.set(parent_id, []);
|
|
113
|
+
grouped.get(parent_id).push(related_item);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
// [7] Apply limit per group
|
|
117
|
+
if (options.limit) {
|
|
118
|
+
for (const [key, items_arr] of grouped) {
|
|
119
|
+
grouped.set(key, items_arr.slice(options.offset ?? 0, (options.offset ?? 0) + options.limit));
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return grouped;
|
|
123
|
+
};
|
|
124
|
+
/**
|
|
125
|
+
* @description Procesa includes recursivamente para cargar relaciones con caché
|
|
126
|
+
* @param items Array de instancias a poblar
|
|
127
|
+
* @param include Objeto con relaciones a incluir
|
|
128
|
+
* @param TableClass Clase de la tabla actual
|
|
129
|
+
* @param depth Profundidad actual (máximo 5 para prevenir deep nesting)
|
|
130
|
+
* @param queryCache Caché de queries para evitar duplicados (opcional)
|
|
131
|
+
* @returns Items con relaciones pobladas
|
|
132
|
+
* @example
|
|
133
|
+
* ```typescript
|
|
134
|
+
* // Uso interno en Table.where()
|
|
135
|
+
* await processIncludes(users, {
|
|
136
|
+
* posts: {
|
|
137
|
+
* where: { published: true },
|
|
138
|
+
* limit: 5,
|
|
139
|
+
* include: {
|
|
140
|
+
* comments: true
|
|
141
|
+
* }
|
|
142
|
+
* }
|
|
143
|
+
* }, User);
|
|
144
|
+
* ```
|
|
145
|
+
*/
|
|
146
|
+
const processIncludes = async (items, include, TableClass, depth = 0, queryCache = new Map()) => {
|
|
147
|
+
// Límite reducido de 10 a 5 para mejor performance
|
|
148
|
+
if (!include || depth > 5 || !items.length)
|
|
149
|
+
return items;
|
|
150
|
+
const schema = TableClass[decorator_1.SCHEMA];
|
|
151
|
+
if (!schema)
|
|
152
|
+
return items;
|
|
153
|
+
const promises = Object.entries(include)
|
|
154
|
+
.filter(([key]) => Object.prototype.hasOwnProperty.call(schema.columns, key))
|
|
155
|
+
.map(async ([relation_key, options]) => {
|
|
156
|
+
const column = schema.columns[relation_key];
|
|
157
|
+
if (!column?.store?.relation)
|
|
158
|
+
return;
|
|
159
|
+
const relation = column.store.relation;
|
|
160
|
+
const opts = typeof options === 'boolean' ? {} : options;
|
|
161
|
+
// Generar clave de caché basada en tipo de relación y IDs de padres
|
|
162
|
+
const parent_ids = items.map(i => i[relation.localKey]).filter(Boolean);
|
|
163
|
+
const cache_key = `${relation.type}:${relation.model().name}:${JSON.stringify(parent_ids.sort())}:${JSON.stringify(opts.where || {})}`;
|
|
164
|
+
// Batch load según tipo con caché
|
|
165
|
+
let data;
|
|
166
|
+
// Verificar caché primero
|
|
167
|
+
if (queryCache.has(cache_key)) {
|
|
168
|
+
data = queryCache.get(cache_key);
|
|
169
|
+
}
|
|
170
|
+
else {
|
|
171
|
+
if (relation.type === 'HasMany') {
|
|
172
|
+
data = await batchLoadHasMany(items, relation, opts);
|
|
173
|
+
}
|
|
174
|
+
else if (relation.type === 'HasOne') {
|
|
175
|
+
const hasMany = await batchLoadHasMany(items, relation, { ...opts, limit: 1 });
|
|
176
|
+
data = new Map();
|
|
177
|
+
for (const [k, v] of hasMany) {
|
|
178
|
+
data.set(k, v[0] ?? null);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
else if (relation.type === 'ManyToMany') {
|
|
182
|
+
data = await batchLoadManyToMany(items, relation, opts);
|
|
183
|
+
}
|
|
184
|
+
else {
|
|
185
|
+
// BelongsTo
|
|
186
|
+
data = await batchLoadBelongsTo(items, relation, opts);
|
|
187
|
+
}
|
|
188
|
+
// Guardar en caché
|
|
189
|
+
queryCache.set(cache_key, data);
|
|
190
|
+
}
|
|
191
|
+
// Asignar datos relacionados a cada item
|
|
192
|
+
for (const item of items) {
|
|
193
|
+
const key = String(item[relation.localKey]);
|
|
194
|
+
const value = (relation.type === 'HasMany' || relation.type === 'ManyToMany')
|
|
195
|
+
? data.get(key) ?? []
|
|
196
|
+
: data.get(key) ?? null;
|
|
197
|
+
Object.defineProperty(item, relation_key, {
|
|
198
|
+
value,
|
|
199
|
+
writable: true,
|
|
200
|
+
enumerable: true,
|
|
201
|
+
configurable: true
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
// Recursión para includes anidados con caché propagado
|
|
205
|
+
if (opts.include && data.size) {
|
|
206
|
+
const all_related = Array.from(data.values()).flat().filter(Boolean);
|
|
207
|
+
if (all_related.length) {
|
|
208
|
+
await (0, exports.processIncludes)(all_related, opts.include, relation.model(), depth + 1, queryCache);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
});
|
|
212
|
+
await Promise.all(promises);
|
|
213
|
+
return items;
|
|
214
|
+
};
|
|
215
|
+
exports.processIncludes = processIncludes;
|
|
216
|
+
//# sourceMappingURL=relations.js.map
|
package/src/@types/index.d.ts
DELETED
|
@@ -1,137 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
@file index.ts
|
|
3
|
-
@descripcion Tipos públicos de Dynamite ORM
|
|
4
|
-
@autor Miguel Alejandro
|
|
5
|
-
@fecha 2025-08-07
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
// Brands para tipos especiales
|
|
9
|
-
export declare const HasManyBrand: unique symbol;
|
|
10
|
-
export declare const BelongsToBrand: unique symbol;
|
|
11
|
-
export declare const HasOneBrand: unique symbol;
|
|
12
|
-
export declare const NonAttributeBrand: unique symbol;
|
|
13
|
-
export declare const CreationOptionalBrand: unique symbol;
|
|
14
|
-
|
|
15
|
-
// Relaciones y atributos especiales
|
|
16
|
-
export type HasMany<T> = T[] & { [HasManyBrand]?: true };
|
|
17
|
-
export type BelongsTo<T> = (T | null) & { [BelongsToBrand]?: true };
|
|
18
|
-
export type HasOne<T> = (T | null) & { [HasOneBrand]?: true };
|
|
19
|
-
export type NonAttribute<T> = T & { [NonAttributeBrand]?: true };
|
|
20
|
-
export type CreationOptional<T> = T & { [CreationOptionalBrand]?: true };
|
|
21
|
-
|
|
22
|
-
// Atributos inferidos (excluye relaciones, non-attributes y funciones)
|
|
23
|
-
export type InferAttributes<T> = {
|
|
24
|
-
[K in keyof T as T[K] extends (...args: any[]) => any
|
|
25
|
-
? never
|
|
26
|
-
: T[K] extends { [HasManyBrand]?: true }
|
|
27
|
-
? never
|
|
28
|
-
: T[K] extends { [BelongsToBrand]?: true }
|
|
29
|
-
? never
|
|
30
|
-
: T[K] extends { [HasOneBrand]?: true }
|
|
31
|
-
? never
|
|
32
|
-
: T[K] extends { [NonAttributeBrand]?: true }
|
|
33
|
-
? never
|
|
34
|
-
: K]: T[K];
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
export type FilterableAttributes<T> = {
|
|
38
|
-
[K in keyof InferAttributes<T>]: InferAttributes<T>[K];
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
export type WhereOptions<T> = {
|
|
42
|
-
where?: Partial<FilterableAttributes<T>>;
|
|
43
|
-
skip?: number;
|
|
44
|
-
limit?: number;
|
|
45
|
-
order?: "ASC" | "DESC";
|
|
46
|
-
attributes?: (keyof FilterableAttributes<T>)[];
|
|
47
|
-
include?: {
|
|
48
|
-
[K in keyof T]?: T[K] extends HasMany<any> | BelongsTo<any> | HasOne<any>
|
|
49
|
-
? IncludeRelationOptions | true
|
|
50
|
-
: never;
|
|
51
|
-
};
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
/** Filtros de query sin cláusula where */
|
|
55
|
-
export type QueryFilters<T> = Omit<WhereOptions<T>, "where">;
|
|
56
|
-
|
|
57
|
-
/** @deprecated Usa QueryFilters */
|
|
58
|
-
export type WhereOptionsWithoutWhere<T> = QueryFilters<T>;
|
|
59
|
-
|
|
60
|
-
export type QueryOperator =
|
|
61
|
-
| "="
|
|
62
|
-
| "!="
|
|
63
|
-
| "<"
|
|
64
|
-
| "<="
|
|
65
|
-
| ">"
|
|
66
|
-
| ">="
|
|
67
|
-
| "in"
|
|
68
|
-
| "not-in"
|
|
69
|
-
| "contains"
|
|
70
|
-
| "begins-with";
|
|
71
|
-
|
|
72
|
-
/** Entrada de validador con soporte lazy */
|
|
73
|
-
export interface ValidatorEntry {
|
|
74
|
-
fn: (value: any) => boolean | string;
|
|
75
|
-
lazy?: boolean;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
// Tipos para core/wrapper
|
|
79
|
-
export interface Column {
|
|
80
|
-
name: string;
|
|
81
|
-
index?: true;
|
|
82
|
-
indexSort?: true;
|
|
83
|
-
primaryKey?: boolean;
|
|
84
|
-
nullable?: boolean;
|
|
85
|
-
unique?: true;
|
|
86
|
-
createdAt?: boolean;
|
|
87
|
-
updatedAt?: boolean;
|
|
88
|
-
softDelete?: boolean;
|
|
89
|
-
lazy_validators?: ((value: any) => boolean | string)[];
|
|
90
|
-
relation?: RelationMetadata;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
export interface RelationMetadata {
|
|
94
|
-
type: "hasMany" | "belongsTo" | "hasOne";
|
|
95
|
-
targetModel: () => any;
|
|
96
|
-
foreignKey: string;
|
|
97
|
-
localKey?: string;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
export interface WrapperEntry {
|
|
101
|
-
name: string;
|
|
102
|
-
columns: Map<string | symbol, Column>;
|
|
103
|
-
relations: Map<string | symbol, RelationMetadata>;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
/** Alias para WrapperEntry (usado internamente con SCHEMA symbol) */
|
|
107
|
-
export type SchemaEntry = WrapperEntry;
|
|
108
|
-
|
|
109
|
-
// Tipos internos del where de Table
|
|
110
|
-
export type IncludeRelationOptions = {
|
|
111
|
-
where?: Record<string, any>;
|
|
112
|
-
attributes?: string[];
|
|
113
|
-
order?: "ASC" | "DESC";
|
|
114
|
-
skip?: number;
|
|
115
|
-
limit?: number;
|
|
116
|
-
include?: Record<string, IncludeRelationOptions | true>;
|
|
117
|
-
};
|
|
118
|
-
|
|
119
|
-
/** Opciones de query para métodos where(), first(), last(), etc. */
|
|
120
|
-
export type QueryOptions<T> = {
|
|
121
|
-
order?: "ASC" | "DESC";
|
|
122
|
-
skip?: number;
|
|
123
|
-
limit?: number;
|
|
124
|
-
attributes?: (keyof InferAttributes<T>)[];
|
|
125
|
-
include?: {
|
|
126
|
-
[K in keyof T]?: T[K] extends HasMany<any> | BelongsTo<any> | HasOne<any>
|
|
127
|
-
? IncludeRelationOptions | true
|
|
128
|
-
: never;
|
|
129
|
-
};
|
|
130
|
-
};
|
|
131
|
-
|
|
132
|
-
/** @deprecated Usa QueryOptions */
|
|
133
|
-
export type WhereQueryOptions<T> = QueryOptions<T>;
|
|
134
|
-
|
|
135
|
-
// Tipos utilitarios para decoradores
|
|
136
|
-
export type Mutate = (value: any) => any;
|
|
137
|
-
export type Validate = (value: any) => boolean | string;
|
package/src/core/method.d.ts
DELETED
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @file method.ts
|
|
3
|
-
* @descripcion Sistema de métodos extensibles para Table
|
|
4
|
-
* @autor Miguel Alejandro
|
|
5
|
-
*/
|
|
6
|
-
/** Handler para métodos estáticos: (TableClass, args) => result */
|
|
7
|
-
export type StaticMethodHandler<R = any> = (table: any, args: any[]) => R | Promise<R>;
|
|
8
|
-
/** Handler para métodos de instancia: (TableClass, instance, args) => result */
|
|
9
|
-
export type InstanceMethodHandler<R = any> = (table: any, instance: any, args: any[]) => R | Promise<R>;
|
|
10
|
-
/**
|
|
11
|
-
* @description Configura la clase Table para el sistema de métodos
|
|
12
|
-
* @param TableClass Clase Table
|
|
13
|
-
*/
|
|
14
|
-
export declare function setTableClass(TableClass: any): void;
|
|
15
|
-
/**
|
|
16
|
-
* @description Registra un método estático en Table y lo define en la clase
|
|
17
|
-
* @param name Nombre del método
|
|
18
|
-
* @param handler Función que implementa el método
|
|
19
|
-
* @example
|
|
20
|
-
* ```typescript
|
|
21
|
-
* registerStaticMethod('customFind', function(t, args) {
|
|
22
|
-
* const meta = mustMeta(t);
|
|
23
|
-
* return instances;
|
|
24
|
-
* });
|
|
25
|
-
* // Uso: User.customFind(...)
|
|
26
|
-
* ```
|
|
27
|
-
*/
|
|
28
|
-
export declare function registerStaticMethod<R = any>(name: string, handler: StaticMethodHandler<R>): void;
|
|
29
|
-
/**
|
|
30
|
-
* @description Registra un método de instancia en Table y lo define en el prototype
|
|
31
|
-
* @param name Nombre del método
|
|
32
|
-
* @param handler Función que implementa el método
|
|
33
|
-
* @example
|
|
34
|
-
* ```typescript
|
|
35
|
-
* registerInstanceMethod('duplicate', function(t, m, args) {
|
|
36
|
-
* return t.create({ ...m.toJSON(), id: undefined });
|
|
37
|
-
* });
|
|
38
|
-
* // Uso: user.duplicate()
|
|
39
|
-
* ```
|
|
40
|
-
*/
|
|
41
|
-
export declare function registerInstanceMethod<R = any>(name: string, handler: InstanceMethodHandler<R>): void;
|
|
42
|
-
/**
|
|
43
|
-
* @description Obtiene un método estático registrado
|
|
44
|
-
*/
|
|
45
|
-
export declare function getStaticMethod(name: string): StaticMethodHandler | undefined;
|
|
46
|
-
/**
|
|
47
|
-
* @description Obtiene un método de instancia registrado
|
|
48
|
-
*/
|
|
49
|
-
export declare function getInstanceMethod(name: string): InstanceMethodHandler | undefined;
|
|
50
|
-
/**
|
|
51
|
-
* @description Ejecuta un método estático registrado
|
|
52
|
-
*/
|
|
53
|
-
export declare function callStaticMethod<R = any>(name: string, table: any, args: any[]): R | Promise<R>;
|
|
54
|
-
/**
|
|
55
|
-
* @description Ejecuta un método de instancia registrado
|
|
56
|
-
*/
|
|
57
|
-
export declare function callInstanceMethod<R = any>(name: string, table: any, instance: any, args: any[]): R | Promise<R>;
|
|
58
|
-
/**
|
|
59
|
-
* @description Verifica si un método estático está registrado
|
|
60
|
-
*/
|
|
61
|
-
export declare function hasStaticMethod(name: string): boolean;
|
|
62
|
-
/**
|
|
63
|
-
* @description Verifica si un método de instancia está registrado
|
|
64
|
-
*/
|
|
65
|
-
export declare function hasInstanceMethod(name: string): boolean;
|
|
66
|
-
/**
|
|
67
|
-
* @description Lista todos los métodos estáticos registrados
|
|
68
|
-
*/
|
|
69
|
-
export declare function listStaticMethods(): string[];
|
|
70
|
-
/**
|
|
71
|
-
* @description Lista todos los métodos de instancia registrados
|
|
72
|
-
*/
|
|
73
|
-
export declare function listInstanceMethods(): string[];
|
package/src/core/method.js
DELETED
|
@@ -1,140 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* @file method.ts
|
|
4
|
-
* @descripcion Sistema de métodos extensibles para Table
|
|
5
|
-
* @autor Miguel Alejandro
|
|
6
|
-
*/
|
|
7
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
-
exports.setTableClass = setTableClass;
|
|
9
|
-
exports.registerStaticMethod = registerStaticMethod;
|
|
10
|
-
exports.registerInstanceMethod = registerInstanceMethod;
|
|
11
|
-
exports.getStaticMethod = getStaticMethod;
|
|
12
|
-
exports.getInstanceMethod = getInstanceMethod;
|
|
13
|
-
exports.callStaticMethod = callStaticMethod;
|
|
14
|
-
exports.callInstanceMethod = callInstanceMethod;
|
|
15
|
-
exports.hasStaticMethod = hasStaticMethod;
|
|
16
|
-
exports.hasInstanceMethod = hasInstanceMethod;
|
|
17
|
-
exports.listStaticMethods = listStaticMethods;
|
|
18
|
-
exports.listInstanceMethods = listInstanceMethods;
|
|
19
|
-
/** Registro de métodos estáticos */
|
|
20
|
-
const static_methods = new Map();
|
|
21
|
-
/** Registro de métodos de instancia */
|
|
22
|
-
const instance_methods = new Map();
|
|
23
|
-
/** Referencia a la clase Table para definir propiedades */
|
|
24
|
-
let table_class = null;
|
|
25
|
-
/**
|
|
26
|
-
* @description Configura la clase Table para el sistema de métodos
|
|
27
|
-
* @param TableClass Clase Table
|
|
28
|
-
*/
|
|
29
|
-
function setTableClass(TableClass) {
|
|
30
|
-
table_class = TableClass;
|
|
31
|
-
}
|
|
32
|
-
/**
|
|
33
|
-
* @description Registra un método estático en Table y lo define en la clase
|
|
34
|
-
* @param name Nombre del método
|
|
35
|
-
* @param handler Función que implementa el método
|
|
36
|
-
* @example
|
|
37
|
-
* ```typescript
|
|
38
|
-
* registerStaticMethod('customFind', function(t, args) {
|
|
39
|
-
* const meta = mustMeta(t);
|
|
40
|
-
* return instances;
|
|
41
|
-
* });
|
|
42
|
-
* // Uso: User.customFind(...)
|
|
43
|
-
* ```
|
|
44
|
-
*/
|
|
45
|
-
function registerStaticMethod(name, handler) {
|
|
46
|
-
static_methods.set(name, handler);
|
|
47
|
-
// Definir método en la clase Table si está configurada
|
|
48
|
-
if (table_class && !Object.prototype.hasOwnProperty.call(table_class, name)) {
|
|
49
|
-
Object.defineProperty(table_class, name, {
|
|
50
|
-
value: function (...args) {
|
|
51
|
-
return callStaticMethod(name, this, args);
|
|
52
|
-
},
|
|
53
|
-
writable: true,
|
|
54
|
-
configurable: true,
|
|
55
|
-
});
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
/**
|
|
59
|
-
* @description Registra un método de instancia en Table y lo define en el prototype
|
|
60
|
-
* @param name Nombre del método
|
|
61
|
-
* @param handler Función que implementa el método
|
|
62
|
-
* @example
|
|
63
|
-
* ```typescript
|
|
64
|
-
* registerInstanceMethod('duplicate', function(t, m, args) {
|
|
65
|
-
* return t.create({ ...m.toJSON(), id: undefined });
|
|
66
|
-
* });
|
|
67
|
-
* // Uso: user.duplicate()
|
|
68
|
-
* ```
|
|
69
|
-
*/
|
|
70
|
-
function registerInstanceMethod(name, handler) {
|
|
71
|
-
instance_methods.set(name, handler);
|
|
72
|
-
// Definir método en el prototype de Table si está configurado
|
|
73
|
-
if (table_class &&
|
|
74
|
-
!Object.prototype.hasOwnProperty.call(table_class.prototype, name)) {
|
|
75
|
-
Object.defineProperty(table_class.prototype, name, {
|
|
76
|
-
value: function (...args) {
|
|
77
|
-
return callInstanceMethod(name, this.constructor, this, args);
|
|
78
|
-
},
|
|
79
|
-
writable: true,
|
|
80
|
-
configurable: true,
|
|
81
|
-
});
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
/**
|
|
85
|
-
* @description Obtiene un método estático registrado
|
|
86
|
-
*/
|
|
87
|
-
function getStaticMethod(name) {
|
|
88
|
-
return static_methods.get(name);
|
|
89
|
-
}
|
|
90
|
-
/**
|
|
91
|
-
* @description Obtiene un método de instancia registrado
|
|
92
|
-
*/
|
|
93
|
-
function getInstanceMethod(name) {
|
|
94
|
-
return instance_methods.get(name);
|
|
95
|
-
}
|
|
96
|
-
/**
|
|
97
|
-
* @description Ejecuta un método estático registrado
|
|
98
|
-
*/
|
|
99
|
-
function callStaticMethod(name, table, args) {
|
|
100
|
-
const handler = static_methods.get(name);
|
|
101
|
-
if (!handler) {
|
|
102
|
-
throw new Error(`Método estático '${name}' no registrado`);
|
|
103
|
-
}
|
|
104
|
-
return handler(table, args);
|
|
105
|
-
}
|
|
106
|
-
/**
|
|
107
|
-
* @description Ejecuta un método de instancia registrado
|
|
108
|
-
*/
|
|
109
|
-
function callInstanceMethod(name, table, instance, args) {
|
|
110
|
-
const handler = instance_methods.get(name);
|
|
111
|
-
if (!handler) {
|
|
112
|
-
throw new Error(`Método de instancia '${name}' no registrado`);
|
|
113
|
-
}
|
|
114
|
-
return handler(table, instance, args);
|
|
115
|
-
}
|
|
116
|
-
/**
|
|
117
|
-
* @description Verifica si un método estático está registrado
|
|
118
|
-
*/
|
|
119
|
-
function hasStaticMethod(name) {
|
|
120
|
-
return static_methods.has(name);
|
|
121
|
-
}
|
|
122
|
-
/**
|
|
123
|
-
* @description Verifica si un método de instancia está registrado
|
|
124
|
-
*/
|
|
125
|
-
function hasInstanceMethod(name) {
|
|
126
|
-
return instance_methods.has(name);
|
|
127
|
-
}
|
|
128
|
-
/**
|
|
129
|
-
* @description Lista todos los métodos estáticos registrados
|
|
130
|
-
*/
|
|
131
|
-
function listStaticMethods() {
|
|
132
|
-
return Array.from(static_methods.keys());
|
|
133
|
-
}
|
|
134
|
-
/**
|
|
135
|
-
* @description Lista todos los métodos de instancia registrados
|
|
136
|
-
*/
|
|
137
|
-
function listInstanceMethods() {
|
|
138
|
-
return Array.from(instance_methods.keys());
|
|
139
|
-
}
|
|
140
|
-
//# sourceMappingURL=method.js.map
|
package/src/core/table.d.ts
DELETED
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @file table.ts
|
|
3
|
-
* @description Tabla autocontenida con arquitectura minimalista y Symbol storage
|
|
4
|
-
* @autor Miguel Alejandro
|
|
5
|
-
* @fecha 2025-01-28
|
|
6
|
-
*/
|
|
7
|
-
import { TransactionContext } from "./client";
|
|
8
|
-
import { VALUES } from "./decorator";
|
|
9
|
-
interface QueryOptions<T> {
|
|
10
|
-
order?: 'ASC' | 'DESC';
|
|
11
|
-
skip?: number;
|
|
12
|
-
limit?: number;
|
|
13
|
-
attributes?: (keyof T)[];
|
|
14
|
-
include?: IncludeRelationOptions;
|
|
15
|
-
_includeTrashed?: boolean;
|
|
16
|
-
}
|
|
17
|
-
interface IncludeRelationOptions {
|
|
18
|
-
[relationName: string]: boolean | {
|
|
19
|
-
where?: any;
|
|
20
|
-
limit?: number;
|
|
21
|
-
};
|
|
22
|
-
}
|
|
23
|
-
type QueryOperator = "=" | "!=" | "<" | "<=" | ">" | ">=" | "in" | "not-in" | "contains" | "begins-with";
|
|
24
|
-
export default class Table<T = any> {
|
|
25
|
-
private readonly [VALUES];
|
|
26
|
-
constructor(props?: Partial<T>);
|
|
27
|
-
/**
|
|
28
|
-
* @description Serializa la instancia a JSON incluyendo relaciones recursivamente
|
|
29
|
-
* @returns Objeto JSON con todas las propiedades y relaciones
|
|
30
|
-
*/
|
|
31
|
-
toJSON(): Record<string, unknown>;
|
|
32
|
-
/**
|
|
33
|
-
* @description Serializa la instancia a string JSON
|
|
34
|
-
* @returns String JSON con todas las propiedades y relaciones
|
|
35
|
-
*/
|
|
36
|
-
toString(): string;
|
|
37
|
-
/**
|
|
38
|
-
* @description Genera payload para operaciones de DB (excluye relaciones)
|
|
39
|
-
*/
|
|
40
|
-
private _toDBPayload;
|
|
41
|
-
save(): Promise<this>;
|
|
42
|
-
destroy(): Promise<null>;
|
|
43
|
-
forceDestroy(): Promise<null>;
|
|
44
|
-
static create<T extends Table>(this: new (data: any) => T, data: any, tx?: TransactionContext): Promise<T>;
|
|
45
|
-
static update<T extends Table>(this: new (data: any) => T, updates: any, filters: any, tx?: TransactionContext): Promise<number>;
|
|
46
|
-
static delete<T extends Table>(this: new (data: any) => T, filters: any, tx?: TransactionContext): Promise<number>;
|
|
47
|
-
static where<T extends Table>(this: new (props?: any) => T, field_or_filters: any, operator_or_value?: any, value?: any, options?: QueryOptions<T>): Promise<T[]>;
|
|
48
|
-
static first<T extends Table>(this: new (props?: any) => T, field_or_filters: any, operator_or_value?: any, value_or_options?: any): Promise<T | undefined>;
|
|
49
|
-
static last<T extends Table>(this: new (props?: any) => T, field_or_filters?: any, operator_or_value?: any): Promise<T | undefined>;
|
|
50
|
-
static withTrashed<T extends Table>(this: new (props?: any) => T, filters?: any, options?: QueryOptions<T>): Promise<T[]>;
|
|
51
|
-
static onlyTrashed<T extends Table>(this: new (props?: any) => T, filters?: any, options?: QueryOptions<T>): Promise<T[]>;
|
|
52
|
-
private insertIntoDynamoDB;
|
|
53
|
-
private updateInDynamoDB;
|
|
54
|
-
private deleteFromDynamoDB;
|
|
55
|
-
}
|
|
56
|
-
export type { QueryOptions, IncludeRelationOptions, QueryOperator };
|