@stonyx/orm 0.3.2-beta.66 → 0.3.2-beta.68

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 CHANGED
@@ -13,7 +13,7 @@ A lightweight ORM for Stonyx projects, featuring model definitions, serializers,
13
13
  - **Models**: Define attributes with type-safe proxies (`attr`) and relationships (`hasMany`, `belongsTo`).
14
14
  - **Serializers**: Map raw data into model-friendly structures, including nested properties.
15
15
  - **Transforms**: Apply custom transformations on data values automatically.
16
- - **DB Integration**: Optional file-based persistence with auto-save support, or MySQL for production workloads.
16
+ - **DB Integration**: Optional file-based persistence with auto-save support, or MySQL/PostgreSQL/TimescaleDB/DynamoDB for production workloads.
17
17
  - **REST Server Integration**: Automatic route setup with customizable access control.
18
18
  - **Lifecycle Hooks**: Middleware-based before/after hooks for validation, authorization, side effects, and auditing.
19
19
 
@@ -65,13 +65,16 @@ const {
65
65
  MYSQL_DATABASE,
66
66
  MYSQL_CONNECTION_LIMIT,
67
67
  MYSQL_MIGRATIONS_DIR,
68
+ DYNAMODB_REGION,
69
+ DYNAMODB_ENDPOINT,
70
+ DYNAMODB_TABLE_PREFIX,
68
71
  } = process.env;
69
72
 
70
73
  export default {
71
74
  orm: {
72
75
  logColor: 'white',
73
76
  logMethod: 'db',
74
-
77
+
75
78
  db: {
76
79
  autosave: DB_AUTO_SAVE ?? 'false',
77
80
  file: DB_FILE ?? 'db.json',
@@ -96,6 +99,11 @@ export default {
96
99
  migrationsDir: MYSQL_MIGRATIONS_DIR ?? 'migrations',
97
100
  migrationsTable: '__migrations',
98
101
  } : undefined,
102
+ dynamodb: DYNAMODB_REGION ? {
103
+ region: DYNAMODB_REGION,
104
+ endpoint: DYNAMODB_ENDPOINT, // optional, for DynamoDB Local
105
+ tablePrefix: DYNAMODB_TABLE_PREFIX, // optional table name prefix
106
+ } : undefined,
99
107
  restServer: {
100
108
  enabled: ORM_USE_REST_SERVER ?? 'true',
101
109
  route: ORM_REST_ROUTE ?? '/'
@@ -243,6 +251,31 @@ Set the `MYSQL_HOST` environment variable to enable MySQL persistence. The ORM l
243
251
  | `stonyx db:migrate` | Apply pending migrations |
244
252
  | `stonyx db:migrate:rollback` | Rollback the most recent migration |
245
253
  | `stonyx db:migrate:status` | Show migration status |
254
+ | `stonyx db:sync` | Sync DynamoDB table definitions to match current model schemas |
255
+
256
+ ### DynamoDB Mode
257
+
258
+ Set the `DYNAMODB_REGION` environment variable to enable DynamoDB persistence. Tables are created with PAY_PER_REQUEST (on-demand) billing. Global Secondary Indexes (GSIs) are auto-provisioned at startup based on model `belongsTo` relationships — each FK column gets a GSI. `findAll()` with conditions routes to a GSI Query when the condition key matches a GSI partition key; non-indexed attribute conditions fall back to Scan + FilterExpression (expensive for large tables). ULID generation replaces auto-increment for numeric-ID models.
259
+
260
+ ```javascript
261
+ dynamodb: {
262
+ region: 'us-east-1',
263
+ endpoint: 'http://localhost:8000', // optional, for DynamoDB Local
264
+ tablePrefix: 'myapp-', // optional table name prefix
265
+ }
266
+ ```
267
+
268
+ Environment variables:
269
+
270
+ * `DYNAMODB_REGION`: AWS region for DynamoDB (e.g., `'us-east-1'`).
271
+ * `DYNAMODB_ENDPOINT`: Optional custom endpoint URL, useful for DynamoDB Local during development.
272
+ * `DYNAMODB_TABLE_PREFIX`: Optional prefix prepended to all table names (e.g., `'myapp-'` yields `'myapp-animals'`).
273
+
274
+ **Peer dependencies:** `@aws-sdk/client-dynamodb` and `@aws-sdk/lib-dynamodb` must be installed when using the DynamoDB driver. The AWS SDK is dynamically imported and only loaded when the DynamoDB driver is selected.
275
+
276
+ ```bash
277
+ npm install @aws-sdk/client-dynamodb @aws-sdk/lib-dynamodb
278
+ ```
246
279
 
247
280
  ### Running MySQL Tests
248
281
 
@@ -12,10 +12,12 @@ export interface DynamoDBConfig {
12
12
  export type DocumentClient = {
13
13
  send(command: unknown): Promise<unknown>;
14
14
  };
15
- export type DocumentClientConstructor = new (options: {
16
- client: unknown;
17
- }) => DocumentClient;
18
- export type DynamoDBClientConstructor = new (options: unknown) => unknown;
15
+ export type DynamoDBClientConstructor = new (options: unknown) => {
16
+ config: unknown;
17
+ };
18
+ export type DocumentClientFromFn = {
19
+ from(client: unknown): DocumentClient;
20
+ };
19
21
  /**
20
22
  * Create a DynamoDBDocumentClient from the given config.
21
23
  * Uses dynamic import so @aws-sdk/* are optional peer deps.
@@ -9,15 +9,15 @@
9
9
  * Uses dynamic import so @aws-sdk/* are optional peer deps.
10
10
  */
11
11
  export async function createDocumentClient(dbConfig) {
12
- const { DynamoDB } = await import('@aws-sdk/client-dynamodb');
13
- const { DynamoDBDocument } = await import('@aws-sdk/lib-dynamodb');
12
+ const { DynamoDBClient } = await import('@aws-sdk/client-dynamodb');
13
+ const { DynamoDBDocumentClient } = await import('@aws-sdk/lib-dynamodb');
14
14
  const clientOptions = {};
15
15
  if (dbConfig.region)
16
16
  clientOptions.region = dbConfig.region;
17
17
  if (dbConfig.endpoint)
18
18
  clientOptions.endpoint = dbConfig.endpoint;
19
- const rawClient = new DynamoDB(clientOptions);
20
- return new DynamoDBDocument({ client: rawClient });
19
+ const rawClient = new DynamoDBClient(clientOptions);
20
+ return DynamoDBDocumentClient.from(rawClient);
21
21
  }
22
22
  /**
23
23
  * Nullify the document client reference (DynamoDB connections are HTTP-based
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "stonyx-async",
5
5
  "stonyx-module"
6
6
  ],
7
- "version": "0.3.2-beta.66",
7
+ "version": "0.3.2-beta.68",
8
8
  "description": "",
9
9
  "main": "dist/index.js",
10
10
  "type": "module",
@@ -103,6 +103,7 @@
103
103
  "scripts": {
104
104
  "build": "tsc",
105
105
  "build:test": "tsc -p tsconfig.test.json",
106
- "test": "pnpm build && NODE_ENV=test node --import tsx/esm --import ./test/setup.ts node_modules/qunit/bin/qunit.js 'test/**/*-test.ts'"
106
+ "test": "pnpm build && NODE_ENV=test node --import tsx/esm --import ./test/setup.ts node_modules/qunit/bin/qunit.js 'test/**/*-test.ts'",
107
+ "test:dynamodb": "pnpm build && node --import tsx/esm --import ./test/integration/dynamodb/setup.ts node_modules/qunit/bin/qunit.js 'test/integration/dynamodb/**/*-test.ts'"
107
108
  }
108
109
  }
@@ -17,27 +17,27 @@ export type DocumentClient = {
17
17
  send(command: unknown): Promise<unknown>;
18
18
  };
19
19
 
20
- export type DocumentClientConstructor = new (options: { client: unknown }) => DocumentClient;
21
- export type DynamoDBClientConstructor = new (options: unknown) => unknown;
20
+ export type DynamoDBClientConstructor = new (options: unknown) => { config: unknown };
21
+ export type DocumentClientFromFn = { from(client: unknown): DocumentClient };
22
22
 
23
23
  /**
24
24
  * Create a DynamoDBDocumentClient from the given config.
25
25
  * Uses dynamic import so @aws-sdk/* are optional peer deps.
26
26
  */
27
27
  export async function createDocumentClient(dbConfig: DynamoDBConfig): Promise<DocumentClient> {
28
- const { DynamoDB } = await import('@aws-sdk/client-dynamodb' as string) as {
29
- DynamoDB: DynamoDBClientConstructor;
28
+ const { DynamoDBClient } = await import('@aws-sdk/client-dynamodb' as string) as {
29
+ DynamoDBClient: DynamoDBClientConstructor;
30
30
  };
31
- const { DynamoDBDocument } = await import('@aws-sdk/lib-dynamodb' as string) as {
32
- DynamoDBDocument: DocumentClientConstructor;
31
+ const { DynamoDBDocumentClient } = await import('@aws-sdk/lib-dynamodb' as string) as {
32
+ DynamoDBDocumentClient: DocumentClientFromFn;
33
33
  };
34
34
 
35
35
  const clientOptions: Record<string, unknown> = {};
36
36
  if (dbConfig.region) clientOptions.region = dbConfig.region;
37
37
  if (dbConfig.endpoint) clientOptions.endpoint = dbConfig.endpoint;
38
38
 
39
- const rawClient = new DynamoDB(clientOptions);
40
- return new DynamoDBDocument({ client: rawClient });
39
+ const rawClient = new DynamoDBClient(clientOptions);
40
+ return DynamoDBDocumentClient.from(rawClient);
41
41
  }
42
42
 
43
43
  /**