@fragno-dev/test 0.1.4 → 0.1.5
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 +11 -7
- package/CHANGELOG.md +8 -0
- package/dist/adapters.d.ts +32 -0
- package/dist/adapters.d.ts.map +1 -0
- package/dist/adapters.js +204 -0
- package/dist/adapters.js.map +1 -0
- package/dist/index.d.ts +17 -16
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +50 -43
- package/dist/index.js.map +1 -1
- package/package.json +27 -2
- package/src/adapters.ts +379 -0
- package/src/index.test.ts +157 -29
- package/src/index.ts +120 -83
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
> @fragno-dev/test@0.1.
|
|
2
|
+
> @fragno-dev/test@0.1.5 build /home/runner/work/fragno/fragno/packages/fragno-test
|
|
3
3
|
> tsdown
|
|
4
4
|
|
|
5
5
|
[34mℹ[39m tsdown [2mv0.15.11[22m powered by rolldown [2mv1.0.0-beta.45[22m
|
|
@@ -7,9 +7,13 @@
|
|
|
7
7
|
[34mℹ[39m entry: [34msrc/index.ts[39m
|
|
8
8
|
[34mℹ[39m tsconfig: [34mtsconfig.json[39m
|
|
9
9
|
[34mℹ[39m Build start
|
|
10
|
-
[34mℹ[39m [2mdist/[22m[1mindex.js[22m
|
|
11
|
-
[34mℹ[39m [2mdist/[
|
|
12
|
-
[34mℹ[39m [2mdist/[22mindex.
|
|
13
|
-
[34mℹ[39m [2mdist/[
|
|
14
|
-
[34mℹ[39m
|
|
15
|
-
[
|
|
10
|
+
[34mℹ[39m [2mdist/[22m[1mindex.js[22m [2m 2.55 kB[22m [2m│ gzip: 0.80 kB[22m
|
|
11
|
+
[34mℹ[39m [2mdist/[22madapters.js.map [2m15.32 kB[22m [2m│ gzip: 3.52 kB[22m
|
|
12
|
+
[34mℹ[39m [2mdist/[22mindex.js.map [2m 8.80 kB[22m [2m│ gzip: 2.50 kB[22m
|
|
13
|
+
[34mℹ[39m [2mdist/[22madapters.js [2m 6.36 kB[22m [2m│ gzip: 1.52 kB[22m
|
|
14
|
+
[34mℹ[39m [2mdist/[22mindex.d.ts.map [2m 1.60 kB[22m [2m│ gzip: 0.76 kB[22m
|
|
15
|
+
[34mℹ[39m [2mdist/[22madapters.d.ts.map [2m 0.85 kB[22m [2m│ gzip: 0.40 kB[22m
|
|
16
|
+
[34mℹ[39m [2mdist/[22m[32m[1mindex.d.ts[22m[39m [2m 2.98 kB[22m [2m│ gzip: 0.82 kB[22m
|
|
17
|
+
[34mℹ[39m [2mdist/[22m[32madapters.d.ts[39m [2m 1.16 kB[22m [2m│ gzip: 0.40 kB[22m
|
|
18
|
+
[34mℹ[39m 8 files, total: 39.61 kB
|
|
19
|
+
[32m✔[39m Build complete in [32m9111ms[39m
|
package/CHANGELOG.md
CHANGED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { Kysely } from "kysely";
|
|
2
|
+
import { drizzle } from "drizzle-orm/pglite";
|
|
3
|
+
import { AnySchema } from "@fragno-dev/db/schema";
|
|
4
|
+
import { DatabaseAdapter } from "@fragno-dev/db/adapters";
|
|
5
|
+
|
|
6
|
+
//#region src/adapters.d.ts
|
|
7
|
+
interface KyselySqliteAdapter {
|
|
8
|
+
type: "kysely-sqlite";
|
|
9
|
+
}
|
|
10
|
+
interface KyselyPgliteAdapter {
|
|
11
|
+
type: "kysely-pglite";
|
|
12
|
+
databasePath?: string;
|
|
13
|
+
}
|
|
14
|
+
interface DrizzlePgliteAdapter {
|
|
15
|
+
type: "drizzle-pglite";
|
|
16
|
+
databasePath?: string;
|
|
17
|
+
}
|
|
18
|
+
type SupportedAdapter = KyselySqliteAdapter | KyselyPgliteAdapter | DrizzlePgliteAdapter;
|
|
19
|
+
type TestContext<T extends SupportedAdapter> = T extends KyselySqliteAdapter | KyselyPgliteAdapter ? {
|
|
20
|
+
readonly kysely: Kysely<any>;
|
|
21
|
+
readonly adapter: DatabaseAdapter<any>;
|
|
22
|
+
resetDatabase: () => Promise<void>;
|
|
23
|
+
cleanup: () => Promise<void>;
|
|
24
|
+
} : T extends DrizzlePgliteAdapter ? {
|
|
25
|
+
readonly drizzle: ReturnType<typeof drizzle<any>>;
|
|
26
|
+
readonly adapter: DatabaseAdapter<any>;
|
|
27
|
+
resetDatabase: () => Promise<void>;
|
|
28
|
+
cleanup: () => Promise<void>;
|
|
29
|
+
} : never;
|
|
30
|
+
//#endregion
|
|
31
|
+
export { DrizzlePgliteAdapter, KyselyPgliteAdapter, KyselySqliteAdapter, SupportedAdapter, TestContext };
|
|
32
|
+
//# sourceMappingURL=adapters.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapters.d.ts","names":[],"sources":["../src/adapters.ts"],"sourcesContent":[],"mappings":";;;;;;UAeiB,mBAAA;;AAAjB;AAIiB,UAAA,mBAAA,CAAmB;EAKnB,IAAA,EAAA,eAAA;EAKL,YAAA,CAAA,EAAA,MAAgB;;AAAyB,UALpC,oBAAA,CAKoC;EAAsB,IAAA,EAAA,gBAAA;EAAoB,YAAA,CAAA,EAAA,MAAA;AAG/F;AAAkC,KAHtB,gBAAA,GAAmB,mBAGG,GAHmB,mBAGnB,GAHyC,oBAGzC;AAAoB,KAA1C,WAA0C,CAAA,UAApB,gBAAoB,CAAA,GAAA,CAAA,SAClD,mBADkD,GAElD,mBAFkD,GAAA;EAClD,SAAA,MAAA,EAGmB,MAHnB,CAAA,GAAA,CAAA;EACA,SAAA,OAAA,EAGoB,eAHpB,CAAA,GAAA,CAAA;EAEmB,aAAA,EAAA,GAAA,GAEI,OAFJ,CAAA,IAAA,CAAA;EACC,OAAA,EAAA,GAAA,GAEH,OAFG,CAAA,IAAA,CAAA;CACG,GAGvB,CAHuB,SAGb,oBAHa,GAAA;EACN,SAAA,OAAA,EAIK,UAJL,CAAA,OAIuB,OAJvB,CAAA,GAAA,CAAA,CAAA;EAEjB,SAAA,OAAA,EAGsB,eAHtB,CAAA,GAAA,CAAA;EAAU,aAAA,EAAA,GAAA,GAIe,OAJf,CAAA,IAAA,CAAA;EAE8B,OAAA,EAAA,GAAA,GAGrB,OAHqB,CAAA,IAAA,CAAA;CAAlB,GAAA,KAAA"}
|
package/dist/adapters.js
ADDED
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
import { Kysely } from "kysely";
|
|
3
|
+
import { SQLocalKysely } from "sqlocal/kysely";
|
|
4
|
+
import { KyselyPGlite } from "kysely-pglite";
|
|
5
|
+
import { drizzle } from "drizzle-orm/pglite";
|
|
6
|
+
import { PGlite } from "@electric-sql/pglite";
|
|
7
|
+
import { KyselyAdapter } from "@fragno-dev/db/adapters/kysely";
|
|
8
|
+
import { DrizzleAdapter } from "@fragno-dev/db/adapters/drizzle";
|
|
9
|
+
import { mkdir, rm, writeFile } from "node:fs/promises";
|
|
10
|
+
import { join } from "node:path";
|
|
11
|
+
import { existsSync } from "node:fs";
|
|
12
|
+
|
|
13
|
+
//#region src/adapters.ts
|
|
14
|
+
/**
|
|
15
|
+
* Create Kysely + SQLite adapter using SQLocalKysely (always in-memory)
|
|
16
|
+
*/
|
|
17
|
+
async function createKyselySqliteAdapter(_config, schema, namespace, migrateToVersion) {
|
|
18
|
+
const createDatabase = async () => {
|
|
19
|
+
const { dialect } = new SQLocalKysely(":memory:");
|
|
20
|
+
const kysely$1 = new Kysely({ dialect });
|
|
21
|
+
const adapter$1 = new KyselyAdapter({
|
|
22
|
+
db: kysely$1,
|
|
23
|
+
provider: "sqlite"
|
|
24
|
+
});
|
|
25
|
+
const migrator = adapter$1.createMigrationEngine(schema, namespace);
|
|
26
|
+
await (migrateToVersion ? await migrator.prepareMigrationTo(migrateToVersion, { updateSettings: false }) : await migrator.prepareMigration({ updateSettings: false })).execute();
|
|
27
|
+
return {
|
|
28
|
+
kysely: kysely$1,
|
|
29
|
+
adapter: adapter$1
|
|
30
|
+
};
|
|
31
|
+
};
|
|
32
|
+
let { kysely, adapter } = await createDatabase();
|
|
33
|
+
const resetDatabase = async () => {
|
|
34
|
+
await kysely.destroy();
|
|
35
|
+
const newDb = await createDatabase();
|
|
36
|
+
kysely = newDb.kysely;
|
|
37
|
+
adapter = newDb.adapter;
|
|
38
|
+
};
|
|
39
|
+
const cleanup = async () => {
|
|
40
|
+
await kysely.destroy();
|
|
41
|
+
};
|
|
42
|
+
return {
|
|
43
|
+
testContext: {
|
|
44
|
+
get kysely() {
|
|
45
|
+
return kysely;
|
|
46
|
+
},
|
|
47
|
+
get adapter() {
|
|
48
|
+
return adapter;
|
|
49
|
+
},
|
|
50
|
+
resetDatabase,
|
|
51
|
+
cleanup
|
|
52
|
+
},
|
|
53
|
+
get adapter() {
|
|
54
|
+
return adapter;
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Create Kysely + PGLite adapter using kysely-pglite
|
|
60
|
+
*/
|
|
61
|
+
async function createKyselyPgliteAdapter(config, schema, namespace, migrateToVersion) {
|
|
62
|
+
const databasePath = config.databasePath;
|
|
63
|
+
const createDatabase = async () => {
|
|
64
|
+
const kyselyPglite$1 = await KyselyPGlite.create(databasePath);
|
|
65
|
+
const kysely$1 = new Kysely({ dialect: kyselyPglite$1.dialect });
|
|
66
|
+
const adapter$1 = new KyselyAdapter({
|
|
67
|
+
db: kysely$1,
|
|
68
|
+
provider: "postgresql"
|
|
69
|
+
});
|
|
70
|
+
const migrator = adapter$1.createMigrationEngine(schema, namespace);
|
|
71
|
+
await (migrateToVersion ? await migrator.prepareMigrationTo(migrateToVersion, { updateSettings: false }) : await migrator.prepareMigration({ updateSettings: false })).execute();
|
|
72
|
+
return {
|
|
73
|
+
kysely: kysely$1,
|
|
74
|
+
adapter: adapter$1,
|
|
75
|
+
kyselyPglite: kyselyPglite$1
|
|
76
|
+
};
|
|
77
|
+
};
|
|
78
|
+
let { kysely, adapter, kyselyPglite } = await createDatabase();
|
|
79
|
+
const resetDatabase = async () => {
|
|
80
|
+
await kysely.destroy();
|
|
81
|
+
try {
|
|
82
|
+
await kyselyPglite.client.close();
|
|
83
|
+
} catch {}
|
|
84
|
+
const newDb = await createDatabase();
|
|
85
|
+
kysely = newDb.kysely;
|
|
86
|
+
adapter = newDb.adapter;
|
|
87
|
+
kyselyPglite = newDb.kyselyPglite;
|
|
88
|
+
};
|
|
89
|
+
const cleanup = async () => {
|
|
90
|
+
await kysely.destroy();
|
|
91
|
+
try {
|
|
92
|
+
await kyselyPglite.client.close();
|
|
93
|
+
} catch {}
|
|
94
|
+
if (databasePath && databasePath !== ":memory:" && existsSync(databasePath)) await rm(databasePath, {
|
|
95
|
+
recursive: true,
|
|
96
|
+
force: true
|
|
97
|
+
});
|
|
98
|
+
};
|
|
99
|
+
return {
|
|
100
|
+
testContext: {
|
|
101
|
+
get kysely() {
|
|
102
|
+
return kysely;
|
|
103
|
+
},
|
|
104
|
+
get adapter() {
|
|
105
|
+
return adapter;
|
|
106
|
+
},
|
|
107
|
+
resetDatabase,
|
|
108
|
+
cleanup
|
|
109
|
+
},
|
|
110
|
+
get adapter() {
|
|
111
|
+
return adapter;
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Create Drizzle + PGLite adapter using drizzle-orm/pglite
|
|
117
|
+
*/
|
|
118
|
+
async function createDrizzlePgliteAdapter(config, schema, namespace, _migrateToVersion) {
|
|
119
|
+
const databasePath = config.databasePath;
|
|
120
|
+
const { generateDrizzleJson, generateMigration } = createRequire(import.meta.url)("drizzle-kit/api");
|
|
121
|
+
const { generateSchema } = await import("@fragno-dev/db/adapters/drizzle/generate");
|
|
122
|
+
const writeAndLoadSchema = async () => {
|
|
123
|
+
const testDir = join(import.meta.dirname, "_generated", "drizzle-test");
|
|
124
|
+
await mkdir(testDir, { recursive: true }).catch(() => {});
|
|
125
|
+
const schemaFilePath = join(testDir, `test-schema-${Date.now()}-${Math.random().toString(36).slice(2, 9)}.ts`);
|
|
126
|
+
await writeFile(schemaFilePath, generateSchema([{
|
|
127
|
+
namespace: namespace ?? "",
|
|
128
|
+
schema
|
|
129
|
+
}], "postgresql"), "utf-8");
|
|
130
|
+
const schemaModule = await import(`${schemaFilePath}?t=${Date.now()}`);
|
|
131
|
+
const cleanup$1 = async () => {
|
|
132
|
+
await rm(testDir, {
|
|
133
|
+
recursive: true,
|
|
134
|
+
force: true
|
|
135
|
+
});
|
|
136
|
+
};
|
|
137
|
+
return {
|
|
138
|
+
schemaModule,
|
|
139
|
+
cleanup: cleanup$1
|
|
140
|
+
};
|
|
141
|
+
};
|
|
142
|
+
const createDatabase = async () => {
|
|
143
|
+
const { schemaModule, cleanup: cleanup$1 } = await writeAndLoadSchema();
|
|
144
|
+
const pglite$1 = new PGlite(databasePath);
|
|
145
|
+
const db = drizzle(pglite$1, { schema: schemaModule });
|
|
146
|
+
const migrationStatements = await generateMigration(generateDrizzleJson({}), generateDrizzleJson(schemaModule));
|
|
147
|
+
for (const statement of migrationStatements) await db.execute(statement);
|
|
148
|
+
return {
|
|
149
|
+
drizzle: db,
|
|
150
|
+
adapter: new DrizzleAdapter({
|
|
151
|
+
db: () => db,
|
|
152
|
+
provider: "postgresql"
|
|
153
|
+
}),
|
|
154
|
+
pglite: pglite$1,
|
|
155
|
+
cleanup: cleanup$1
|
|
156
|
+
};
|
|
157
|
+
};
|
|
158
|
+
let { drizzle: drizzleDb, adapter, pglite, cleanup: schemaCleanup } = await createDatabase();
|
|
159
|
+
const resetDatabase = async () => {
|
|
160
|
+
await pglite.close();
|
|
161
|
+
await schemaCleanup();
|
|
162
|
+
const newDb = await createDatabase();
|
|
163
|
+
drizzleDb = newDb.drizzle;
|
|
164
|
+
adapter = newDb.adapter;
|
|
165
|
+
pglite = newDb.pglite;
|
|
166
|
+
schemaCleanup = newDb.cleanup;
|
|
167
|
+
};
|
|
168
|
+
const cleanup = async () => {
|
|
169
|
+
await pglite.close();
|
|
170
|
+
await schemaCleanup();
|
|
171
|
+
if (databasePath && databasePath !== ":memory:" && existsSync(databasePath)) await rm(databasePath, {
|
|
172
|
+
recursive: true,
|
|
173
|
+
force: true
|
|
174
|
+
});
|
|
175
|
+
};
|
|
176
|
+
return {
|
|
177
|
+
testContext: {
|
|
178
|
+
get drizzle() {
|
|
179
|
+
return drizzleDb;
|
|
180
|
+
},
|
|
181
|
+
get adapter() {
|
|
182
|
+
return adapter;
|
|
183
|
+
},
|
|
184
|
+
resetDatabase,
|
|
185
|
+
cleanup
|
|
186
|
+
},
|
|
187
|
+
get adapter() {
|
|
188
|
+
return adapter;
|
|
189
|
+
}
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Create adapter based on configuration
|
|
194
|
+
*/
|
|
195
|
+
async function createAdapter(adapterConfig, schema, namespace, migrateToVersion) {
|
|
196
|
+
if (adapterConfig.type === "kysely-sqlite") return createKyselySqliteAdapter(adapterConfig, schema, namespace, migrateToVersion);
|
|
197
|
+
else if (adapterConfig.type === "kysely-pglite") return createKyselyPgliteAdapter(adapterConfig, schema, namespace, migrateToVersion);
|
|
198
|
+
else if (adapterConfig.type === "drizzle-pglite") return createDrizzlePgliteAdapter(adapterConfig, schema, namespace, migrateToVersion);
|
|
199
|
+
throw new Error(`Unsupported adapter type: ${adapterConfig.type}`);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
//#endregion
|
|
203
|
+
export { createAdapter };
|
|
204
|
+
//# sourceMappingURL=adapters.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapters.js","names":["kysely","adapter","kyselyPglite","cleanup","pglite"],"sources":["../src/adapters.ts"],"sourcesContent":["import { Kysely } from \"kysely\";\nimport { SQLocalKysely } from \"sqlocal/kysely\";\nimport { KyselyPGlite } from \"kysely-pglite\";\nimport { drizzle } from \"drizzle-orm/pglite\";\nimport { PGlite } from \"@electric-sql/pglite\";\nimport { KyselyAdapter } from \"@fragno-dev/db/adapters/kysely\";\nimport { DrizzleAdapter } from \"@fragno-dev/db/adapters/drizzle\";\nimport type { AnySchema } from \"@fragno-dev/db/schema\";\nimport type { DatabaseAdapter } from \"@fragno-dev/db/adapters\";\nimport { createRequire } from \"node:module\";\nimport { mkdir, writeFile, rm } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { existsSync } from \"node:fs\";\n\n// Adapter configuration types\nexport interface KyselySqliteAdapter {\n type: \"kysely-sqlite\";\n}\n\nexport interface KyselyPgliteAdapter {\n type: \"kysely-pglite\";\n databasePath?: string;\n}\n\nexport interface DrizzlePgliteAdapter {\n type: \"drizzle-pglite\";\n databasePath?: string;\n}\n\nexport type SupportedAdapter = KyselySqliteAdapter | KyselyPgliteAdapter | DrizzlePgliteAdapter;\n\n// Conditional return types based on adapter\nexport type TestContext<T extends SupportedAdapter> = T extends\n | KyselySqliteAdapter\n | KyselyPgliteAdapter\n ? {\n readonly kysely: Kysely<any>; // eslint-disable-line @typescript-eslint/no-explicit-any\n readonly adapter: DatabaseAdapter<any>; // eslint-disable-line @typescript-eslint/no-explicit-any\n resetDatabase: () => Promise<void>;\n cleanup: () => Promise<void>;\n }\n : T extends DrizzlePgliteAdapter\n ? {\n readonly drizzle: ReturnType<typeof drizzle<any>>; // eslint-disable-line @typescript-eslint/no-explicit-any\n readonly adapter: DatabaseAdapter<any>; // eslint-disable-line @typescript-eslint/no-explicit-any\n resetDatabase: () => Promise<void>;\n cleanup: () => Promise<void>;\n }\n : never;\n\n// Factory function return type\ninterface AdapterFactoryResult<T extends SupportedAdapter> {\n testContext: TestContext<T>;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n adapter: DatabaseAdapter<any>;\n}\n\n/**\n * Create Kysely + SQLite adapter using SQLocalKysely (always in-memory)\n */\nexport async function createKyselySqliteAdapter(\n _config: KyselySqliteAdapter,\n schema: AnySchema,\n namespace: string,\n migrateToVersion?: number,\n): Promise<AdapterFactoryResult<KyselySqliteAdapter>> {\n // Helper to create a new database instance and run migrations\n const createDatabase = async () => {\n // Create SQLocalKysely instance (always in-memory for tests)\n const { dialect } = new SQLocalKysely(\":memory:\");\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const kysely = new Kysely<any>({\n dialect,\n });\n\n // Create KyselyAdapter\n const adapter = new KyselyAdapter({\n db: kysely,\n provider: \"sqlite\",\n });\n\n // Run migrations\n const migrator = adapter.createMigrationEngine(schema, namespace);\n const preparedMigration = migrateToVersion\n ? await migrator.prepareMigrationTo(migrateToVersion, {\n updateSettings: false,\n })\n : await migrator.prepareMigration({\n updateSettings: false,\n });\n await preparedMigration.execute();\n\n return { kysely, adapter };\n };\n\n // Create initial database\n let { kysely, adapter } = await createDatabase();\n\n // Reset database function - creates a fresh in-memory database and re-runs migrations\n const resetDatabase = async () => {\n // Destroy the old Kysely instance\n await kysely.destroy();\n\n // Create a new database instance\n const newDb = await createDatabase();\n kysely = newDb.kysely;\n adapter = newDb.adapter;\n };\n\n // Cleanup function - closes connections (no files to delete for in-memory)\n const cleanup = async () => {\n await kysely.destroy();\n };\n\n return {\n testContext: {\n get kysely() {\n return kysely;\n },\n get adapter() {\n return adapter;\n },\n resetDatabase,\n cleanup,\n },\n get adapter() {\n return adapter;\n },\n };\n}\n\n/**\n * Create Kysely + PGLite adapter using kysely-pglite\n */\nexport async function createKyselyPgliteAdapter(\n config: KyselyPgliteAdapter,\n schema: AnySchema,\n namespace: string,\n migrateToVersion?: number,\n): Promise<AdapterFactoryResult<KyselyPgliteAdapter>> {\n const databasePath = config.databasePath;\n\n // Helper to create a new database instance and run migrations\n const createDatabase = async () => {\n // Create KyselyPGlite instance\n const kyselyPglite = await KyselyPGlite.create(databasePath);\n\n // Create Kysely instance with PGlite dialect\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const kysely = new Kysely<any>({\n dialect: kyselyPglite.dialect,\n });\n\n // Create KyselyAdapter\n const adapter = new KyselyAdapter({\n db: kysely,\n provider: \"postgresql\",\n });\n\n // Run migrations\n const migrator = adapter.createMigrationEngine(schema, namespace);\n const preparedMigration = migrateToVersion\n ? await migrator.prepareMigrationTo(migrateToVersion, {\n updateSettings: false,\n })\n : await migrator.prepareMigration({\n updateSettings: false,\n });\n await preparedMigration.execute();\n\n return { kysely, adapter, kyselyPglite };\n };\n\n // Create initial database\n let { kysely, adapter, kyselyPglite } = await createDatabase();\n\n // Reset database function - creates a fresh database and re-runs migrations\n const resetDatabase = async () => {\n // Close the old instances\n await kysely.destroy();\n\n try {\n await kyselyPglite.client.close();\n } catch {\n // Ignore if already closed\n }\n\n // Create a new database instance\n const newDb = await createDatabase();\n kysely = newDb.kysely;\n adapter = newDb.adapter;\n kyselyPglite = newDb.kyselyPglite;\n };\n\n // Cleanup function - closes connections and deletes database directory\n const cleanup = async () => {\n await kysely.destroy();\n\n try {\n await kyselyPglite.client.close();\n } catch {\n // Ignore if already closed\n }\n\n // Delete the database directory if it exists and is a file path\n if (databasePath && databasePath !== \":memory:\" && existsSync(databasePath)) {\n await rm(databasePath, { recursive: true, force: true });\n }\n };\n\n return {\n testContext: {\n get kysely() {\n return kysely;\n },\n get adapter() {\n return adapter;\n },\n resetDatabase,\n cleanup,\n },\n get adapter() {\n return adapter;\n },\n };\n}\n\n/**\n * Create Drizzle + PGLite adapter using drizzle-orm/pglite\n */\nexport async function createDrizzlePgliteAdapter(\n config: DrizzlePgliteAdapter,\n schema: AnySchema,\n namespace: string,\n _migrateToVersion?: number,\n): Promise<AdapterFactoryResult<DrizzlePgliteAdapter>> {\n const databasePath = config.databasePath;\n\n // Import drizzle-kit for migrations\n const require = createRequire(import.meta.url);\n const { generateDrizzleJson, generateMigration } =\n require(\"drizzle-kit/api\") as typeof import(\"drizzle-kit/api\");\n\n // Import generateSchema from the properly exported module\n const { generateSchema } = await import(\"@fragno-dev/db/adapters/drizzle/generate\");\n\n // Helper to write schema to file and dynamically import it\n const writeAndLoadSchema = async () => {\n const testDir = join(import.meta.dirname, \"_generated\", \"drizzle-test\");\n await mkdir(testDir, { recursive: true }).catch(() => {\n // Ignore error if directory already exists\n });\n\n const schemaFilePath = join(\n testDir,\n `test-schema-${Date.now()}-${Math.random().toString(36).slice(2, 9)}.ts`,\n );\n\n // Generate and write the Drizzle schema to file\n const drizzleSchemaTs = generateSchema([{ namespace: namespace ?? \"\", schema }], \"postgresql\");\n await writeFile(schemaFilePath, drizzleSchemaTs, \"utf-8\");\n\n // Dynamically import the generated schema (with cache busting)\n const schemaModule = await import(`${schemaFilePath}?t=${Date.now()}`);\n\n const cleanup = async () => {\n await rm(testDir, { recursive: true, force: true });\n };\n\n return { schemaModule, cleanup };\n };\n\n // Helper to create a new database instance and run migrations\n const createDatabase = async () => {\n // Write schema to file and load it\n const { schemaModule, cleanup } = await writeAndLoadSchema();\n\n // Create PGlite instance\n const pglite = new PGlite(databasePath);\n\n // Create Drizzle instance with PGlite\n const db = drizzle(pglite, {\n schema: schemaModule,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n }) as any;\n\n // Generate and run migrations\n const migrationStatements = await generateMigration(\n generateDrizzleJson({}), // Empty schema (starting state)\n generateDrizzleJson(schemaModule), // Target schema\n );\n\n // Execute migration SQL\n for (const statement of migrationStatements) {\n await db.execute(statement);\n }\n\n // Create DrizzleAdapter\n const adapter = new DrizzleAdapter({\n db: () => db,\n provider: \"postgresql\",\n });\n\n return { drizzle: db, adapter, pglite, cleanup };\n };\n\n // Create initial database\n let { drizzle: drizzleDb, adapter, pglite, cleanup: schemaCleanup } = await createDatabase();\n\n // Reset database function - creates a fresh database and re-runs migrations\n const resetDatabase = async () => {\n // Close the old instances and cleanup\n await pglite.close();\n await schemaCleanup();\n\n // Create a new database instance\n const newDb = await createDatabase();\n drizzleDb = newDb.drizzle;\n adapter = newDb.adapter;\n pglite = newDb.pglite;\n schemaCleanup = newDb.cleanup;\n };\n\n // Cleanup function - closes connections and deletes generated files and database directory\n const cleanup = async () => {\n await pglite.close();\n await schemaCleanup();\n\n // Delete the database directory if it exists and is a file path\n if (databasePath && databasePath !== \":memory:\" && existsSync(databasePath)) {\n await rm(databasePath, { recursive: true, force: true });\n }\n };\n\n return {\n testContext: {\n get drizzle() {\n return drizzleDb;\n },\n get adapter() {\n return adapter;\n },\n resetDatabase,\n cleanup,\n },\n get adapter() {\n return adapter;\n },\n };\n}\n\n/**\n * Create adapter based on configuration\n */\nexport async function createAdapter<T extends SupportedAdapter>(\n adapterConfig: T,\n schema: AnySchema,\n namespace: string,\n migrateToVersion?: number,\n): Promise<AdapterFactoryResult<T>> {\n if (adapterConfig.type === \"kysely-sqlite\") {\n return createKyselySqliteAdapter(adapterConfig, schema, namespace, migrateToVersion) as Promise<\n AdapterFactoryResult<T>\n >;\n } else if (adapterConfig.type === \"kysely-pglite\") {\n return createKyselyPgliteAdapter(adapterConfig, schema, namespace, migrateToVersion) as Promise<\n AdapterFactoryResult<T>\n >;\n } else if (adapterConfig.type === \"drizzle-pglite\") {\n return createDrizzlePgliteAdapter(\n adapterConfig,\n schema,\n namespace,\n migrateToVersion,\n ) as Promise<AdapterFactoryResult<T>>;\n }\n\n throw new Error(`Unsupported adapter type: ${(adapterConfig as SupportedAdapter).type}`);\n}\n"],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { DrizzlePgliteAdapter, KyselyPgliteAdapter, KyselySqliteAdapter, SupportedAdapter, TestContext } from "./adapters.js";
|
|
2
2
|
import { CreateFragmentForTestOptions, CreateFragmentForTestOptions as CreateFragmentForTestOptions$1, FragmentForTest, FragmentForTest as FragmentForTest$1, InitRoutesOverrides, RouteHandlerInputOptions, TestResponse, createFragmentForTest } from "@fragno-dev/core/test";
|
|
3
3
|
import { AnySchema } from "@fragno-dev/db/schema";
|
|
4
|
-
import { DatabaseAdapter } from "@fragno-dev/db/adapters";
|
|
5
4
|
import { FragnoPublicConfig } from "@fragno-dev/core/api/fragment-instantiation";
|
|
6
5
|
import { FragmentDefinition } from "@fragno-dev/core/api/fragment-builder";
|
|
7
6
|
|
|
@@ -10,27 +9,29 @@ import { FragmentDefinition } from "@fragno-dev/core/api/fragment-builder";
|
|
|
10
9
|
/**
|
|
11
10
|
* Options for creating a database fragment for testing
|
|
12
11
|
*/
|
|
13
|
-
interface CreateDatabaseFragmentForTestOptions<TConfig, TDeps, TServices, TAdditionalContext extends Record<string, unknown>, TOptions extends FragnoPublicConfig> extends Omit<CreateFragmentForTestOptions$1<TConfig, TDeps, TServices, TAdditionalContext, TOptions>, "config"> {
|
|
14
|
-
|
|
12
|
+
interface CreateDatabaseFragmentForTestOptions<TConfig, TDeps, TServices, TAdditionalContext extends Record<string, unknown>, TOptions extends FragnoPublicConfig, TAdapter extends SupportedAdapter> extends Omit<CreateFragmentForTestOptions$1<TConfig, TDeps, TServices, TAdditionalContext, TOptions>, "config"> {
|
|
13
|
+
adapter: TAdapter;
|
|
15
14
|
migrateToVersion?: number;
|
|
16
15
|
config?: TConfig;
|
|
17
16
|
}
|
|
18
17
|
/**
|
|
19
|
-
*
|
|
18
|
+
* Result of creating a database fragment for testing
|
|
19
|
+
* All properties are getters that return the current fragment instance
|
|
20
20
|
*/
|
|
21
|
-
interface
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
21
|
+
interface DatabaseFragmentTestResult<TConfig, TDeps, TServices, TAdditionalContext extends Record<string, unknown>, TOptions extends FragnoPublicConfig, TAdapter extends SupportedAdapter> {
|
|
22
|
+
readonly fragment: FragmentForTest$1<TConfig, TDeps, TServices, TAdditionalContext, TOptions>;
|
|
23
|
+
readonly services: TServices;
|
|
24
|
+
readonly initRoutes: FragmentForTest$1<TConfig, TDeps, TServices, TAdditionalContext, TOptions>["initRoutes"];
|
|
25
|
+
readonly handler: FragmentForTest$1<TConfig, TDeps, TServices, TAdditionalContext, TOptions>["handler"];
|
|
26
|
+
readonly config: TConfig;
|
|
27
|
+
readonly deps: TDeps;
|
|
28
|
+
readonly additionalContext: TAdditionalContext;
|
|
29
|
+
test: TestContext<TAdapter>;
|
|
29
30
|
}
|
|
30
|
-
declare function createDatabaseFragmentForTest<const TConfig, const TDeps, const TServices extends Record<string, unknown>, const TAdditionalContext extends Record<string, unknown>, const TOptions extends FragnoPublicConfig, const TSchema extends AnySchema>(fragmentBuilder: {
|
|
31
|
+
declare function createDatabaseFragmentForTest<const TConfig, const TDeps, const TServices extends Record<string, unknown>, const TAdditionalContext extends Record<string, unknown>, const TOptions extends FragnoPublicConfig, const TSchema extends AnySchema, const TAdapter extends SupportedAdapter>(fragmentBuilder: {
|
|
31
32
|
definition: FragmentDefinition<TConfig, TDeps, TServices, TAdditionalContext>;
|
|
32
33
|
$requiredOptions: TOptions;
|
|
33
|
-
}, options
|
|
34
|
+
}, options: CreateDatabaseFragmentForTestOptions<TConfig, TDeps, TServices, TAdditionalContext, TOptions, TAdapter>): Promise<DatabaseFragmentTestResult<TConfig, TDeps, TServices, TAdditionalContext, TOptions, TAdapter>>;
|
|
34
35
|
//#endregion
|
|
35
|
-
export { CreateDatabaseFragmentForTestOptions, type CreateFragmentForTestOptions,
|
|
36
|
+
export { CreateDatabaseFragmentForTestOptions, type CreateFragmentForTestOptions, DatabaseFragmentTestResult, type DrizzlePgliteAdapter, type FragmentForTest, type InitRoutesOverrides, type KyselyPgliteAdapter, type KyselySqliteAdapter, type RouteHandlerInputOptions, type SupportedAdapter, type TestContext, type TestResponse, createDatabaseFragmentForTest, createFragmentForTest };
|
|
36
37
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/index.ts"],"sourcesContent":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/index.ts"],"sourcesContent":[],"mappings":";;;;;;;;AAuCA;;;AAMmB,UANF,oCAME,CAAA,OAAA,EAAA,KAAA,EAAA,SAAA,EAAA,2BAFU,MAEV,CAAA,MAAA,EAAA,OAAA,CAAA,EAAA,iBADA,kBACA,EAAA,iBAAA,gBAAA,CAAA,SACT,IADS,CAEf,8BAFe,CAEc,OAFd,EAEuB,KAFvB,EAE8B,SAF9B,EAEyC,kBAFzC,EAE6D,QAF7D,CAAA,EAAA,QAAA,CAAA,CAAA;EAEc,OAAA,EAGtB,QAHsB;EAAS,gBAAA,CAAA,EAAA,MAAA;EAAO,MAAA,CAAA,EAKtC,OALsC;;;;;;AADvC,UAaO,0BAbP,CAAA,OAAA,EAAA,KAAA,EAAA,SAAA,EAAA,2BAiBmB,MAjBnB,CAAA,MAAA,EAAA,OAAA,CAAA,EAAA,iBAkBS,kBAlBT,EAAA,iBAmBS,gBAnBT,CAAA,CAAA;EAAI,SAAA,QAAA,EAqBO,iBArBP,CAqBuB,OArBvB,EAqBgC,KArBhC,EAqBuC,SArBvC,EAqBkD,kBArBlD,EAqBsE,QArBtE,CAAA;EAaG,SAAA,QAAA,EASI,SATJ;EAIY,SAAA,UAAA,EAMN,iBANM,CAOzB,OAPyB,EAQzB,KARyB,EASzB,SATyB,EAUzB,kBAVyB,EAWzB,QAXyB,CAAA,CAAA,YAAA,CAAA;EACV,SAAA,OAAA,EAYC,iBAZD,CAaf,OAbe,EAcf,KAde,EAef,SAfe,EAgBf,kBAhBe,EAiBf,QAjBe,CAAA,CAAA,SAAA,CAAA;EACA,SAAA,MAAA,EAkBA,OAlBA;EAEkB,SAAA,IAAA,EAiBpB,KAjBoB;EAAS,SAAA,iBAAA,EAkBhB,kBAlBgB;EAAO,IAAA,EAmB7C,WAnB6C,CAmBjC,QAnBiC,CAAA;;AAA+B,iBAsB9D,6BAtB8D,CAAA,aAAA,EAAA,WAAA,EAAA,wBAyB1D,MAzB0D,CAAA,MAAA,EAAA,OAAA,CAAA,EAAA,iCA0BjD,MA1BiD,CAAA,MAAA,EAAA,OAAA,CAAA,EAAA,uBA2B3D,kBA3B2D,EAAA,sBA4B5D,SA5B4D,EAAA,uBA6B3D,gBA7B2D,CAAA,CAAA,eAAA,EAAA;EAA/D,UAAA,EAgCL,kBAhCK,CAgCc,OAhCd,EAgCuB,KAhCvB,EAgC8B,SAhC9B,EAgCyC,kBAhCzC,CAAA;EACA,gBAAA,EAgCC,QAhCD;CAEjB,EAAA,OAAA,EAgCO,oCAhCP,CAiCA,OAjCA,EAkCA,KAlCA,EAmCA,SAnCA,EAoCA,kBApCA,EAqCA,QArCA,EAsCA,QAtCA,CAAA,CAAA,EAwCD,OAxCC,CAyCF,0BAzCE,CAyCyB,OAzCzB,EAyCkC,KAzClC,EAyCyC,SAzCzC,EAyCoD,kBAzCpD,EAyCwE,QAzCxE,EAyCkF,QAzClF,CAAA,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -1,30 +1,14 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { SQLocalKysely } from "sqlocal/kysely";
|
|
3
|
-
import { KyselyAdapter } from "@fragno-dev/db/adapters/kysely";
|
|
1
|
+
import { createAdapter } from "./adapters.js";
|
|
4
2
|
import { createFragmentForTest, createFragmentForTest as createFragmentForTest$1 } from "@fragno-dev/core/test";
|
|
5
3
|
|
|
6
4
|
//#region src/index.ts
|
|
7
5
|
async function createDatabaseFragmentForTest(fragmentBuilder, options) {
|
|
8
|
-
const {
|
|
6
|
+
const { adapter: adapterConfig, migrateToVersion, config, options: fragmentOptions, deps, services, additionalContext } = options;
|
|
9
7
|
const fragmentAdditionalContext = fragmentBuilder.definition.additionalContext;
|
|
10
8
|
const schema = fragmentAdditionalContext?.databaseSchema;
|
|
11
9
|
const namespace = fragmentAdditionalContext?.databaseNamespace ?? "";
|
|
12
10
|
if (!schema) throw new Error(`Fragment '${fragmentBuilder.definition.name}' does not have a database schema. Make sure you're using defineFragmentWithDatabase().withDatabase(schema).`);
|
|
13
|
-
const
|
|
14
|
-
const { dialect } = new SQLocalKysely(databasePath);
|
|
15
|
-
const kysely$1 = new Kysely({ dialect });
|
|
16
|
-
const adapter$1 = new KyselyAdapter({
|
|
17
|
-
db: kysely$1,
|
|
18
|
-
provider: "sqlite"
|
|
19
|
-
});
|
|
20
|
-
const migrator = adapter$1.createMigrationEngine(schema, namespace);
|
|
21
|
-
await (migrateToVersion ? await migrator.prepareMigrationTo(migrateToVersion, { updateSettings: false }) : await migrator.prepareMigration({ updateSettings: false })).execute();
|
|
22
|
-
return {
|
|
23
|
-
kysely: kysely$1,
|
|
24
|
-
adapter: adapter$1
|
|
25
|
-
};
|
|
26
|
-
};
|
|
27
|
-
let { kysely, adapter } = await createDatabase();
|
|
11
|
+
const { testContext: originalTestContext, adapter } = await createAdapter(adapterConfig, schema, namespace, migrateToVersion);
|
|
28
12
|
let mergedOptions = {
|
|
29
13
|
...fragmentOptions,
|
|
30
14
|
databaseAdapter: adapter
|
|
@@ -36,24 +20,11 @@ async function createDatabaseFragmentForTest(fragmentBuilder, options) {
|
|
|
36
20
|
services,
|
|
37
21
|
additionalContext
|
|
38
22
|
});
|
|
39
|
-
const
|
|
40
|
-
await kysely.destroy();
|
|
41
|
-
const newDb = await createDatabase();
|
|
42
|
-
kysely = newDb.kysely;
|
|
43
|
-
adapter = newDb.adapter;
|
|
44
|
-
mergedOptions = {
|
|
45
|
-
...fragmentOptions,
|
|
46
|
-
databaseAdapter: adapter
|
|
47
|
-
};
|
|
48
|
-
fragment = createFragmentForTest$1(fragmentBuilder, {
|
|
49
|
-
config,
|
|
50
|
-
options: mergedOptions,
|
|
51
|
-
deps,
|
|
52
|
-
services,
|
|
53
|
-
additionalContext
|
|
54
|
-
});
|
|
55
|
-
};
|
|
23
|
+
const originalResetDatabase = originalTestContext.resetDatabase;
|
|
56
24
|
return {
|
|
25
|
+
get fragment() {
|
|
26
|
+
return fragment;
|
|
27
|
+
},
|
|
57
28
|
get services() {
|
|
58
29
|
return fragment.services;
|
|
59
30
|
},
|
|
@@ -72,13 +43,49 @@ async function createDatabaseFragmentForTest(fragmentBuilder, options) {
|
|
|
72
43
|
get additionalContext() {
|
|
73
44
|
return fragment.additionalContext;
|
|
74
45
|
},
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
46
|
+
test: Object.create(originalTestContext, {
|
|
47
|
+
kysely: {
|
|
48
|
+
get() {
|
|
49
|
+
return originalTestContext.kysely;
|
|
50
|
+
},
|
|
51
|
+
enumerable: true
|
|
52
|
+
},
|
|
53
|
+
drizzle: {
|
|
54
|
+
get() {
|
|
55
|
+
return originalTestContext.drizzle;
|
|
56
|
+
},
|
|
57
|
+
enumerable: true
|
|
58
|
+
},
|
|
59
|
+
adapter: {
|
|
60
|
+
get() {
|
|
61
|
+
return originalTestContext.adapter;
|
|
62
|
+
},
|
|
63
|
+
enumerable: true
|
|
64
|
+
},
|
|
65
|
+
resetDatabase: {
|
|
66
|
+
value: async () => {
|
|
67
|
+
await originalResetDatabase();
|
|
68
|
+
mergedOptions = {
|
|
69
|
+
...fragmentOptions,
|
|
70
|
+
databaseAdapter: originalTestContext.adapter
|
|
71
|
+
};
|
|
72
|
+
fragment = createFragmentForTest$1(fragmentBuilder, {
|
|
73
|
+
config,
|
|
74
|
+
options: mergedOptions,
|
|
75
|
+
deps,
|
|
76
|
+
services,
|
|
77
|
+
additionalContext
|
|
78
|
+
});
|
|
79
|
+
},
|
|
80
|
+
enumerable: true
|
|
81
|
+
},
|
|
82
|
+
cleanup: {
|
|
83
|
+
value: async () => {
|
|
84
|
+
await originalTestContext.cleanup();
|
|
85
|
+
},
|
|
86
|
+
enumerable: true
|
|
87
|
+
}
|
|
88
|
+
})
|
|
82
89
|
};
|
|
83
90
|
}
|
|
84
91
|
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["
|
|
1
|
+
{"version":3,"file":"index.js","names":["createFragmentForTest"],"sources":["../src/index.ts"],"sourcesContent":["import type { AnySchema } from \"@fragno-dev/db/schema\";\nimport {\n createFragmentForTest,\n type FragmentForTest,\n type CreateFragmentForTestOptions,\n} from \"@fragno-dev/core/test\";\nimport type { FragnoPublicConfig } from \"@fragno-dev/core/api/fragment-instantiation\";\nimport type { FragmentDefinition } from \"@fragno-dev/core/api/fragment-builder\";\nimport {\n createAdapter,\n type SupportedAdapter,\n type TestContext,\n type KyselySqliteAdapter,\n type KyselyPgliteAdapter,\n type DrizzlePgliteAdapter,\n} from \"./adapters\";\n\n// Re-export utilities from @fragno-dev/core/test\nexport {\n createFragmentForTest,\n type TestResponse,\n type CreateFragmentForTestOptions,\n type RouteHandlerInputOptions,\n type FragmentForTest,\n type InitRoutesOverrides,\n} from \"@fragno-dev/core/test\";\n\n// Re-export adapter types\nexport type {\n SupportedAdapter,\n KyselySqliteAdapter,\n KyselyPgliteAdapter,\n DrizzlePgliteAdapter,\n TestContext,\n} from \"./adapters\";\n\n/**\n * Options for creating a database fragment for testing\n */\nexport interface CreateDatabaseFragmentForTestOptions<\n TConfig,\n TDeps,\n TServices,\n TAdditionalContext extends Record<string, unknown>,\n TOptions extends FragnoPublicConfig,\n TAdapter extends SupportedAdapter,\n> extends Omit<\n CreateFragmentForTestOptions<TConfig, TDeps, TServices, TAdditionalContext, TOptions>,\n \"config\"\n > {\n adapter: TAdapter;\n migrateToVersion?: number;\n config?: TConfig;\n}\n\n/**\n * Result of creating a database fragment for testing\n * All properties are getters that return the current fragment instance\n */\nexport interface DatabaseFragmentTestResult<\n TConfig,\n TDeps,\n TServices,\n TAdditionalContext extends Record<string, unknown>,\n TOptions extends FragnoPublicConfig,\n TAdapter extends SupportedAdapter,\n> {\n readonly fragment: FragmentForTest<TConfig, TDeps, TServices, TAdditionalContext, TOptions>;\n readonly services: TServices;\n readonly initRoutes: FragmentForTest<\n TConfig,\n TDeps,\n TServices,\n TAdditionalContext,\n TOptions\n >[\"initRoutes\"];\n readonly handler: FragmentForTest<\n TConfig,\n TDeps,\n TServices,\n TAdditionalContext,\n TOptions\n >[\"handler\"];\n readonly config: TConfig;\n readonly deps: TDeps;\n readonly additionalContext: TAdditionalContext;\n test: TestContext<TAdapter>;\n}\n\nexport async function createDatabaseFragmentForTest<\n const TConfig,\n const TDeps,\n const TServices extends Record<string, unknown>,\n const TAdditionalContext extends Record<string, unknown>,\n const TOptions extends FragnoPublicConfig,\n const TSchema extends AnySchema,\n const TAdapter extends SupportedAdapter,\n>(\n fragmentBuilder: {\n definition: FragmentDefinition<TConfig, TDeps, TServices, TAdditionalContext>;\n $requiredOptions: TOptions;\n },\n options: CreateDatabaseFragmentForTestOptions<\n TConfig,\n TDeps,\n TServices,\n TAdditionalContext,\n TOptions,\n TAdapter\n >,\n): Promise<\n DatabaseFragmentTestResult<TConfig, TDeps, TServices, TAdditionalContext, TOptions, TAdapter>\n> {\n const {\n adapter: adapterConfig,\n migrateToVersion,\n config,\n options: fragmentOptions,\n deps,\n services,\n additionalContext,\n } = options;\n\n // Get schema and namespace from fragment definition's additionalContext\n // Safe cast: DatabaseFragmentBuilder adds databaseSchema and databaseNamespace to additionalContext\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const fragmentAdditionalContext = fragmentBuilder.definition.additionalContext as any;\n const schema = fragmentAdditionalContext?.databaseSchema as TSchema | undefined;\n const namespace = (fragmentAdditionalContext?.databaseNamespace as string | undefined) ?? \"\";\n\n if (!schema) {\n throw new Error(\n `Fragment '${fragmentBuilder.definition.name}' does not have a database schema. ` +\n `Make sure you're using defineFragmentWithDatabase().withDatabase(schema).`,\n );\n }\n\n // Create adapter using the factory\n const { testContext: originalTestContext, adapter } = await createAdapter(\n adapterConfig,\n schema,\n namespace,\n migrateToVersion,\n );\n\n // Create fragment with database adapter in options\n // Safe cast: We're merging the user's options with the databaseAdapter, which is required by TOptions\n // The user's TOptions is constrained to FragnoPublicConfig (or a subtype), which we extend with databaseAdapter\n let mergedOptions = {\n ...fragmentOptions,\n databaseAdapter: adapter,\n } as unknown as TOptions;\n\n // Safe cast: If config is not provided, we pass undefined as TConfig.\n // The base createFragmentForTest expects config: TConfig, but if TConfig allows undefined\n // or if the fragment doesn't use config in its dependencies function, this will work correctly.\n let fragment = createFragmentForTest(fragmentBuilder, {\n config: config as TConfig,\n options: mergedOptions,\n deps,\n services,\n additionalContext,\n });\n\n // Wrap resetDatabase to also recreate the fragment with the new adapter\n const originalResetDatabase = originalTestContext.resetDatabase;\n\n // Create test context with getters that always return current values\n // We need to cast to any to avoid TypeScript errors when accessing kysely/drizzle properties\n // that may not exist depending on the adapter type\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const testContext: any = Object.create(originalTestContext, {\n kysely: {\n get() {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return (originalTestContext as any).kysely;\n },\n enumerable: true,\n },\n drizzle: {\n get() {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return (originalTestContext as any).drizzle;\n },\n enumerable: true,\n },\n adapter: {\n get() {\n return originalTestContext.adapter;\n },\n enumerable: true,\n },\n resetDatabase: {\n value: async () => {\n // Call the original reset database function\n await originalResetDatabase();\n\n // Recreate the fragment with the new adapter (which has been updated by the factory's resetDatabase)\n mergedOptions = {\n ...fragmentOptions,\n databaseAdapter: originalTestContext.adapter,\n } as unknown as TOptions;\n\n fragment = createFragmentForTest(fragmentBuilder, {\n config: config as TConfig,\n options: mergedOptions,\n deps,\n services,\n additionalContext,\n });\n },\n enumerable: true,\n },\n cleanup: {\n value: async () => {\n await originalTestContext.cleanup();\n },\n enumerable: true,\n },\n });\n\n // Return an object with getters for fragment properties so they always reference the current fragment\n return {\n get fragment() {\n return fragment;\n },\n get services() {\n return fragment.services;\n },\n get initRoutes() {\n return fragment.initRoutes;\n },\n get handler() {\n return fragment.handler;\n },\n get config() {\n return fragment.config;\n },\n get deps() {\n return fragment.deps;\n },\n get additionalContext() {\n return fragment.additionalContext;\n },\n test: testContext,\n };\n}\n"],"mappings":";;;;AAyFA,eAAsB,8BASpB,iBAIA,SAUA;CACA,MAAM,EACJ,SAAS,eACT,kBACA,QACA,SAAS,iBACT,MACA,UACA,sBACE;CAKJ,MAAM,4BAA4B,gBAAgB,WAAW;CAC7D,MAAM,SAAS,2BAA2B;CAC1C,MAAM,YAAa,2BAA2B,qBAA4C;AAE1F,KAAI,CAAC,OACH,OAAM,IAAI,MACR,aAAa,gBAAgB,WAAW,KAAK,8GAE9C;CAIH,MAAM,EAAE,aAAa,qBAAqB,YAAY,MAAM,cAC1D,eACA,QACA,WACA,iBACD;CAKD,IAAI,gBAAgB;EAClB,GAAG;EACH,iBAAiB;EAClB;CAKD,IAAI,WAAWA,wBAAsB,iBAAiB;EAC5C;EACR,SAAS;EACT;EACA;EACA;EACD,CAAC;CAGF,MAAM,wBAAwB,oBAAoB;AAyDlD,QAAO;EACL,IAAI,WAAW;AACb,UAAO;;EAET,IAAI,WAAW;AACb,UAAO,SAAS;;EAElB,IAAI,aAAa;AACf,UAAO,SAAS;;EAElB,IAAI,UAAU;AACZ,UAAO,SAAS;;EAElB,IAAI,SAAS;AACX,UAAO,SAAS;;EAElB,IAAI,OAAO;AACT,UAAO,SAAS;;EAElB,IAAI,oBAAoB;AACtB,UAAO,SAAS;;EAElB,MAzEuB,OAAO,OAAO,qBAAqB;GAC1D,QAAQ;IACN,MAAM;AAEJ,YAAQ,oBAA4B;;IAEtC,YAAY;IACb;GACD,SAAS;IACP,MAAM;AAEJ,YAAQ,oBAA4B;;IAEtC,YAAY;IACb;GACD,SAAS;IACP,MAAM;AACJ,YAAO,oBAAoB;;IAE7B,YAAY;IACb;GACD,eAAe;IACb,OAAO,YAAY;AAEjB,WAAM,uBAAuB;AAG7B,qBAAgB;MACd,GAAG;MACH,iBAAiB,oBAAoB;MACtC;AAED,gBAAWA,wBAAsB,iBAAiB;MACxC;MACR,SAAS;MACT;MACA;MACA;MACD,CAAC;;IAEJ,YAAY;IACb;GACD,SAAS;IACP,OAAO,YAAY;AACjB,WAAM,oBAAoB,SAAS;;IAErC,YAAY;IACb;GACF,CAAC;EA0BD"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fragno-dev/test",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.5",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": {
|
|
@@ -16,11 +16,36 @@
|
|
|
16
16
|
"kysely": "^0.28.7",
|
|
17
17
|
"sqlocal": "^0.15.2",
|
|
18
18
|
"@fragno-dev/core": "0.1.3",
|
|
19
|
-
"@fragno-dev/db": "0.1.
|
|
19
|
+
"@fragno-dev/db": "0.1.9"
|
|
20
|
+
},
|
|
21
|
+
"peerDependencies": {
|
|
22
|
+
"@electric-sql/pglite": "^0.3.11",
|
|
23
|
+
"drizzle-kit": "^0.30.3",
|
|
24
|
+
"drizzle-orm": "^0.44.7",
|
|
25
|
+
"kysely-pglite": "^0.6.1"
|
|
26
|
+
},
|
|
27
|
+
"peerDependenciesMeta": {
|
|
28
|
+
"@electric-sql/pglite": {
|
|
29
|
+
"optional": true
|
|
30
|
+
},
|
|
31
|
+
"drizzle-kit": {
|
|
32
|
+
"optional": true
|
|
33
|
+
},
|
|
34
|
+
"drizzle-orm": {
|
|
35
|
+
"optional": true
|
|
36
|
+
},
|
|
37
|
+
"kysely-pglite": {
|
|
38
|
+
"optional": true
|
|
39
|
+
}
|
|
20
40
|
},
|
|
21
41
|
"devDependencies": {
|
|
42
|
+
"@electric-sql/pglite": "^0.3.11",
|
|
43
|
+
"@libsql/client": "^0.14.0",
|
|
22
44
|
"@types/node": "^22",
|
|
23
45
|
"@vitest/coverage-istanbul": "^3.2.4",
|
|
46
|
+
"drizzle-kit": "^0.30.3",
|
|
47
|
+
"drizzle-orm": "^0.44.7",
|
|
48
|
+
"kysely-pglite": "^0.6.1",
|
|
24
49
|
"vitest": "^3.2.4",
|
|
25
50
|
"zod": "^4.1.12",
|
|
26
51
|
"@fragno-private/typescript-config": "0.0.1",
|