@moriajs/db 0.3.5 → 0.4.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/.turbo/turbo-build.log +1 -1
- package/dist/index.d.ts +45 -45
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +137 -67
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +38 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +38 -0
- package/dist/types.js.map +1 -0
- package/package.json +4 -3
- package/src/index.ts +158 -75
- package/src/types.ts +64 -0
package/.turbo/turbo-build.log
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -1,25 +1,21 @@
|
|
|
1
|
-
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
* Database-agnostic adapter layer built on Kysely.
|
|
5
|
-
* Default: PostgreSQL (production), SQLite (development).
|
|
6
|
-
* Designed to work with kysely-schema for schema-first development.
|
|
7
|
-
*/
|
|
8
|
-
import { Kysely } from 'kysely';
|
|
1
|
+
import { MoriaDB, MoriaDBAdapter } from './types.js';
|
|
2
|
+
export * from './types.js';
|
|
9
3
|
/**
|
|
10
4
|
* Supported database adapters.
|
|
11
5
|
*/
|
|
12
|
-
export type
|
|
6
|
+
export type DatabaseAdapterName = 'pg' | 'sqlite' | 'mysql';
|
|
13
7
|
/**
|
|
14
8
|
* Configuration for creating a database connection.
|
|
15
9
|
*/
|
|
16
10
|
export interface DatabaseConfig {
|
|
17
|
-
/** Database adapter to use */
|
|
18
|
-
adapter:
|
|
19
|
-
/** Connection URL (for pg/mysql) */
|
|
11
|
+
/** Database adapter name to use */
|
|
12
|
+
adapter: DatabaseAdapterName;
|
|
13
|
+
/** Connection URL (for pg/mysql/pongo) */
|
|
20
14
|
url?: string;
|
|
21
15
|
/** File path (for sqlite) */
|
|
22
16
|
filename?: string;
|
|
17
|
+
/** Whether to use Pongo (Document API) instead of Kysely (SQL API) for Postgres */
|
|
18
|
+
usePongo?: boolean;
|
|
23
19
|
/** Connection pool size */
|
|
24
20
|
pool?: {
|
|
25
21
|
min?: number;
|
|
@@ -27,45 +23,49 @@ export interface DatabaseConfig {
|
|
|
27
23
|
};
|
|
28
24
|
}
|
|
29
25
|
/**
|
|
30
|
-
*
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
26
|
+
* Kysely Adapter Implementation (SQL)
|
|
27
|
+
*/
|
|
28
|
+
export declare class KyselyAdapter implements MoriaDBAdapter {
|
|
29
|
+
private config;
|
|
30
|
+
private db;
|
|
31
|
+
constructor(config: DatabaseConfig);
|
|
32
|
+
connect(): Promise<void>;
|
|
33
|
+
disconnect(): Promise<void>;
|
|
34
|
+
private createDialect;
|
|
35
|
+
find<T>(collection: string, filter?: any): Promise<T[]>;
|
|
36
|
+
findOne<T>(collection: string, filter?: any): Promise<T | null>;
|
|
37
|
+
insertOne<T>(collection: string, data: any): Promise<T>;
|
|
38
|
+
updateOne(collection: string, filter: any, data: any): Promise<void>;
|
|
39
|
+
deleteOne(collection: string, filter: any): Promise<void>;
|
|
40
|
+
raw<T>(): T;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Pongo Adapter Implementation (Document Store on Postgres)
|
|
44
|
+
*/
|
|
45
|
+
export declare class PongoAdapter implements MoriaDBAdapter {
|
|
46
|
+
private config;
|
|
47
|
+
private client;
|
|
48
|
+
constructor(config: DatabaseConfig);
|
|
49
|
+
connect(): Promise<void>;
|
|
50
|
+
disconnect(): Promise<void>;
|
|
51
|
+
find<T extends Record<string, any> = any>(collection: string, filter?: any): Promise<T[]>;
|
|
52
|
+
findOne<T extends Record<string, any> = any>(collection: string, filter?: any): Promise<T | null>;
|
|
53
|
+
insertOne<T extends Record<string, any> = any>(collection: string, data: any): Promise<T>;
|
|
54
|
+
updateOne(collection: string, filter: any, data: any): Promise<void>;
|
|
55
|
+
deleteOne(collection: string, filter: any): Promise<void>;
|
|
56
|
+
raw<T>(): T;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Factory to create a MoriaDB instance.
|
|
46
60
|
*/
|
|
47
|
-
export declare function createDatabase
|
|
61
|
+
export declare function createDatabase(config: DatabaseConfig): Promise<MoriaDB>;
|
|
48
62
|
/**
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
* @example
|
|
52
|
-
* ```ts
|
|
53
|
-
* import { createApp } from '@moriajs/core';
|
|
54
|
-
* import { createDatabasePlugin } from '@moriajs/db';
|
|
55
|
-
*
|
|
56
|
-
* const app = await createApp();
|
|
57
|
-
* await app.use(createDatabasePlugin({
|
|
58
|
-
* adapter: 'sqlite',
|
|
59
|
-
* filename: './dev.db',
|
|
60
|
-
* }));
|
|
61
|
-
* ```
|
|
63
|
+
* MoriaJS database plugin for Fastify integration.
|
|
62
64
|
*/
|
|
63
65
|
export declare function createDatabasePlugin(config: DatabaseConfig): {
|
|
64
66
|
name: string;
|
|
65
67
|
register({ server }: {
|
|
66
|
-
server:
|
|
67
|
-
decorate: (key: string, value: unknown) => void;
|
|
68
|
-
};
|
|
68
|
+
server: any;
|
|
69
69
|
}): Promise<void>;
|
|
70
70
|
};
|
|
71
71
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -1,81 +1,148 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @moriajs/db
|
|
3
|
-
*
|
|
4
|
-
* Database-agnostic adapter layer built on Kysely.
|
|
5
|
-
* Default: PostgreSQL (production), SQLite (development).
|
|
6
|
-
* Designed to work with kysely-schema for schema-first development.
|
|
7
|
-
*/
|
|
8
1
|
import { Kysely, PostgresDialect, SqliteDialect } from 'kysely';
|
|
2
|
+
import { pongoClient } from '@event-driven-io/pongo';
|
|
3
|
+
import { MoriaDB } from './types.js';
|
|
4
|
+
export * from './types.js';
|
|
9
5
|
/**
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* @example
|
|
13
|
-
* ```ts
|
|
14
|
-
* // Production (PostgreSQL)
|
|
15
|
-
* const db = await createDatabase({
|
|
16
|
-
* adapter: 'pg',
|
|
17
|
-
* url: process.env.DATABASE_URL,
|
|
18
|
-
* });
|
|
19
|
-
*
|
|
20
|
-
* // Development (SQLite)
|
|
21
|
-
* const db = await createDatabase({
|
|
22
|
-
* adapter: 'sqlite',
|
|
23
|
-
* filename: './dev.db',
|
|
24
|
-
* });
|
|
25
|
-
* ```
|
|
6
|
+
* Kysely Adapter Implementation (SQL)
|
|
26
7
|
*/
|
|
27
|
-
export
|
|
28
|
-
|
|
29
|
-
|
|
8
|
+
export class KyselyAdapter {
|
|
9
|
+
config;
|
|
10
|
+
db = null;
|
|
11
|
+
constructor(config) {
|
|
12
|
+
this.config = config;
|
|
13
|
+
}
|
|
14
|
+
async connect() {
|
|
15
|
+
const dialect = await this.createDialect(this.config);
|
|
16
|
+
this.db = new Kysely({ dialect });
|
|
17
|
+
}
|
|
18
|
+
async disconnect() {
|
|
19
|
+
if (this.db) {
|
|
20
|
+
await this.db.destroy();
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
async createDialect(config) {
|
|
24
|
+
switch (config.adapter) {
|
|
25
|
+
case 'pg': {
|
|
26
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-explicit-any
|
|
27
|
+
const pg = globalThis.require('pg');
|
|
28
|
+
return new PostgresDialect({
|
|
29
|
+
pool: new pg.Pool({
|
|
30
|
+
connectionString: config.url,
|
|
31
|
+
min: config.pool?.min ?? 2,
|
|
32
|
+
max: config.pool?.max ?? 10,
|
|
33
|
+
}),
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
case 'sqlite': {
|
|
37
|
+
const BetterSqlite3Module = await import('better-sqlite3');
|
|
38
|
+
const BetterSqlite3 = BetterSqlite3Module.default;
|
|
39
|
+
return new SqliteDialect({
|
|
40
|
+
database: new BetterSqlite3(config.filename ?? ':memory:'),
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
default:
|
|
44
|
+
throw new Error(`@moriajs/db: Unsupported Kysely adapter "${config.adapter}"`);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
async find(collection, filter = {}) {
|
|
48
|
+
let query = this.db.selectFrom(collection).selectAll();
|
|
49
|
+
for (const [key, value] of Object.entries(filter)) {
|
|
50
|
+
query = query.where(key, '=', value);
|
|
51
|
+
}
|
|
52
|
+
return await query.execute();
|
|
53
|
+
}
|
|
54
|
+
async findOne(collection, filter = {}) {
|
|
55
|
+
let query = this.db.selectFrom(collection).selectAll();
|
|
56
|
+
for (const [key, value] of Object.entries(filter)) {
|
|
57
|
+
query = query.where(key, '=', value);
|
|
58
|
+
}
|
|
59
|
+
const result = await query.limit(1).executeTakeFirst();
|
|
60
|
+
return result || null;
|
|
61
|
+
}
|
|
62
|
+
async insertOne(collection, data) {
|
|
63
|
+
const result = await this.db
|
|
64
|
+
.insertInto(collection)
|
|
65
|
+
.values(data)
|
|
66
|
+
.returningAll()
|
|
67
|
+
.executeTakeFirstOrThrow();
|
|
68
|
+
return result;
|
|
69
|
+
}
|
|
70
|
+
async updateOne(collection, filter, data) {
|
|
71
|
+
let query = this.db.updateTable(collection).set(data);
|
|
72
|
+
for (const [key, value] of Object.entries(filter)) {
|
|
73
|
+
query = query.where(key, '=', value);
|
|
74
|
+
}
|
|
75
|
+
await query.execute();
|
|
76
|
+
}
|
|
77
|
+
async deleteOne(collection, filter) {
|
|
78
|
+
let query = this.db.deleteFrom(collection);
|
|
79
|
+
for (const [key, value] of Object.entries(filter)) {
|
|
80
|
+
query = query.where(key, '=', value);
|
|
81
|
+
}
|
|
82
|
+
await query.execute();
|
|
83
|
+
}
|
|
84
|
+
raw() {
|
|
85
|
+
return this.db;
|
|
86
|
+
}
|
|
30
87
|
}
|
|
31
88
|
/**
|
|
32
|
-
*
|
|
89
|
+
* Pongo Adapter Implementation (Document Store on Postgres)
|
|
33
90
|
*/
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
min: config.pool?.min ?? 2,
|
|
44
|
-
max: config.pool?.max ?? 10,
|
|
45
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
46
|
-
}),
|
|
47
|
-
});
|
|
48
|
-
}
|
|
49
|
-
case 'sqlite': {
|
|
50
|
-
// Dynamic import — better-sqlite3 is an optional dependency
|
|
51
|
-
const BetterSqlite3Module = await import('better-sqlite3');
|
|
52
|
-
const BetterSqlite3 = BetterSqlite3Module.default;
|
|
53
|
-
return new SqliteDialect({
|
|
54
|
-
database: new BetterSqlite3(config.filename ?? ':memory:'),
|
|
55
|
-
});
|
|
91
|
+
export class PongoAdapter {
|
|
92
|
+
config;
|
|
93
|
+
client = null;
|
|
94
|
+
constructor(config) {
|
|
95
|
+
this.config = config;
|
|
96
|
+
}
|
|
97
|
+
async connect() {
|
|
98
|
+
if (!this.config.url) {
|
|
99
|
+
throw new Error('@moriajs/db: PostgreSQL connection URL is required for Pongo');
|
|
56
100
|
}
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
101
|
+
this.client = pongoClient(this.config.url);
|
|
102
|
+
await this.client.connect();
|
|
103
|
+
}
|
|
104
|
+
async disconnect() {
|
|
105
|
+
if (this.client) {
|
|
106
|
+
await this.client.close();
|
|
60
107
|
}
|
|
61
|
-
|
|
62
|
-
|
|
108
|
+
}
|
|
109
|
+
async find(collection, filter = {}) {
|
|
110
|
+
return await this.client.db().collection(collection).find(filter);
|
|
111
|
+
}
|
|
112
|
+
async findOne(collection, filter = {}) {
|
|
113
|
+
return await this.client.db().collection(collection).findOne(filter);
|
|
114
|
+
}
|
|
115
|
+
async insertOne(collection, data) {
|
|
116
|
+
const result = await this.client.db().collection(collection).insertOne(data);
|
|
117
|
+
return result;
|
|
118
|
+
}
|
|
119
|
+
async updateOne(collection, filter, data) {
|
|
120
|
+
await this.client.db().collection(collection).updateOne(filter, { $set: data });
|
|
121
|
+
}
|
|
122
|
+
async deleteOne(collection, filter) {
|
|
123
|
+
await this.client.db().collection(collection).deleteOne(filter);
|
|
124
|
+
}
|
|
125
|
+
raw() {
|
|
126
|
+
return this.client;
|
|
63
127
|
}
|
|
64
128
|
}
|
|
65
129
|
/**
|
|
66
|
-
*
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
130
|
+
* Factory to create a MoriaDB instance.
|
|
131
|
+
*/
|
|
132
|
+
export async function createDatabase(config) {
|
|
133
|
+
let adapter;
|
|
134
|
+
if (config.usePongo && config.adapter === 'pg') {
|
|
135
|
+
adapter = new PongoAdapter(config);
|
|
136
|
+
}
|
|
137
|
+
else {
|
|
138
|
+
adapter = new KyselyAdapter(config);
|
|
139
|
+
}
|
|
140
|
+
const db = new MoriaDB(adapter);
|
|
141
|
+
await db.connect();
|
|
142
|
+
return db;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* MoriaJS database plugin for Fastify integration.
|
|
79
146
|
*/
|
|
80
147
|
export function createDatabasePlugin(config) {
|
|
81
148
|
return {
|
|
@@ -83,6 +150,9 @@ export function createDatabasePlugin(config) {
|
|
|
83
150
|
async register({ server }) {
|
|
84
151
|
const db = await createDatabase(config);
|
|
85
152
|
server.decorate('db', db);
|
|
153
|
+
server.addHook('onClose', async () => {
|
|
154
|
+
await db.disconnect();
|
|
155
|
+
});
|
|
86
156
|
},
|
|
87
157
|
};
|
|
88
158
|
}
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MoriaDB Agnostic Interface
|
|
3
|
+
*/
|
|
4
|
+
export interface MoriaDBAdapter {
|
|
5
|
+
/** Connect to the database */
|
|
6
|
+
connect(): Promise<void>;
|
|
7
|
+
/** Close the database connection */
|
|
8
|
+
disconnect(): Promise<void>;
|
|
9
|
+
/** Find multiple documents/rows */
|
|
10
|
+
find<T extends Record<string, any>>(collection: string, filter: any): Promise<T[]>;
|
|
11
|
+
/** Find a single document/row */
|
|
12
|
+
findOne<T extends Record<string, any>>(collection: string, filter: any): Promise<T | null>;
|
|
13
|
+
/** Insert one document/row */
|
|
14
|
+
insertOne<T extends Record<string, any>>(collection: string, data: any): Promise<T>;
|
|
15
|
+
/** Update documents/rows */
|
|
16
|
+
updateOne(collection: string, filter: any, data: any): Promise<void>;
|
|
17
|
+
/** Delete documents/rows */
|
|
18
|
+
deleteOne(collection: string, filter: any): Promise<void>;
|
|
19
|
+
/** Get the raw underlying driver instance (Kysely, Pongo, etc.) */
|
|
20
|
+
raw<T>(): T;
|
|
21
|
+
}
|
|
22
|
+
export declare class MoriaDB {
|
|
23
|
+
private adapter;
|
|
24
|
+
constructor(adapter: MoriaDBAdapter);
|
|
25
|
+
connect(): Promise<void>;
|
|
26
|
+
disconnect(): Promise<void>;
|
|
27
|
+
find<T extends Record<string, any>>(collection: string, filter?: any): Promise<T[]>;
|
|
28
|
+
findOne<T extends Record<string, any>>(collection: string, filter?: any): Promise<T | null>;
|
|
29
|
+
insertOne<T extends Record<string, any>>(collection: string, data: any): Promise<T>;
|
|
30
|
+
updateOne(collection: string, filter: any, data: any): Promise<void>;
|
|
31
|
+
deleteOne(collection: string, filter: any): Promise<void>;
|
|
32
|
+
/**
|
|
33
|
+
* Access the raw underlying driver instance.
|
|
34
|
+
* Use this when you need library-specific features.
|
|
35
|
+
*/
|
|
36
|
+
raw<T>(): T;
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,WAAW,cAAc;IAC3B,8BAA8B;IAC9B,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACzB,oCAAoC;IACpC,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAE5B,mCAAmC;IACnC,IAAI,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC;IACnF,iCAAiC;IACjC,OAAO,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,GAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;IAC3F,8BAA8B;IAC9B,SAAS,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IACpF,4BAA4B;IAC5B,SAAS,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACrE,4BAA4B;IAC5B,SAAS,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE1D,mEAAmE;IACnE,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC;CACf;AAED,qBAAa,OAAO;IACJ,OAAO,CAAC,OAAO;gBAAP,OAAO,EAAE,cAAc;IAErC,OAAO;IAIP,UAAU;IAIV,IAAI,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,GAAE,GAAQ,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC;IAIvF,OAAO,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,GAAE,GAAQ,GAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC;IAI/F,SAAS,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,GAAG,OAAO,CAAC,CAAC,CAAC;IAInF,SAAS,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC;IAIpE,SAAS,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC;IAI/D;;;OAGG;IACH,GAAG,CAAC,CAAC,KAAK,CAAC;CAGd"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MoriaDB Agnostic Interface
|
|
3
|
+
*/
|
|
4
|
+
export class MoriaDB {
|
|
5
|
+
adapter;
|
|
6
|
+
constructor(adapter) {
|
|
7
|
+
this.adapter = adapter;
|
|
8
|
+
}
|
|
9
|
+
async connect() {
|
|
10
|
+
return this.adapter.connect();
|
|
11
|
+
}
|
|
12
|
+
async disconnect() {
|
|
13
|
+
return this.adapter.disconnect();
|
|
14
|
+
}
|
|
15
|
+
async find(collection, filter = {}) {
|
|
16
|
+
return this.adapter.find(collection, filter);
|
|
17
|
+
}
|
|
18
|
+
async findOne(collection, filter = {}) {
|
|
19
|
+
return this.adapter.findOne(collection, filter);
|
|
20
|
+
}
|
|
21
|
+
async insertOne(collection, data) {
|
|
22
|
+
return this.adapter.insertOne(collection, data);
|
|
23
|
+
}
|
|
24
|
+
async updateOne(collection, filter, data) {
|
|
25
|
+
return this.adapter.updateOne(collection, filter, data);
|
|
26
|
+
}
|
|
27
|
+
async deleteOne(collection, filter) {
|
|
28
|
+
return this.adapter.deleteOne(collection, filter);
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Access the raw underlying driver instance.
|
|
32
|
+
* Use this when you need library-specific features.
|
|
33
|
+
*/
|
|
34
|
+
raw() {
|
|
35
|
+
return this.adapter.raw();
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAuBH,MAAM,OAAO,OAAO;IACI;IAApB,YAAoB,OAAuB;QAAvB,YAAO,GAAP,OAAO,CAAgB;IAAI,CAAC;IAEhD,KAAK,CAAC,OAAO;QACT,OAAO,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;IAClC,CAAC;IAED,KAAK,CAAC,UAAU;QACZ,OAAO,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC;IACrC,CAAC;IAED,KAAK,CAAC,IAAI,CAAgC,UAAkB,EAAE,SAAc,EAAE;QAC1E,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,CAAI,UAAU,EAAE,MAAM,CAAC,CAAC;IACpD,CAAC;IAED,KAAK,CAAC,OAAO,CAAgC,UAAkB,EAAE,SAAc,EAAE;QAC7E,OAAO,IAAI,CAAC,OAAO,CAAC,OAAO,CAAI,UAAU,EAAE,MAAM,CAAC,CAAC;IACvD,CAAC;IAED,KAAK,CAAC,SAAS,CAAgC,UAAkB,EAAE,IAAS;QACxE,OAAO,IAAI,CAAC,OAAO,CAAC,SAAS,CAAI,UAAU,EAAE,IAAI,CAAC,CAAC;IACvD,CAAC;IAED,KAAK,CAAC,SAAS,CAAC,UAAkB,EAAE,MAAW,EAAE,IAAS;QACtD,OAAO,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC;IAC5D,CAAC;IAED,KAAK,CAAC,SAAS,CAAC,UAAkB,EAAE,MAAW;QAC3C,OAAO,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;IACtD,CAAC;IAED;;;OAGG;IACH,GAAG;QACC,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,EAAK,CAAC;IACjC,CAAC;CACJ"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@moriajs/db",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "MoriaJS database — Kysely adapters with kysely-schema integration",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -12,7 +12,8 @@
|
|
|
12
12
|
}
|
|
13
13
|
},
|
|
14
14
|
"dependencies": {
|
|
15
|
-
"kysely": "^0.27.0"
|
|
15
|
+
"kysely": "^0.27.0",
|
|
16
|
+
"@event-driven-io/pongo": "^0.16.11"
|
|
16
17
|
},
|
|
17
18
|
"optionalDependencies": {
|
|
18
19
|
"pg": "^8.13.0",
|
|
@@ -25,7 +26,7 @@
|
|
|
25
26
|
"@types/better-sqlite3": "^7.6.0"
|
|
26
27
|
},
|
|
27
28
|
"peerDependencies": {
|
|
28
|
-
"@moriajs/core": "0.
|
|
29
|
+
"@moriajs/core": "0.4.0"
|
|
29
30
|
},
|
|
30
31
|
"license": "MIT",
|
|
31
32
|
"author": "Guntur-D <guntur.d.npm@gmail.com>",
|
package/src/index.ts
CHANGED
|
@@ -1,28 +1,26 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @moriajs/db
|
|
3
|
-
*
|
|
4
|
-
* Database-agnostic adapter layer built on Kysely.
|
|
5
|
-
* Default: PostgreSQL (production), SQLite (development).
|
|
6
|
-
* Designed to work with kysely-schema for schema-first development.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
1
|
import { Kysely, PostgresDialect, SqliteDialect } from 'kysely';
|
|
2
|
+
import { pongoClient, PongoClient } from '@event-driven-io/pongo';
|
|
3
|
+
import { MoriaDB, MoriaDBAdapter } from './types.js';
|
|
4
|
+
|
|
5
|
+
export * from './types.js';
|
|
10
6
|
|
|
11
7
|
/**
|
|
12
8
|
* Supported database adapters.
|
|
13
9
|
*/
|
|
14
|
-
export type
|
|
10
|
+
export type DatabaseAdapterName = 'pg' | 'sqlite' | 'mysql';
|
|
15
11
|
|
|
16
12
|
/**
|
|
17
13
|
* Configuration for creating a database connection.
|
|
18
14
|
*/
|
|
19
15
|
export interface DatabaseConfig {
|
|
20
|
-
/** Database adapter to use */
|
|
21
|
-
adapter:
|
|
22
|
-
/** Connection URL (for pg/mysql) */
|
|
16
|
+
/** Database adapter name to use */
|
|
17
|
+
adapter: DatabaseAdapterName;
|
|
18
|
+
/** Connection URL (for pg/mysql/pongo) */
|
|
23
19
|
url?: string;
|
|
24
20
|
/** File path (for sqlite) */
|
|
25
21
|
filename?: string;
|
|
22
|
+
/** Whether to use Pongo (Document API) instead of Kysely (SQL API) for Postgres */
|
|
23
|
+
usePongo?: boolean;
|
|
26
24
|
/** Connection pool size */
|
|
27
25
|
pool?: {
|
|
28
26
|
min?: number;
|
|
@@ -31,89 +29,174 @@ export interface DatabaseConfig {
|
|
|
31
29
|
}
|
|
32
30
|
|
|
33
31
|
/**
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
* @example
|
|
37
|
-
* ```ts
|
|
38
|
-
* // Production (PostgreSQL)
|
|
39
|
-
* const db = await createDatabase({
|
|
40
|
-
* adapter: 'pg',
|
|
41
|
-
* url: process.env.DATABASE_URL,
|
|
42
|
-
* });
|
|
43
|
-
*
|
|
44
|
-
* // Development (SQLite)
|
|
45
|
-
* const db = await createDatabase({
|
|
46
|
-
* adapter: 'sqlite',
|
|
47
|
-
* filename: './dev.db',
|
|
48
|
-
* });
|
|
49
|
-
* ```
|
|
32
|
+
* Kysely Adapter Implementation (SQL)
|
|
50
33
|
*/
|
|
51
|
-
export
|
|
52
|
-
|
|
53
|
-
|
|
34
|
+
export class KyselyAdapter implements MoriaDBAdapter {
|
|
35
|
+
private db: Kysely<any> | null = null;
|
|
36
|
+
|
|
37
|
+
constructor(private config: DatabaseConfig) { }
|
|
38
|
+
|
|
39
|
+
async connect(): Promise<void> {
|
|
40
|
+
const dialect = await this.createDialect(this.config);
|
|
41
|
+
this.db = new Kysely<any>({ dialect });
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
async disconnect(): Promise<void> {
|
|
45
|
+
if (this.db) {
|
|
46
|
+
await this.db.destroy();
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
private async createDialect(config: DatabaseConfig) {
|
|
51
|
+
switch (config.adapter) {
|
|
52
|
+
case 'pg': {
|
|
53
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-explicit-any
|
|
54
|
+
const pg = (globalThis as any).require('pg') as { Pool: new (opts: Record<string, unknown>) => unknown };
|
|
55
|
+
return new PostgresDialect({
|
|
56
|
+
pool: new pg.Pool({
|
|
57
|
+
connectionString: config.url,
|
|
58
|
+
min: config.pool?.min ?? 2,
|
|
59
|
+
max: config.pool?.max ?? 10,
|
|
60
|
+
}) as any,
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
case 'sqlite': {
|
|
64
|
+
const BetterSqlite3Module = await import('better-sqlite3');
|
|
65
|
+
const BetterSqlite3 = BetterSqlite3Module.default;
|
|
66
|
+
return new SqliteDialect({
|
|
67
|
+
database: new BetterSqlite3(config.filename ?? ':memory:'),
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
default:
|
|
71
|
+
throw new Error(`@moriajs/db: Unsupported Kysely adapter "${config.adapter}"`);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
async find<T>(collection: string, filter: any = {}): Promise<T[]> {
|
|
76
|
+
let query = this.db!.selectFrom(collection).selectAll();
|
|
77
|
+
for (const [key, value] of Object.entries(filter)) {
|
|
78
|
+
query = query.where(key as any, '=', value as any);
|
|
79
|
+
}
|
|
80
|
+
return await query.execute() as T[];
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
async findOne<T>(collection: string, filter: any = {}): Promise<T | null> {
|
|
84
|
+
let query = this.db!.selectFrom(collection).selectAll();
|
|
85
|
+
for (const [key, value] of Object.entries(filter)) {
|
|
86
|
+
query = query.where(key as any, '=', value as any);
|
|
87
|
+
}
|
|
88
|
+
const result = await query.limit(1).executeTakeFirst();
|
|
89
|
+
return (result as T) || null;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
async insertOne<T>(collection: string, data: any): Promise<T> {
|
|
93
|
+
const result = await this.db!
|
|
94
|
+
.insertInto(collection)
|
|
95
|
+
.values(data)
|
|
96
|
+
.returningAll()
|
|
97
|
+
.executeTakeFirstOrThrow();
|
|
98
|
+
return result as T;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
async updateOne(collection: string, filter: any, data: any): Promise<void> {
|
|
102
|
+
let query = this.db!.updateTable(collection).set(data);
|
|
103
|
+
for (const [key, value] of Object.entries(filter)) {
|
|
104
|
+
query = query.where(key as any, '=', value as any);
|
|
105
|
+
}
|
|
106
|
+
await query.execute();
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
async deleteOne(collection: string, filter: any): Promise<void> {
|
|
110
|
+
let query = this.db!.deleteFrom(collection);
|
|
111
|
+
for (const [key, value] of Object.entries(filter)) {
|
|
112
|
+
query = query.where(key as any, '=', value as any);
|
|
113
|
+
}
|
|
114
|
+
await query.execute();
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
raw<T>(): T {
|
|
118
|
+
return this.db as unknown as T;
|
|
119
|
+
}
|
|
54
120
|
}
|
|
55
121
|
|
|
56
122
|
/**
|
|
57
|
-
*
|
|
123
|
+
* Pongo Adapter Implementation (Document Store on Postgres)
|
|
58
124
|
*/
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
case 'pg': {
|
|
62
|
-
// Dynamic import — pg is an optional dependency
|
|
63
|
-
// eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-explicit-any
|
|
64
|
-
const pg = (globalThis as any).require('pg') as { Pool: new (opts: Record<string, unknown>) => unknown };
|
|
65
|
-
return new PostgresDialect({
|
|
66
|
-
pool: new pg.Pool({
|
|
67
|
-
connectionString: config.url,
|
|
68
|
-
min: config.pool?.min ?? 2,
|
|
69
|
-
max: config.pool?.max ?? 10,
|
|
70
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
71
|
-
}) as any,
|
|
72
|
-
});
|
|
73
|
-
}
|
|
125
|
+
export class PongoAdapter implements MoriaDBAdapter {
|
|
126
|
+
private client: PongoClient | null = null;
|
|
74
127
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
database: new BetterSqlite3(config.filename ?? ':memory:'),
|
|
81
|
-
});
|
|
128
|
+
constructor(private config: DatabaseConfig) { }
|
|
129
|
+
|
|
130
|
+
async connect(): Promise<void> {
|
|
131
|
+
if (!this.config.url) {
|
|
132
|
+
throw new Error('@moriajs/db: PostgreSQL connection URL is required for Pongo');
|
|
82
133
|
}
|
|
134
|
+
this.client = pongoClient(this.config.url);
|
|
135
|
+
await this.client.connect();
|
|
136
|
+
}
|
|
83
137
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
'Contributions welcome!'
|
|
88
|
-
);
|
|
138
|
+
async disconnect(): Promise<void> {
|
|
139
|
+
if (this.client) {
|
|
140
|
+
await this.client.close();
|
|
89
141
|
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
async find<T extends Record<string, any> = any>(collection: string, filter: any = {}): Promise<T[]> {
|
|
145
|
+
return await this.client!.db().collection<T>(collection).find(filter) as any;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
async findOne<T extends Record<string, any> = any>(collection: string, filter: any = {}): Promise<T | null> {
|
|
149
|
+
return await this.client!.db().collection<T>(collection).findOne(filter) as any;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
async insertOne<T extends Record<string, any> = any>(collection: string, data: any): Promise<T> {
|
|
153
|
+
const result = await this.client!.db().collection<T>(collection).insertOne(data);
|
|
154
|
+
return result as unknown as T;
|
|
155
|
+
}
|
|
90
156
|
|
|
91
|
-
|
|
92
|
-
|
|
157
|
+
async updateOne(collection: string, filter: any, data: any): Promise<void> {
|
|
158
|
+
await this.client!.db().collection(collection).updateOne(filter, { $set: data });
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
async deleteOne(collection: string, filter: any): Promise<void> {
|
|
162
|
+
await this.client!.db().collection(collection).deleteOne(filter);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
raw<T>(): T {
|
|
166
|
+
return this.client as unknown as T;
|
|
93
167
|
}
|
|
94
168
|
}
|
|
95
169
|
|
|
96
170
|
/**
|
|
97
|
-
*
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
171
|
+
* Factory to create a MoriaDB instance.
|
|
172
|
+
*/
|
|
173
|
+
export async function createDatabase(config: DatabaseConfig): Promise<MoriaDB> {
|
|
174
|
+
let adapter: MoriaDBAdapter;
|
|
175
|
+
|
|
176
|
+
if (config.usePongo && config.adapter === 'pg') {
|
|
177
|
+
adapter = new PongoAdapter(config);
|
|
178
|
+
} else {
|
|
179
|
+
adapter = new KyselyAdapter(config);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
const db = new MoriaDB(adapter);
|
|
183
|
+
await db.connect();
|
|
184
|
+
return db;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* MoriaJS database plugin for Fastify integration.
|
|
110
189
|
*/
|
|
111
190
|
export function createDatabasePlugin(config: DatabaseConfig) {
|
|
112
191
|
return {
|
|
113
192
|
name: '@moriajs/db',
|
|
114
|
-
async register({ server }: { server:
|
|
193
|
+
async register({ server }: { server: any }) {
|
|
115
194
|
const db = await createDatabase(config);
|
|
116
195
|
server.decorate('db', db);
|
|
196
|
+
|
|
197
|
+
server.addHook('onClose', async () => {
|
|
198
|
+
await db.disconnect();
|
|
199
|
+
});
|
|
117
200
|
},
|
|
118
201
|
};
|
|
119
202
|
}
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MoriaDB Agnostic Interface
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export interface MoriaDBAdapter {
|
|
6
|
+
/** Connect to the database */
|
|
7
|
+
connect(): Promise<void>;
|
|
8
|
+
/** Close the database connection */
|
|
9
|
+
disconnect(): Promise<void>;
|
|
10
|
+
|
|
11
|
+
/** Find multiple documents/rows */
|
|
12
|
+
find<T extends Record<string, any>>(collection: string, filter: any): Promise<T[]>;
|
|
13
|
+
/** Find a single document/row */
|
|
14
|
+
findOne<T extends Record<string, any>>(collection: string, filter: any): Promise<T | null>;
|
|
15
|
+
/** Insert one document/row */
|
|
16
|
+
insertOne<T extends Record<string, any>>(collection: string, data: any): Promise<T>;
|
|
17
|
+
/** Update documents/rows */
|
|
18
|
+
updateOne(collection: string, filter: any, data: any): Promise<void>;
|
|
19
|
+
/** Delete documents/rows */
|
|
20
|
+
deleteOne(collection: string, filter: any): Promise<void>;
|
|
21
|
+
|
|
22
|
+
/** Get the raw underlying driver instance (Kysely, Pongo, etc.) */
|
|
23
|
+
raw<T>(): T;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export class MoriaDB {
|
|
27
|
+
constructor(private adapter: MoriaDBAdapter) { }
|
|
28
|
+
|
|
29
|
+
async connect() {
|
|
30
|
+
return this.adapter.connect();
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
async disconnect() {
|
|
34
|
+
return this.adapter.disconnect();
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
async find<T extends Record<string, any>>(collection: string, filter: any = {}): Promise<T[]> {
|
|
38
|
+
return this.adapter.find<T>(collection, filter);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
async findOne<T extends Record<string, any>>(collection: string, filter: any = {}): Promise<T | null> {
|
|
42
|
+
return this.adapter.findOne<T>(collection, filter);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
async insertOne<T extends Record<string, any>>(collection: string, data: any): Promise<T> {
|
|
46
|
+
return this.adapter.insertOne<T>(collection, data);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
async updateOne(collection: string, filter: any, data: any): Promise<void> {
|
|
50
|
+
return this.adapter.updateOne(collection, filter, data);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
async deleteOne(collection: string, filter: any): Promise<void> {
|
|
54
|
+
return this.adapter.deleteOne(collection, filter);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Access the raw underlying driver instance.
|
|
59
|
+
* Use this when you need library-specific features.
|
|
60
|
+
*/
|
|
61
|
+
raw<T>(): T {
|
|
62
|
+
return this.adapter.raw<T>();
|
|
63
|
+
}
|
|
64
|
+
}
|