@arcaelas/dynamite 1.0.15 → 1.0.17

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 (53) hide show
  1. package/package.json +1 -1
  2. package/src/@types/index.d.ts +96 -0
  3. package/src/@types/index.js +9 -0
  4. package/src/core/client.d.ts +69 -0
  5. package/src/core/client.js +164 -0
  6. package/src/core/table.d.ts +98 -0
  7. package/src/core/table.js +459 -0
  8. package/src/core/wrapper.d.ts +17 -0
  9. package/src/core/wrapper.js +46 -0
  10. package/src/decorators/belongs_to.d.ts +1 -0
  11. package/src/decorators/belongs_to.js +24 -0
  12. package/src/decorators/created_at.d.ts +1 -0
  13. package/src/decorators/created_at.js +11 -0
  14. package/src/decorators/default.d.ts +1 -0
  15. package/src/decorators/default.js +47 -0
  16. package/src/decorators/has_many.d.ts +1 -0
  17. package/src/decorators/has_many.js +24 -0
  18. package/src/decorators/index.d.ts +11 -0
  19. package/src/decorators/index.js +36 -0
  20. package/src/decorators/index_sort.d.ts +12 -0
  21. package/src/decorators/index_sort.js +43 -0
  22. package/src/decorators/mutate.d.ts +2 -0
  23. package/src/decorators/mutate.js +51 -0
  24. package/src/decorators/name.d.ts +1 -0
  25. package/src/decorators/name.js +28 -0
  26. package/src/decorators/not_null.d.ts +1 -0
  27. package/src/decorators/not_null.js +13 -0
  28. package/src/decorators/primary_key.d.ts +6 -0
  29. package/src/decorators/primary_key.js +30 -0
  30. package/src/decorators/updated_at.d.ts +12 -0
  31. package/src/decorators/updated_at.js +26 -0
  32. package/src/decorators/validate.d.ts +1 -0
  33. package/src/decorators/validate.js +53 -0
  34. package/src/index.d.ts +22 -0
  35. package/src/index.js +47 -0
  36. package/src/utils/batch-relations.d.ts +14 -0
  37. package/src/utils/batch-relations.js +131 -0
  38. package/src/utils/circular-detector.d.ts +82 -0
  39. package/src/utils/circular-detector.js +212 -0
  40. package/src/utils/memory-manager.d.ts +42 -0
  41. package/src/utils/memory-manager.js +107 -0
  42. package/src/utils/naming.d.ts +8 -0
  43. package/src/utils/naming.js +18 -0
  44. package/src/utils/projection.d.ts +12 -0
  45. package/src/utils/projection.js +51 -0
  46. package/src/utils/relations.d.ts +17 -0
  47. package/src/utils/relations.js +165 -0
  48. package/src/utils/security-validator.d.ts +49 -0
  49. package/src/utils/security-validator.js +163 -0
  50. package/src/utils/throttle-manager.d.ts +78 -0
  51. package/src/utils/throttle-manager.js +201 -0
  52. package/src/utils/transaction-manager.d.ts +88 -0
  53. package/src/utils/transaction-manager.js +300 -0
package/package.json CHANGED
@@ -49,5 +49,5 @@
49
49
  "prepublishOnly": "yarn build",
50
50
  "postpublish": "find src -type f \\( -name '*.js' -o -name '*.d.ts' -o -name '*.map' \\) -delete"
51
51
  },
52
- "version": "1.0.15"
52
+ "version": "1.0.17"
53
53
  }
@@ -0,0 +1,96 @@
1
+ export declare const HasManyBrand: unique symbol;
2
+ export declare const BelongsToBrand: unique symbol;
3
+ export declare const NonAttributeBrand: unique symbol;
4
+ export declare const CreationOptionalBrand: unique symbol;
5
+ export type HasMany<T> = T[] & {
6
+ [HasManyBrand]?: true;
7
+ };
8
+ export type BelongsTo<T> = (T | null) & {
9
+ [BelongsToBrand]?: true;
10
+ };
11
+ export type NonAttribute<T> = T & {
12
+ [NonAttributeBrand]?: true;
13
+ };
14
+ export type CreationOptional<T> = T & {
15
+ [CreationOptionalBrand]?: true;
16
+ };
17
+ export type InferAttributes<T> = {
18
+ [K in keyof T as T[K] extends (...args: any[]) => any ? never : T[K] extends {
19
+ [HasManyBrand]?: true;
20
+ } ? never : T[K] extends {
21
+ [BelongsToBrand]?: true;
22
+ } ? never : T[K] extends {
23
+ [NonAttributeBrand]?: true;
24
+ } ? never : K]: T[K];
25
+ };
26
+ export type FilterableAttributes<T> = {
27
+ [K in keyof InferAttributes<T>]: InferAttributes<T>[K];
28
+ };
29
+ type SelectResult<T, A extends keyof T> = Pick<T, A>;
30
+ type ResolveIncludeType<T, K extends keyof T> = T[K] extends HasMany<infer U> ? U[] : T[K] extends BelongsTo<infer U> ? U | null : never;
31
+ export type IncludeOptions = {
32
+ where?: Record<string, any>;
33
+ attributes?: string[];
34
+ limit?: number;
35
+ skip?: number;
36
+ order?: "ASC" | "DESC";
37
+ };
38
+ export type QueryResult<T, A extends keyof T = keyof T, I extends Record<string, any> = {}> = SelectResult<T & {
39
+ [K in keyof I]: K extends keyof T ? ResolveIncludeType<T, K> : never;
40
+ }, A>;
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> ? IncludeOptions | {} : never;
49
+ };
50
+ };
51
+ export type WhereOptionsWithoutWhere<T> = Omit<WhereOptions<T>, "where">;
52
+ export type QueryOperator = "=" | "!=" | "<" | "<=" | ">" | ">=" | "in" | "not-in" | "contains" | "begins-with";
53
+ export interface Column {
54
+ name: string;
55
+ default?: any | (() => any);
56
+ mutate?: ((value: any) => any)[];
57
+ validate?: ((value: any) => boolean | string)[];
58
+ index?: true;
59
+ indexSort?: true;
60
+ primaryKey?: boolean;
61
+ nullable?: boolean;
62
+ unique?: true;
63
+ createdAt?: boolean;
64
+ updatedAt?: boolean;
65
+ }
66
+ export interface RelationMetadata {
67
+ type: "hasMany" | "belongsTo";
68
+ targetModel: () => any;
69
+ foreignKey: string;
70
+ localKey?: string;
71
+ }
72
+ export interface WrapperEntry {
73
+ name: string;
74
+ columns: Map<string | symbol, Column>;
75
+ relations: Map<string | symbol, RelationMetadata>;
76
+ }
77
+ export type IncludeRelationOptions = {
78
+ where?: Record<string, any>;
79
+ attributes?: string[];
80
+ order?: "ASC" | "DESC";
81
+ skip?: number;
82
+ limit?: number;
83
+ include?: Record<string, IncludeRelationOptions | true>;
84
+ };
85
+ export type WhereQueryOptions<T> = {
86
+ order?: "ASC" | "DESC";
87
+ skip?: number;
88
+ limit?: number;
89
+ attributes?: (keyof InferAttributes<T>)[];
90
+ include?: {
91
+ [K in keyof T]?: T[K] extends HasMany<any> | BelongsTo<any> ? IncludeRelationOptions | true : never;
92
+ };
93
+ };
94
+ export type Mutate = (value: any) => any;
95
+ export type Validate = (value: any) => boolean | string;
96
+ export {};
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ /*
3
+ @file index.ts
4
+ @descripcion Tipos públicos de Dynamite ORM
5
+ @autor Miguel Alejandro
6
+ @fecha 2025-08-07
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,69 @@
1
+ /**
2
+ * @file client.ts
3
+ * @description Centralized Dynamite client with multi-client support and table sync
4
+ * @autor Miguel Alejandro
5
+ * @fecha 2025-01-27
6
+ */
7
+ import { DynamoDBClient, DynamoDBClientConfig } from "@aws-sdk/client-dynamodb";
8
+ /**
9
+ * Configuration for Dynamite client initialization
10
+ */
11
+ export interface DynamiteConfig extends DynamoDBClientConfig {
12
+ tables: Array<new (...args: any[]) => any>;
13
+ }
14
+ /**
15
+ * Centralized Dynamite client for managing DynamoDB connections and table synchronization
16
+ */
17
+ export declare class Dynamite {
18
+ private client;
19
+ private tables;
20
+ private connected;
21
+ private synced;
22
+ /**
23
+ * Initialize Dynamite client with configuration
24
+ * @param config Dynamite client configuration
25
+ */
26
+ constructor(config: DynamiteConfig);
27
+ /**
28
+ * Synchronize all declared tables and their GSIs
29
+ */
30
+ sync(): Promise<void>;
31
+ /**
32
+ * Connect the client for Table operations
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;
47
+ /**
48
+ * Create table with automatic GSI detection and creation
49
+ * @param ctor Table class constructor
50
+ */
51
+ private createTableWithGSI;
52
+ }
53
+ /**
54
+ * Set global client for Table class operations
55
+ * @param client DynamoDB client instance
56
+ */
57
+ export declare const setGlobalClient: (client: DynamoDBClient) => void;
58
+ /**
59
+ * Get global client for Table class operations
60
+ */
61
+ export declare const getGlobalClient: () => DynamoDBClient;
62
+ /**
63
+ * Check if global client is available
64
+ */
65
+ export declare const hasGlobalClient: () => boolean;
66
+ /**
67
+ * Require global client for Table operations (throws if not available)
68
+ */
69
+ export declare const requireClient: () => DynamoDBClient;
@@ -0,0 +1,164 @@
1
+ "use strict";
2
+ /**
3
+ * @file client.ts
4
+ * @description Centralized Dynamite client with multi-client support and table sync
5
+ * @autor Miguel Alejandro
6
+ * @fecha 2025-01-27
7
+ */
8
+ var __importDefault = (this && this.__importDefault) || function (mod) {
9
+ return (mod && mod.__esModule) ? mod : { "default": mod };
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.requireClient = exports.hasGlobalClient = exports.getGlobalClient = exports.setGlobalClient = exports.Dynamite = void 0;
13
+ const client_dynamodb_1 = require("@aws-sdk/client-dynamodb");
14
+ const wrapper_1 = __importDefault(require("./wrapper"));
15
+ /**
16
+ * Centralized Dynamite client for managing DynamoDB connections and table synchronization
17
+ */
18
+ class Dynamite {
19
+ /**
20
+ * Initialize Dynamite client with configuration
21
+ * @param config Dynamite client configuration
22
+ */
23
+ constructor(config) {
24
+ this.connected = false;
25
+ this.synced = false;
26
+ const { tables, ...clientConfig } = config;
27
+ this.client = new client_dynamodb_1.DynamoDBClient(clientConfig);
28
+ this.tables = tables;
29
+ }
30
+ /**
31
+ * Synchronize all declared tables and their GSIs
32
+ */
33
+ async sync() {
34
+ if (this.synced && this.connected)
35
+ return;
36
+ await Promise.all(this.tables.map((table) => this.createTableWithGSI(table)));
37
+ this.synced = true;
38
+ }
39
+ /**
40
+ * Connect the client for Table operations
41
+ */
42
+ connect() {
43
+ if (this.connected)
44
+ return;
45
+ (0, exports.setGlobalClient)(this.client);
46
+ this.connected = true;
47
+ }
48
+ /**
49
+ * Get the underlying DynamoDB client
50
+ */
51
+ getClient() {
52
+ return this.client;
53
+ }
54
+ /**
55
+ * Check if client is connected and tables are synced
56
+ */
57
+ isReady() {
58
+ return this.connected && this.synced;
59
+ }
60
+ /**
61
+ * Disconnect and cleanup DynamoDB client
62
+ */
63
+ disconnect() {
64
+ try {
65
+ this.client.destroy();
66
+ this.connected = false;
67
+ this.synced = false;
68
+ if (globalClient === this.client)
69
+ globalClient = undefined;
70
+ }
71
+ catch (error) {
72
+ console.warn("Error during Dynamite disconnect:", error);
73
+ }
74
+ }
75
+ /**
76
+ * Create table with automatic GSI detection and creation
77
+ * @param ctor Table class constructor
78
+ */
79
+ async createTableWithGSI(ctor) {
80
+ const meta = wrapper_1.default.get(ctor);
81
+ if (!meta)
82
+ throw new Error(`Class ${ctor.name} not registered in wrapper`);
83
+ const cols = [...meta.columns.values()];
84
+ const pk = cols.find((c) => c.index);
85
+ if (!pk)
86
+ throw new Error(`PartitionKey missing in ${ctor.name}`);
87
+ const sk = cols.find((c) => c.indexSort);
88
+ const attr = new Map();
89
+ attr.set(pk.name, "S");
90
+ if (sk)
91
+ attr.set(sk.name, "S");
92
+ let gsiIndex = 1;
93
+ const gsiDefinitions = [...meta.relations.values()]
94
+ .filter((relation) => relation.type === "hasMany")
95
+ .map((relation) => {
96
+ const { foreignKey } = relation;
97
+ if (!attr.has(foreignKey))
98
+ attr.set(foreignKey, "S");
99
+ return {
100
+ IndexName: `GSI${gsiIndex++}_${foreignKey}`,
101
+ KeySchema: [{ AttributeName: foreignKey, KeyType: "HASH" }],
102
+ Projection: { ProjectionType: "ALL" },
103
+ };
104
+ });
105
+ const schema = [{ AttributeName: pk.name, KeyType: "HASH" }];
106
+ if (sk && sk.name !== pk.name)
107
+ schema.push({ AttributeName: sk.name, KeyType: "RANGE" });
108
+ try {
109
+ await this.client.send(new client_dynamodb_1.CreateTableCommand({
110
+ TableName: meta.name,
111
+ BillingMode: "PAY_PER_REQUEST",
112
+ AttributeDefinitions: [...attr].map(([AttributeName, AttributeType]) => ({
113
+ AttributeName,
114
+ AttributeType,
115
+ })),
116
+ KeySchema: schema,
117
+ ...(gsiDefinitions.length > 0 && {
118
+ GlobalSecondaryIndexes: gsiDefinitions,
119
+ }),
120
+ }));
121
+ }
122
+ catch (error) {
123
+ if (error.name !== "ResourceInUseException")
124
+ throw error;
125
+ }
126
+ }
127
+ }
128
+ exports.Dynamite = Dynamite;
129
+ let globalClient;
130
+ /**
131
+ * Set global client for Table class operations
132
+ * @param client DynamoDB client instance
133
+ */
134
+ const setGlobalClient = (client) => {
135
+ globalClient = client;
136
+ };
137
+ exports.setGlobalClient = setGlobalClient;
138
+ /**
139
+ * Get global client for Table class operations
140
+ */
141
+ const getGlobalClient = () => {
142
+ if (!globalClient)
143
+ throw new Error("No global DynamoDB client set. Call setGlobalClient() first.");
144
+ return globalClient;
145
+ };
146
+ exports.getGlobalClient = getGlobalClient;
147
+ /**
148
+ * Check if global client is available
149
+ */
150
+ const hasGlobalClient = () => {
151
+ return globalClient !== undefined;
152
+ };
153
+ exports.hasGlobalClient = hasGlobalClient;
154
+ /**
155
+ * Require global client for Table operations (throws if not available)
156
+ */
157
+ const requireClient = () => {
158
+ if (!globalClient) {
159
+ throw new Error("DynamoDB client no configurado. Use Dynamite.connect() primero.");
160
+ }
161
+ return globalClient;
162
+ };
163
+ exports.requireClient = requireClient;
164
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1,98 @@
1
+ /**
2
+ * @file table.ts
3
+ * @descripcion Clase Table rediseñada con API completa y tipado estricto
4
+ * @autor Miguel Alejandro
5
+ * @fecha 2025-07-30
6
+ */
7
+ import type { InferAttributes, QueryOperator, WhereQueryOptions, WrapperEntry } from "../@types/index";
8
+ import { STORE } from "./wrapper";
9
+ export default class Table<T = any> {
10
+ protected [STORE]: {
11
+ [K in keyof T]?: T[K];
12
+ };
13
+ constructor(data: InferAttributes<T>);
14
+ /** Serializar instancia a JSON plano */
15
+ toJSON(): Record<string, any>;
16
+ /** Guardar instancia (crear o actualizar) */
17
+ save(): Promise<this>;
18
+ /** Actualizar instancia */
19
+ update(patch: Partial<InferAttributes<T>>): Promise<this>;
20
+ /** Eliminar instancia */
21
+ destroy(): Promise<null>;
22
+ /**
23
+ * Crear un nuevo registro en la base de datos
24
+ */
25
+ static create<M extends Table>(this: {
26
+ new (data: InferAttributes<M>): M;
27
+ prototype: M;
28
+ }, data: InferAttributes<M>): Promise<M>;
29
+ /**
30
+ * Actualizar registros en la base de datos
31
+ * @param updates - Campos a actualizar. Los campos con valor `undefined` se ignoran.
32
+ * @param filters - Filtros para seleccionar los registros a actualizar
33
+ * @returns Número de registros actualizados
34
+ */
35
+ static update<M extends Table>(this: {
36
+ new (data: InferAttributes<M>): M;
37
+ prototype: M;
38
+ }, updates: Partial<InferAttributes<M>>, filters: Partial<InferAttributes<M>>): Promise<number>;
39
+ /**
40
+ * Eliminar registros de la base de datos
41
+ */
42
+ static delete<M extends Table>(this: {
43
+ new (data: InferAttributes<M>): M;
44
+ prototype: M;
45
+ }, filters: Partial<InferAttributes<M>>): Promise<number>;
46
+ /** Filtrar registros por campo igual a valor */
47
+ static where<M extends Table, K extends keyof InferAttributes<M>>(this: {
48
+ new (data: InferAttributes<M>): M;
49
+ prototype: M;
50
+ }, field: K, value: InferAttributes<M>[K] | InferAttributes<M>[K][]): Promise<M[]>;
51
+ /** Filtrar registros por campo con operador específico */
52
+ static where<M extends Table, K extends keyof InferAttributes<M>>(this: {
53
+ new (data: InferAttributes<M>): M;
54
+ prototype: M;
55
+ }, field: K, operator: QueryOperator, value: InferAttributes<M>[K] | InferAttributes<M>[K][]): Promise<M[]>;
56
+ /** Filtrar registros por múltiples campos (AND) */
57
+ static where<M extends Table>(this: {
58
+ new (data: InferAttributes<M>): M;
59
+ prototype: M;
60
+ }, filters: Partial<InferAttributes<M>>): Promise<M[]>;
61
+ /** Filtrar registros con opciones avanzadas */
62
+ static where<M extends Table>(this: {
63
+ new (data: InferAttributes<M>): M;
64
+ prototype: M;
65
+ }, filters: Partial<InferAttributes<M>>, options: WhereQueryOptions<M>): Promise<M[]>;
66
+ /**
67
+ * Obtener el primer registro que coincida con los filtros
68
+ */
69
+ static first<M extends Table, K extends keyof InferAttributes<M>>(this: {
70
+ new (data: InferAttributes<M>): M;
71
+ prototype: M;
72
+ }, field: K, value: InferAttributes<M>[K]): Promise<M | undefined>;
73
+ static first<M extends Table, K extends keyof InferAttributes<M>>(this: {
74
+ new (data: InferAttributes<M>): M;
75
+ prototype: M;
76
+ }, field: K, operator: QueryOperator, value: InferAttributes<M>[K] | InferAttributes<M>[K][]): Promise<M | undefined>;
77
+ static first<M extends Table>(this: {
78
+ new (data: InferAttributes<M>): M;
79
+ prototype: M;
80
+ }, filters: Partial<InferAttributes<M>>): Promise<M | undefined>;
81
+ /**
82
+ * Obtener el último registro que coincida con los filtros
83
+ */
84
+ static last<M extends Table, K extends keyof InferAttributes<M>>(this: {
85
+ new (data: InferAttributes<M>): M;
86
+ prototype: M;
87
+ }, field: K, value: InferAttributes<M>[K]): Promise<M | undefined>;
88
+ static last<M extends Table, K extends keyof InferAttributes<M>>(this: {
89
+ new (data: InferAttributes<M>): M;
90
+ prototype: M;
91
+ }, field: K, operator: QueryOperator, value: InferAttributes<M>[K] | InferAttributes<M>[K][]): Promise<M | undefined>;
92
+ static last<M extends Table>(this: {
93
+ new (data: InferAttributes<M>): M;
94
+ prototype: M;
95
+ }, filters: Partial<InferAttributes<M>>): Promise<M | undefined>;
96
+ }
97
+ export { STORE };
98
+ export type { WrapperEntry };