@miiajs/drizzle 0.1.0

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Ruslan Matiushev
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,17 @@
1
+ # @miiajs/drizzle
2
+
3
+ Drizzle ORM integration (PostgreSQL, MySQL, SQLite) for MiiaJS.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @miiajs/drizzle drizzle-orm
9
+ ```
10
+
11
+ ## Documentation
12
+
13
+ **[miiajs.com/docs/packages/drizzle](https://miiajs.com/docs/packages/drizzle)**
14
+
15
+ ## License
16
+
17
+ MIT
@@ -0,0 +1,9 @@
1
+ import { Logger } from '@miiajs/core';
2
+ import type { Dialect } from './types.js';
3
+ export interface ConnectionResult {
4
+ client: any;
5
+ createDb: (schema: Record<string, any>) => any;
6
+ }
7
+ export declare function createConnection(dialect: Dialect, url: string, logger: Logger, casing?: 'snake_case' | 'camelCase', pool?: Record<string, unknown>): Promise<ConnectionResult>;
8
+ export declare function closeConnection(dialect: Dialect, client: any): Promise<void>;
9
+ //# sourceMappingURL=connection.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connection.d.ts","sourceRoot":"","sources":["../src/connection.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA;AACrC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAA;AAEzC,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,GAAG,CAAA;IACX,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KAAK,GAAG,CAAA;CAC/C;AASD,wBAAsB,gBAAgB,CACpC,OAAO,EAAE,OAAO,EAChB,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,EACd,MAAM,CAAC,EAAE,YAAY,GAAG,WAAW,EACnC,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC7B,OAAO,CAAC,gBAAgB,CAAC,CAwC3B;AAED,wBAAsB,eAAe,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,CAYlF"}
@@ -0,0 +1,64 @@
1
+ import { Logger } from '@miiajs/core';
2
+ class DrizzleLogger {
3
+ logger;
4
+ constructor(logger) {
5
+ this.logger = logger;
6
+ }
7
+ logQuery(query, params) {
8
+ this.logger.debug(`${query} -- ${JSON.stringify(params)}`);
9
+ }
10
+ }
11
+ export async function createConnection(dialect, url, logger, casing, pool) {
12
+ const drizzleLogger = new DrizzleLogger(logger);
13
+ switch (dialect) {
14
+ case 'postgres': {
15
+ const postgresModule = await import('postgres');
16
+ const postgres = ('default' in postgresModule ? postgresModule.default : postgresModule);
17
+ const client = postgres(url, pool);
18
+ await client `SELECT 1`;
19
+ const { drizzle } = await import('drizzle-orm/postgres-js');
20
+ return {
21
+ client,
22
+ createDb: (schema) => drizzle(client, { schema, logger: drizzleLogger, casing }),
23
+ };
24
+ }
25
+ case 'mysql': {
26
+ // @ts-expect-error - mysql2 is an optional peer dependency
27
+ const mysql2 = await import('mysql2/promise');
28
+ const mysqlPool = mysql2.createPool({ uri: url, ...pool });
29
+ await mysqlPool.query('SELECT 1');
30
+ const { drizzle } = await import('drizzle-orm/mysql2');
31
+ return {
32
+ client: mysqlPool,
33
+ createDb: (schema) => drizzle(mysqlPool, { schema, mode: 'default', logger: drizzleLogger, casing }),
34
+ };
35
+ }
36
+ case 'sqlite': {
37
+ // @ts-expect-error - better-sqlite3 is an optional peer dependency
38
+ const Database = (await import('better-sqlite3')).default;
39
+ const sqlite = new Database(url);
40
+ sqlite.pragma('journal_mode');
41
+ const { drizzle } = await import('drizzle-orm/better-sqlite3');
42
+ return {
43
+ client: sqlite,
44
+ createDb: (schema) => drizzle(sqlite, { schema, logger: drizzleLogger, casing }),
45
+ };
46
+ }
47
+ default:
48
+ throw new Error(`[Miia/Drizzle] Unknown dialect: ${dialect}`);
49
+ }
50
+ }
51
+ export async function closeConnection(dialect, client) {
52
+ switch (dialect) {
53
+ case 'postgres':
54
+ await client.end();
55
+ break;
56
+ case 'mysql':
57
+ await client.end();
58
+ break;
59
+ case 'sqlite':
60
+ client.close();
61
+ break;
62
+ }
63
+ }
64
+ //# sourceMappingURL=connection.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connection.js","sourceRoot":"","sources":["../src/connection.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Default number of connection attempts before giving up.
3
+ * Override via DrizzleModuleOptions.connection.retry.attempts.
4
+ */
5
+ export declare const DEFAULT_RETRY_ATTEMPTS = 3;
6
+ /**
7
+ * Default delay (ms) between connection retries.
8
+ * Override via DrizzleModuleOptions.connection.retry.delay.
9
+ */
10
+ export declare const DEFAULT_RETRY_DELAY = 2000;
11
+ /**
12
+ * Node.js network error codes considered retryable during connection.
13
+ * Non-retryable errors (e.g. auth failure) abort immediately.
14
+ */
15
+ export declare const RETRYABLE_CODES: ReadonlySet<string>;
16
+ /** Logger context tag for this package. */
17
+ export declare const LOGGER_CONTEXT = "DrizzleModule";
18
+ //# sourceMappingURL=constants.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,eAAO,MAAM,sBAAsB,IAAI,CAAA;AAEvC;;;GAGG;AACH,eAAO,MAAM,mBAAmB,OAAQ,CAAA;AAExC;;;GAGG;AACH,eAAO,MAAM,eAAe,EAAE,WAAW,CAAC,MAAM,CAM9C,CAAA;AAEF,2CAA2C;AAC3C,eAAO,MAAM,cAAc,kBAAkB,CAAA"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Default number of connection attempts before giving up.
3
+ * Override via DrizzleModuleOptions.connection.retry.attempts.
4
+ */
5
+ export const DEFAULT_RETRY_ATTEMPTS = 3;
6
+ /**
7
+ * Default delay (ms) between connection retries.
8
+ * Override via DrizzleModuleOptions.connection.retry.delay.
9
+ */
10
+ export const DEFAULT_RETRY_DELAY = 2_000;
11
+ /**
12
+ * Node.js network error codes considered retryable during connection.
13
+ * Non-retryable errors (e.g. auth failure) abort immediately.
14
+ */
15
+ export const RETRYABLE_CODES = new Set([
16
+ 'ECONNREFUSED',
17
+ 'ECONNRESET',
18
+ 'ETIMEDOUT',
19
+ 'ENOTFOUND',
20
+ 'EAI_AGAIN',
21
+ ]);
22
+ /** Logger context tag for this package. */
23
+ export const LOGGER_CONTEXT = 'DrizzleModule';
24
+ //# sourceMappingURL=constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,CAAA;AAEvC;;;GAGG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,KAAK,CAAA;AAExC;;;GAGG;AACH,MAAM,CAAC,MAAM,eAAe,GAAwB,IAAI,GAAG,CAAC;IAC1D,cAAc;IACd,YAAY;IACZ,WAAW;IACX,WAAW;IACX,WAAW;CACZ,CAAC,CAAA;AAEF,2CAA2C;AAC3C,MAAM,CAAC,MAAM,cAAc,GAAG,eAAe,CAAA"}
@@ -0,0 +1,6 @@
1
+ import type { ConfiguredModule, OptionsOrFactory } from '@miiajs/core';
2
+ import type { DrizzleModuleOptions } from './types.js';
3
+ export declare class DrizzleModule {
4
+ static configure(optionsOrFactory: OptionsOrFactory<DrizzleModuleOptions>, name?: string): ConfiguredModule;
5
+ }
6
+ //# sourceMappingURL=drizzle.module.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"drizzle.module.d.ts","sourceRoot":"","sources":["../src/drizzle.module.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAgC,gBAAgB,EAAE,MAAM,cAAc,CAAA;AAEpG,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAA;AAyCtD,qBAAa,aAAa;IACxB,MAAM,CAAC,SAAS,CAAC,gBAAgB,EAAE,gBAAgB,CAAC,oBAAoB,CAAC,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,gBAAgB;CAiC5G"}
@@ -0,0 +1,69 @@
1
+ import { resolveOptions } from '@miiajs/core';
2
+ import { DrizzleService } from './drizzle.service.js';
3
+ import { drizzleDb, getInternalServiceToken } from './tokens.js';
4
+ // ─── Lazy proxies ────────────────────────────────────────────────────────────
5
+ // DrizzleService.onInit happens AFTER provider factories run, so we can't return
6
+ // a real db handle from the factory. The proxy defers underlying lookup until
7
+ // first property access.
8
+ function createLazyProxy(get) {
9
+ let cached;
10
+ const resolve = () => (cached ??= get());
11
+ return new Proxy({}, {
12
+ get(_, prop) {
13
+ const target = resolve();
14
+ const value = target[prop];
15
+ return typeof value === 'function' ? value.bind(target) : value;
16
+ },
17
+ has(_, prop) {
18
+ return prop in resolve();
19
+ },
20
+ ownKeys() {
21
+ return Reflect.ownKeys(resolve());
22
+ },
23
+ getOwnPropertyDescriptor(_, prop) {
24
+ return Object.getOwnPropertyDescriptor(resolve(), prop);
25
+ },
26
+ });
27
+ }
28
+ // ─── Friendly error helper ───────────────────────────────────────────────────
29
+ function configureMissingError(name, suffix) {
30
+ return new Error(`[Miia/Drizzle] ${suffix} ` +
31
+ `DrizzleModule.configure() is missing in the root module${name ? ` for connection "${name}"` : ''}.`);
32
+ }
33
+ // ─── DrizzleModule ───────────────────────────────────────────────────────────
34
+ export class DrizzleModule {
35
+ static configure(optionsOrFactory, name) {
36
+ const serviceToken = getInternalServiceToken(name);
37
+ const dbToken = drizzleDb(name);
38
+ const ModuleClass = name ? class DrizzleNamedModule {
39
+ } : DrizzleModule;
40
+ return {
41
+ module: ModuleClass,
42
+ providers: [
43
+ {
44
+ token: serviceToken,
45
+ factory: (resolve) => {
46
+ const options = resolveOptions(optionsOrFactory, { resolve });
47
+ return new DrizzleService(options);
48
+ },
49
+ },
50
+ {
51
+ token: dbToken,
52
+ factory: (resolve) => {
53
+ return createLazyProxy(() => {
54
+ let service;
55
+ try {
56
+ service = resolve(serviceToken);
57
+ }
58
+ catch {
59
+ throw configureMissingError(name, `inject(drizzleDb(${name ? `'${name}'` : ''})) failed:`);
60
+ }
61
+ return service.db;
62
+ });
63
+ },
64
+ },
65
+ ],
66
+ };
67
+ }
68
+ }
69
+ //# sourceMappingURL=drizzle.module.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"drizzle.module.js","sourceRoot":"","sources":["../src/drizzle.module.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AAE7C,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AACrD,OAAO,EAAE,SAAS,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAA;AAEhE,gFAAgF;AAChF,iFAAiF;AACjF,8EAA8E;AAC9E,yBAAyB;AAEzB,SAAS,eAAe,CAAmB,GAAY;IACrD,IAAI,MAAqB,CAAA;IACzB,MAAM,OAAO,GAAG,GAAG,EAAE,CAAC,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC,CAAA;IACxC,OAAO,IAAI,KAAK,CAAC,EAAO,EAAE;QACxB,GAAG,CAAC,CAAC,EAAE,IAAI;YACT,MAAM,MAAM,GAAG,OAAO,EAAS,CAAA;YAC/B,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,CAAA;YAC1B,OAAO,OAAO,KAAK,KAAK,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK,CAAA;QACjE,CAAC;QACD,GAAG,CAAC,CAAC,EAAE,IAAI;YACT,OAAO,IAAI,IAAK,OAAO,EAAU,CAAA;QACnC,CAAC;QACD,OAAO;YACL,OAAO,OAAO,CAAC,OAAO,CAAC,OAAO,EAAS,CAAC,CAAA;QAC1C,CAAC;QACD,wBAAwB,CAAC,CAAC,EAAE,IAAI;YAC9B,OAAO,MAAM,CAAC,wBAAwB,CAAC,OAAO,EAAS,EAAE,IAAI,CAAC,CAAA;QAChE,CAAC;KACF,CAAC,CAAA;AACJ,CAAC;AAED,gFAAgF;AAEhF,SAAS,qBAAqB,CAAC,IAAwB,EAAE,MAAc;IACrE,OAAO,IAAI,KAAK,CACd,kBAAkB,MAAM,GAAG;QACzB,0DAA0D,IAAI,CAAC,CAAC,CAAC,oBAAoB,IAAI,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,CACvG,CAAA;AACH,CAAC;AAED,gFAAgF;AAEhF,MAAM,OAAO,aAAa;IACxB,MAAM,CAAC,SAAS,CAAC,gBAAwD,EAAE,IAAa;QACtF,MAAM,YAAY,GAAG,uBAAuB,CAAC,IAAI,CAAC,CAAA;QAClD,MAAM,OAAO,GAAG,SAAS,CAAC,IAAI,CAAC,CAAA;QAE/B,MAAM,WAAW,GAAG,IAAI,CAAC,CAAC,CAAE,MAAM,kBAAkB;SAAmB,CAAC,CAAC,CAAC,aAAa,CAAA;QAEvF,OAAO;YACL,MAAM,EAAE,WAAW;YACnB,SAAS,EAAE;gBACT;oBACE,KAAK,EAAE,YAAY;oBACnB,OAAO,EAAE,CAAC,OAAO,EAAE,EAAE;wBACnB,MAAM,OAAO,GAAG,cAAc,CAAC,gBAAgB,EAAE,EAAE,OAAO,EAAE,CAAC,CAAA;wBAC7D,OAAO,IAAI,cAAc,CAAC,OAAO,CAAC,CAAA;oBACpC,CAAC;iBACwB;gBAC3B;oBACE,KAAK,EAAE,OAAO;oBACd,OAAO,EAAE,CAAC,OAAO,EAAE,EAAE;wBACnB,OAAO,eAAe,CAAS,GAAG,EAAE;4BAClC,IAAI,OAAuB,CAAA;4BAC3B,IAAI,CAAC;gCACH,OAAO,GAAG,OAAO,CAAiB,YAAY,CAAC,CAAA;4BACjD,CAAC;4BAAC,MAAM,CAAC;gCACP,MAAM,qBAAqB,CAAC,IAAI,EAAE,oBAAoB,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,GAAG,CAAC,CAAC,CAAC,EAAE,YAAY,CAAC,CAAA;4BAC5F,CAAC;4BACD,OAAO,OAAO,CAAC,EAAY,CAAA;wBAC7B,CAAC,CAAC,CAAA;oBACJ,CAAC;iBACwB;aAC5B;SACF,CAAA;IACH,CAAC;CACF"}
@@ -0,0 +1,17 @@
1
+ import type { DrizzleModuleOptions } from './types.js';
2
+ /**
3
+ * Internal lifecycle owner for a DrizzleModule connection. NOT exported from the
4
+ * package index. Users interact with @miiajs/drizzle through `inject(db)` where
5
+ * `db = drizzleDb<TDb>()`.
6
+ */
7
+ export declare class DrizzleService {
8
+ private readonly options;
9
+ private logger;
10
+ private client;
11
+ private _db;
12
+ constructor(options: DrizzleModuleOptions);
13
+ get db(): any;
14
+ onInit(): Promise<void>;
15
+ onDestroy(): Promise<void>;
16
+ }
17
+ //# sourceMappingURL=drizzle.service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"drizzle.service.d.ts","sourceRoot":"","sources":["../src/drizzle.service.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAA;AAItD;;;;GAIG;AACH,qBAAa,cAAc;IAKb,OAAO,CAAC,QAAQ,CAAC,OAAO;IAJpC,OAAO,CAAC,MAAM,CAA6B;IAC3C,OAAO,CAAC,MAAM,CAAY;IAC1B,OAAO,CAAC,GAAG,CAAY;gBAEM,OAAO,EAAE,oBAAoB;IAE1D,IAAI,EAAE,IAAI,GAAG,CAKZ;IAEK,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;IAgDvB,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;CASjC"}
@@ -0,0 +1,70 @@
1
+ import { Logger } from '@miiajs/core';
2
+ import { createConnection, closeConnection } from './connection.js';
3
+ import { DEFAULT_RETRY_ATTEMPTS, DEFAULT_RETRY_DELAY, LOGGER_CONTEXT, RETRYABLE_CODES } from './constants.js';
4
+ /**
5
+ * Internal lifecycle owner for a DrizzleModule connection. NOT exported from the
6
+ * package index. Users interact with @miiajs/drizzle through `inject(db)` where
7
+ * `db = drizzleDb<TDb>()`.
8
+ */
9
+ export class DrizzleService {
10
+ options;
11
+ logger = new Logger(LOGGER_CONTEXT);
12
+ client = null;
13
+ _db = null;
14
+ constructor(options) {
15
+ this.options = options;
16
+ }
17
+ get db() {
18
+ if (!this._db) {
19
+ throw new Error('[Miia/Drizzle] Not connected. Ensure app.init() was called.');
20
+ }
21
+ return this._db;
22
+ }
23
+ async onInit() {
24
+ const attempts = this.options.connection.retry?.attempts ?? DEFAULT_RETRY_ATTEMPTS;
25
+ const delay = this.options.connection.retry?.delay ?? DEFAULT_RETRY_DELAY;
26
+ for (let i = 1; i <= attempts; i++) {
27
+ let client = null;
28
+ try {
29
+ const conn = await createConnection(this.options.dialect, this.options.connection.url, this.logger, this.options.casing, this.options.connection.pool);
30
+ client = conn.client;
31
+ const db = conn.createDb(this.options.schema ?? {});
32
+ this.client = client;
33
+ this._db = db;
34
+ return;
35
+ }
36
+ catch (error) {
37
+ // Resource leak fix: close client if connect succeeded but a later
38
+ // step (createDb, etc) failed.
39
+ if (client) {
40
+ try {
41
+ await closeConnection(this.options.dialect, client);
42
+ }
43
+ catch {
44
+ // swallow - we're already in an error path
45
+ }
46
+ this.client = null;
47
+ this._db = null;
48
+ }
49
+ const code = error?.code ?? error?.cause?.code;
50
+ const retryable = code && RETRYABLE_CODES.has(code);
51
+ if (!retryable || i === attempts) {
52
+ this.logger.error(retryable ? `Failed to connect after ${attempts} attempts` : `Connection failed: ${error.message}`, error.stack);
53
+ throw error;
54
+ }
55
+ this.logger.error(`Database connection failed. Retrying (${i}/${attempts})...`);
56
+ await new Promise((resolve) => setTimeout(resolve, delay));
57
+ }
58
+ }
59
+ }
60
+ async onDestroy() {
61
+ this.logger.log('Disconnecting from database...');
62
+ if (this.client) {
63
+ await closeConnection(this.options.dialect, this.client);
64
+ }
65
+ this._db = null;
66
+ this.client = null;
67
+ this.logger.log('Disconnected from database');
68
+ }
69
+ }
70
+ //# sourceMappingURL=drizzle.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"drizzle.service.js","sourceRoot":"","sources":["../src/drizzle.service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ export { DrizzleModule } from './drizzle.module.js';
2
+ export { drizzleDb } from './tokens.js';
3
+ export type { Dialect, DrizzleModuleOptions, DrizzleDbToken } from './types.js';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AACnD,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AACvC,YAAY,EAAE,OAAO,EAAE,oBAAoB,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,3 @@
1
+ export { DrizzleModule } from './drizzle.module.js';
2
+ export { drizzleDb } from './tokens.js';
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AACnD,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA"}
@@ -0,0 +1,21 @@
1
+ export type DrizzleDbToken<TDb = any> = new () => TDb;
2
+ /**
3
+ * Returns a typed DI token for the Drizzle database of a DrizzleModule connection.
4
+ *
5
+ * - `drizzleDb()` - default connection.
6
+ * - `drizzleDb('analytics')` - named connection.
7
+ *
8
+ * The generic parameter is the concrete Drizzle database type for autocomplete:
9
+ *
10
+ * export const db = drizzleDb<PostgresJsDatabase<typeof schema>>()
11
+ * export const analytics = drizzleDb<PostgresJsDatabase<typeof analyticsSchema>>('analytics')
12
+ *
13
+ * Memoization is by `name` only. The generic is compile-time - the runtime token
14
+ * returned for a given name is identical across different `TDb` instantiations.
15
+ * As a consequence, `drizzleDb<X>()` in one file and `drizzleDb<Y>()` in another
16
+ * resolve to the same DI token but project different TypeScript types at each
17
+ * call site. Keep a single `db.ts` per connection as the source of truth.
18
+ */
19
+ export declare function drizzleDb<TDb = any>(name?: string): DrizzleDbToken<TDb>;
20
+ export declare function getInternalServiceToken(name?: string): string;
21
+ //# sourceMappingURL=tokens.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tokens.d.ts","sourceRoot":"","sources":["../src/tokens.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,cAAc,CAAC,GAAG,GAAG,GAAG,IAAI,UAAU,GAAG,CAAA;AAIrD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,SAAS,CAAC,GAAG,GAAG,GAAG,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,cAAc,CAAC,GAAG,CAAC,CAUvE;AAID,wBAAgB,uBAAuB,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAE7D"}
package/dist/tokens.js ADDED
@@ -0,0 +1,34 @@
1
+ const cache = new Map();
2
+ /**
3
+ * Returns a typed DI token for the Drizzle database of a DrizzleModule connection.
4
+ *
5
+ * - `drizzleDb()` - default connection.
6
+ * - `drizzleDb('analytics')` - named connection.
7
+ *
8
+ * The generic parameter is the concrete Drizzle database type for autocomplete:
9
+ *
10
+ * export const db = drizzleDb<PostgresJsDatabase<typeof schema>>()
11
+ * export const analytics = drizzleDb<PostgresJsDatabase<typeof analyticsSchema>>('analytics')
12
+ *
13
+ * Memoization is by `name` only. The generic is compile-time - the runtime token
14
+ * returned for a given name is identical across different `TDb` instantiations.
15
+ * As a consequence, `drizzleDb<X>()` in one file and `drizzleDb<Y>()` in another
16
+ * resolve to the same DI token but project different TypeScript types at each
17
+ * call site. Keep a single `db.ts` per connection as the source of truth.
18
+ */
19
+ export function drizzleDb(name) {
20
+ const key = name ?? '';
21
+ let cls = cache.get(key);
22
+ if (!cls) {
23
+ cls = class {
24
+ static __name = `drizzleDb(${name ?? 'default'})`;
25
+ };
26
+ cache.set(key, cls);
27
+ }
28
+ return cls;
29
+ }
30
+ // ─── Internal token helpers (not exported from package index) ─────────────
31
+ export function getInternalServiceToken(name) {
32
+ return name ? `__DRIZZLE_SERVICE_${name}` : '__DRIZZLE_SERVICE';
33
+ }
34
+ //# sourceMappingURL=tokens.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tokens.js","sourceRoot":"","sources":["../src/tokens.ts"],"names":[],"mappings":"AAEA,MAAM,KAAK,GAAG,IAAI,GAAG,EAAmC,CAAA;AAExD;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,SAAS,CAAY,IAAa;IAChD,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAA;IACtB,IAAI,GAAG,GAAG,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;IACxB,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,GAAG,GAAG;YACJ,MAAM,CAAU,MAAM,GAAG,aAAa,IAAI,IAAI,SAAS,GAAG,CAAA;SACrB,CAAA;QACvC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,CAAA;IACrB,CAAC;IACD,OAAO,GAA0B,CAAA;AACnC,CAAC;AAED,6EAA6E;AAE7E,MAAM,UAAU,uBAAuB,CAAC,IAAa;IACnD,OAAO,IAAI,CAAC,CAAC,CAAC,qBAAqB,IAAI,EAAE,CAAC,CAAC,CAAC,mBAAmB,CAAA;AACjE,CAAC"}
@@ -0,0 +1,16 @@
1
+ export type Dialect = 'postgres' | 'mysql' | 'sqlite';
2
+ export interface DrizzleModuleOptions {
3
+ dialect: Dialect;
4
+ connection: {
5
+ url: string;
6
+ pool?: Record<string, unknown>;
7
+ retry?: {
8
+ attempts?: number;
9
+ delay?: number;
10
+ };
11
+ };
12
+ schema?: Record<string, unknown>;
13
+ casing?: 'snake_case' | 'camelCase';
14
+ }
15
+ export type { DrizzleDbToken } from './tokens.js';
16
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,OAAO,GAAG,UAAU,GAAG,OAAO,GAAG,QAAQ,CAAA;AAErD,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,OAAO,CAAA;IAChB,UAAU,EAAE;QACV,GAAG,EAAE,MAAM,CAAA;QACX,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;QAC9B,KAAK,CAAC,EAAE;YACN,QAAQ,CAAC,EAAE,MAAM,CAAA;YACjB,KAAK,CAAC,EAAE,MAAM,CAAA;SACf,CAAA;KACF,CAAA;IACD,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAChC,MAAM,CAAC,EAAE,YAAY,GAAG,WAAW,CAAA;CACpC;AAED,YAAY,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
package/package.json ADDED
@@ -0,0 +1,75 @@
1
+ {
2
+ "name": "@miiajs/drizzle",
3
+ "version": "0.1.0",
4
+ "author": "Ruslan Matiushev",
5
+ "license": "MIT",
6
+ "description": "Drizzle ORM integration for MiiaJS (PostgreSQL, MySQL, SQLite).",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/miiajs/miia.git",
10
+ "directory": "packages/drizzle"
11
+ },
12
+ "homepage": "https://github.com/miiajs/miia/tree/main/packages/drizzle#readme",
13
+ "bugs": {
14
+ "url": "https://github.com/miiajs/miia/issues"
15
+ },
16
+ "keywords": [
17
+ "miiajs",
18
+ "miia",
19
+ "drizzle",
20
+ "orm",
21
+ "postgres",
22
+ "mysql",
23
+ "sqlite"
24
+ ],
25
+ "publishConfig": {
26
+ "access": "public"
27
+ },
28
+ "type": "module",
29
+ "exports": {
30
+ ".": {
31
+ "types": "./dist/index.d.ts",
32
+ "import": "./dist/index.js"
33
+ }
34
+ },
35
+ "main": "./dist/index.js",
36
+ "types": "./dist/index.d.ts",
37
+ "files": [
38
+ "dist",
39
+ "README.md",
40
+ "LICENSE"
41
+ ],
42
+ "sideEffects": false,
43
+ "engines": {
44
+ "node": ">=22.22.1",
45
+ "bun": ">=1.3.11",
46
+ "deno": ">=2.6.1"
47
+ },
48
+ "dependencies": {
49
+ "@miiajs/core": "workspace:*"
50
+ },
51
+ "peerDependencies": {
52
+ "better-sqlite3": "^11.0.0",
53
+ "drizzle-orm": ">=0.45.2 <1.0.0",
54
+ "mysql2": "^3.0.0",
55
+ "postgres": "^3.0.0"
56
+ },
57
+ "peerDependenciesMeta": {
58
+ "better-sqlite3": {
59
+ "optional": true
60
+ },
61
+ "mysql2": {
62
+ "optional": true
63
+ },
64
+ "postgres": {
65
+ "optional": true
66
+ }
67
+ },
68
+ "scripts": {
69
+ "build": "tsc --build",
70
+ "clean": "tsc --build --clean"
71
+ },
72
+ "devDependencies": {
73
+ "drizzle-orm": "^0.45.2"
74
+ }
75
+ }