@hedystia/db 2.0.5 → 2.0.7
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/dist/cache/index.mjs +12 -0
- package/dist/cache/index.mjs.map +1 -0
- package/dist/cache/manager.mjs +156 -153
- package/dist/cache/manager.mjs.map +1 -1
- package/dist/cache/memory-store.mjs +113 -111
- package/dist/cache/memory-store.mjs.map +1 -1
- package/dist/cli/commands/migrate.cjs +78 -0
- package/dist/cli/commands/migrate.cjs.map +1 -0
- package/dist/cli/commands/migrate.mjs +83 -0
- package/dist/cli/commands/migrate.mjs.map +1 -0
- package/dist/cli.cjs +36 -0
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.mjs +37 -0
- package/dist/cli.mjs.map +1 -1
- package/dist/core/database.cjs +72 -29
- package/dist/core/database.cjs.map +1 -1
- package/dist/core/database.d.cts +65 -0
- package/dist/core/database.d.mts +65 -0
- package/dist/core/database.mjs +88 -34
- package/dist/core/database.mjs.map +1 -1
- package/dist/core/repository.mjs +414 -410
- package/dist/core/repository.mjs.map +1 -1
- package/dist/drivers/driver.mjs +9 -7
- package/dist/drivers/driver.mjs.map +1 -1
- package/dist/drivers/file.mjs +315 -312
- package/dist/drivers/file.mjs.map +1 -1
- package/dist/drivers/index.mjs +15 -6
- package/dist/drivers/index.mjs.map +1 -1
- package/dist/drivers/mysql.mjs +261 -256
- package/dist/drivers/mysql.mjs.map +1 -1
- package/dist/drivers/sql-compiler.mjs +4 -1
- package/dist/drivers/sql-compiler.mjs.map +1 -1
- package/dist/drivers/sqlite.cjs +12 -1
- package/dist/drivers/sqlite.cjs.map +1 -1
- package/dist/drivers/sqlite.mjs +258 -242
- package/dist/drivers/sqlite.mjs.map +1 -1
- package/dist/errors.mjs +48 -64
- package/dist/errors.mjs.map +1 -1
- package/dist/index.mjs +21 -9
- package/dist/index.mjs.map +1 -1
- package/dist/schema/column.mjs +155 -157
- package/dist/schema/column.mjs.map +1 -1
- package/dist/schema/columns/index.mjs +103 -171
- package/dist/schema/columns/index.mjs.map +1 -1
- package/dist/schema/index.mjs +15 -0
- package/dist/schema/index.mjs.map +1 -0
- package/dist/schema/registry.mjs +122 -119
- package/dist/schema/registry.mjs.map +1 -1
- package/dist/schema/table.mjs +4 -1
- package/dist/schema/table.mjs.map +1 -1
- package/dist/sync/synchronizer.mjs +2 -1
- package/dist/sync/synchronizer.mjs.map +1 -1
- package/dist/types.d.cts +67 -6
- package/dist/types.d.mts +67 -6
- package/package.json +1 -1
package/dist/core/database.d.cts
CHANGED
|
@@ -4,20 +4,74 @@ import { SchemaRegistry } from "../schema/registry.cjs";
|
|
|
4
4
|
|
|
5
5
|
//#region src/core/database.d.ts
|
|
6
6
|
type TypedTableRepository<S extends readonly AnyTableDef[], T extends AnyTableDef> = {
|
|
7
|
+
/**
|
|
8
|
+
* Find all rows matching the given options
|
|
9
|
+
* @param options - Filter, sort, paginate, and eagerly load relations
|
|
10
|
+
* @returns Array of matching rows
|
|
11
|
+
*/
|
|
7
12
|
find<O extends QueryOptions<InferRow<T>, RelationQueryMap<S, T>> = {}>(options?: O): Promise<ResolveResult<S, T, O>[]>;
|
|
13
|
+
/**
|
|
14
|
+
* Find all rows matching the given options (alias for {@link find})
|
|
15
|
+
* @param options - Filter, sort, paginate, and eagerly load relations
|
|
16
|
+
* @returns Array of matching rows
|
|
17
|
+
*/
|
|
8
18
|
findMany<O extends QueryOptions<InferRow<T>, RelationQueryMap<S, T>> = {}>(options?: O): Promise<ResolveResult<S, T, O>[]>;
|
|
19
|
+
/**
|
|
20
|
+
* Find the first row matching the given options
|
|
21
|
+
* @param options - Filter, sort, and eagerly load relations
|
|
22
|
+
* @returns The first matching row, or `null` if none found
|
|
23
|
+
*/
|
|
9
24
|
findFirst<O extends QueryOptions<InferRow<T>, RelationQueryMap<S, T>> = {}>(options?: O): Promise<ResolveResult<S, T, O> | null>;
|
|
25
|
+
/**
|
|
26
|
+
* Insert one or more rows into the table
|
|
27
|
+
* @param data - Row data (or array of row data) to insert
|
|
28
|
+
* @returns The inserted row
|
|
29
|
+
*/
|
|
10
30
|
insert(data: Partial<InferRow<T>> | Partial<InferRow<T>>[]): Promise<InferRow<T>>;
|
|
31
|
+
/**
|
|
32
|
+
* Insert multiple rows into the table
|
|
33
|
+
* @param data - Array of row data to insert
|
|
34
|
+
* @returns Array of inserted rows
|
|
35
|
+
*/
|
|
11
36
|
insertMany(data: Partial<InferRow<T>>[]): Promise<InferRow<T>[]>;
|
|
37
|
+
/**
|
|
38
|
+
* Update rows matching the where clause
|
|
39
|
+
* @param options - Where clause and partial data to apply
|
|
40
|
+
* @returns Array of updated rows
|
|
41
|
+
*/
|
|
12
42
|
update(options: UpdateOptions<InferRow<T>>): Promise<InferRow<T>[]>;
|
|
43
|
+
/**
|
|
44
|
+
* Delete rows matching the where clause
|
|
45
|
+
* @param options - Where clause to select rows for deletion
|
|
46
|
+
* @returns Number of deleted rows
|
|
47
|
+
*/
|
|
13
48
|
delete(options: DeleteOptions<InferRow<T>>): Promise<number>;
|
|
49
|
+
/**
|
|
50
|
+
* Count rows matching the where clause
|
|
51
|
+
* @param options - Optional where clause to filter rows
|
|
52
|
+
* @returns Number of matching rows
|
|
53
|
+
*/
|
|
14
54
|
count(options?: Pick<QueryOptions<InferRow<T>>, "where">): Promise<number>;
|
|
55
|
+
/**
|
|
56
|
+
* Check whether at least one row matches the where clause
|
|
57
|
+
* @param options - Where clause to check
|
|
58
|
+
* @returns `true` if a matching row exists, `false` otherwise
|
|
59
|
+
*/
|
|
15
60
|
exists(options: Pick<QueryOptions<InferRow<T>>, "where">): Promise<boolean>;
|
|
61
|
+
/**
|
|
62
|
+
* Insert a row if it doesn't exist, or update it if it does
|
|
63
|
+
* @param options - Where clause to check, data to create, and data to update
|
|
64
|
+
* @returns The created or updated row
|
|
65
|
+
*/
|
|
16
66
|
upsert(options: {
|
|
17
67
|
where: WhereClause<InferRow<T>>;
|
|
18
68
|
create: Partial<InferRow<T>>;
|
|
19
69
|
update: Partial<InferRow<T>>;
|
|
20
70
|
}): Promise<InferRow<T>>;
|
|
71
|
+
/**
|
|
72
|
+
* Remove all rows from the table
|
|
73
|
+
* @returns Resolves when the table has been truncated
|
|
74
|
+
*/
|
|
21
75
|
truncate(): Promise<void>;
|
|
22
76
|
};
|
|
23
77
|
type ExtractRepos<S> = S extends readonly AnyTableDef[] ? { [T in S[number] as T["__name"]]: TypedTableRepository<S, T> } : S extends Record<string, any> ? { [K in keyof S as S[K] extends AnyTableDef ? K : never]: TypedTableRepository<InferSchemas<S>, Extract<S[K], AnyTableDef>> } : never;
|
|
@@ -60,6 +114,17 @@ type DatabaseInstance<S> = ExtractRepos<S> & {
|
|
|
60
114
|
* @returns {Promise<T>} Result
|
|
61
115
|
*/
|
|
62
116
|
transaction<T>(fn: () => Promise<T>): Promise<T>;
|
|
117
|
+
/**
|
|
118
|
+
* Run pending migrations manually
|
|
119
|
+
* @returns {Promise<void>}
|
|
120
|
+
*/
|
|
121
|
+
migrateUp(): Promise<void>;
|
|
122
|
+
/**
|
|
123
|
+
* Rollback migrations
|
|
124
|
+
* @param {number} [steps=1] - Number of migrations to rollback
|
|
125
|
+
* @returns {Promise<string[]>} Names of rolled back migrations
|
|
126
|
+
*/
|
|
127
|
+
migrateDown(steps?: number): Promise<string[]>;
|
|
63
128
|
};
|
|
64
129
|
declare function database<const S extends readonly AnyTableDef[] | Record<string, any>>(config: DatabaseConfig & {
|
|
65
130
|
schemas: S;
|
package/dist/core/database.d.mts
CHANGED
|
@@ -4,20 +4,74 @@ import { SchemaRegistry } from "../schema/registry.mjs";
|
|
|
4
4
|
|
|
5
5
|
//#region src/core/database.d.ts
|
|
6
6
|
type TypedTableRepository<S extends readonly AnyTableDef[], T extends AnyTableDef> = {
|
|
7
|
+
/**
|
|
8
|
+
* Find all rows matching the given options
|
|
9
|
+
* @param options - Filter, sort, paginate, and eagerly load relations
|
|
10
|
+
* @returns Array of matching rows
|
|
11
|
+
*/
|
|
7
12
|
find<O extends QueryOptions<InferRow<T>, RelationQueryMap<S, T>> = {}>(options?: O): Promise<ResolveResult<S, T, O>[]>;
|
|
13
|
+
/**
|
|
14
|
+
* Find all rows matching the given options (alias for {@link find})
|
|
15
|
+
* @param options - Filter, sort, paginate, and eagerly load relations
|
|
16
|
+
* @returns Array of matching rows
|
|
17
|
+
*/
|
|
8
18
|
findMany<O extends QueryOptions<InferRow<T>, RelationQueryMap<S, T>> = {}>(options?: O): Promise<ResolveResult<S, T, O>[]>;
|
|
19
|
+
/**
|
|
20
|
+
* Find the first row matching the given options
|
|
21
|
+
* @param options - Filter, sort, and eagerly load relations
|
|
22
|
+
* @returns The first matching row, or `null` if none found
|
|
23
|
+
*/
|
|
9
24
|
findFirst<O extends QueryOptions<InferRow<T>, RelationQueryMap<S, T>> = {}>(options?: O): Promise<ResolveResult<S, T, O> | null>;
|
|
25
|
+
/**
|
|
26
|
+
* Insert one or more rows into the table
|
|
27
|
+
* @param data - Row data (or array of row data) to insert
|
|
28
|
+
* @returns The inserted row
|
|
29
|
+
*/
|
|
10
30
|
insert(data: Partial<InferRow<T>> | Partial<InferRow<T>>[]): Promise<InferRow<T>>;
|
|
31
|
+
/**
|
|
32
|
+
* Insert multiple rows into the table
|
|
33
|
+
* @param data - Array of row data to insert
|
|
34
|
+
* @returns Array of inserted rows
|
|
35
|
+
*/
|
|
11
36
|
insertMany(data: Partial<InferRow<T>>[]): Promise<InferRow<T>[]>;
|
|
37
|
+
/**
|
|
38
|
+
* Update rows matching the where clause
|
|
39
|
+
* @param options - Where clause and partial data to apply
|
|
40
|
+
* @returns Array of updated rows
|
|
41
|
+
*/
|
|
12
42
|
update(options: UpdateOptions<InferRow<T>>): Promise<InferRow<T>[]>;
|
|
43
|
+
/**
|
|
44
|
+
* Delete rows matching the where clause
|
|
45
|
+
* @param options - Where clause to select rows for deletion
|
|
46
|
+
* @returns Number of deleted rows
|
|
47
|
+
*/
|
|
13
48
|
delete(options: DeleteOptions<InferRow<T>>): Promise<number>;
|
|
49
|
+
/**
|
|
50
|
+
* Count rows matching the where clause
|
|
51
|
+
* @param options - Optional where clause to filter rows
|
|
52
|
+
* @returns Number of matching rows
|
|
53
|
+
*/
|
|
14
54
|
count(options?: Pick<QueryOptions<InferRow<T>>, "where">): Promise<number>;
|
|
55
|
+
/**
|
|
56
|
+
* Check whether at least one row matches the where clause
|
|
57
|
+
* @param options - Where clause to check
|
|
58
|
+
* @returns `true` if a matching row exists, `false` otherwise
|
|
59
|
+
*/
|
|
15
60
|
exists(options: Pick<QueryOptions<InferRow<T>>, "where">): Promise<boolean>;
|
|
61
|
+
/**
|
|
62
|
+
* Insert a row if it doesn't exist, or update it if it does
|
|
63
|
+
* @param options - Where clause to check, data to create, and data to update
|
|
64
|
+
* @returns The created or updated row
|
|
65
|
+
*/
|
|
16
66
|
upsert(options: {
|
|
17
67
|
where: WhereClause<InferRow<T>>;
|
|
18
68
|
create: Partial<InferRow<T>>;
|
|
19
69
|
update: Partial<InferRow<T>>;
|
|
20
70
|
}): Promise<InferRow<T>>;
|
|
71
|
+
/**
|
|
72
|
+
* Remove all rows from the table
|
|
73
|
+
* @returns Resolves when the table has been truncated
|
|
74
|
+
*/
|
|
21
75
|
truncate(): Promise<void>;
|
|
22
76
|
};
|
|
23
77
|
type ExtractRepos<S> = S extends readonly AnyTableDef[] ? { [T in S[number] as T["__name"]]: TypedTableRepository<S, T> } : S extends Record<string, any> ? { [K in keyof S as S[K] extends AnyTableDef ? K : never]: TypedTableRepository<InferSchemas<S>, Extract<S[K], AnyTableDef>> } : never;
|
|
@@ -60,6 +114,17 @@ type DatabaseInstance<S> = ExtractRepos<S> & {
|
|
|
60
114
|
* @returns {Promise<T>} Result
|
|
61
115
|
*/
|
|
62
116
|
transaction<T>(fn: () => Promise<T>): Promise<T>;
|
|
117
|
+
/**
|
|
118
|
+
* Run pending migrations manually
|
|
119
|
+
* @returns {Promise<void>}
|
|
120
|
+
*/
|
|
121
|
+
migrateUp(): Promise<void>;
|
|
122
|
+
/**
|
|
123
|
+
* Rollback migrations
|
|
124
|
+
* @param {number} [steps=1] - Number of migrations to rollback
|
|
125
|
+
* @returns {Promise<string[]>} Names of rolled back migrations
|
|
126
|
+
*/
|
|
127
|
+
migrateDown(steps?: number): Promise<string[]>;
|
|
63
128
|
};
|
|
64
129
|
declare function database<const S extends readonly AnyTableDef[] | Record<string, any>>(config: DatabaseConfig & {
|
|
65
130
|
schemas: S;
|
package/dist/core/database.mjs
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
|
+
import { __esmMin } from "../_virtual/_rolldown/runtime.mjs";
|
|
1
2
|
import { MIGRATIONS_TABLE, init_constants } from "../constants.mjs";
|
|
2
3
|
import { CacheManager } from "../cache/manager.mjs";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
4
|
+
import { init_cache } from "../cache/index.mjs";
|
|
5
|
+
import { DatabaseError, init_errors } from "../errors.mjs";
|
|
6
|
+
import { createDriver, init_drivers } from "../drivers/index.mjs";
|
|
5
7
|
import { SchemaRegistry } from "../schema/registry.mjs";
|
|
6
|
-
import {
|
|
8
|
+
import { init_schema } from "../schema/index.mjs";
|
|
9
|
+
import { TableRepository, init_repository } from "./repository.mjs";
|
|
7
10
|
//#region src/core/database.ts
|
|
8
|
-
init_constants();
|
|
9
11
|
/**
|
|
10
12
|
* Create a database instance with typed repositories for each schema
|
|
11
13
|
* @param {DatabaseConfig} config - Database configuration
|
|
@@ -23,7 +25,13 @@ function database(config) {
|
|
|
23
25
|
const schemas = normalizeSchemas(config.schemas);
|
|
24
26
|
const registry = new SchemaRegistry();
|
|
25
27
|
registry.register(schemas);
|
|
26
|
-
const
|
|
28
|
+
const dbName = typeof config.database === "string" ? config.database : config.database.name;
|
|
29
|
+
let connectionConfig;
|
|
30
|
+
if (Array.isArray(config.connection)) if (dbName === "sqlite") connectionConfig = config.connection.find((c) => "filename" in c) ?? config.connection[0];
|
|
31
|
+
else if (dbName === "mysql" || dbName === "mariadb") connectionConfig = config.connection.find((c) => "host" in c) ?? config.connection[0];
|
|
32
|
+
else if (dbName === "file") connectionConfig = config.connection.find((c) => "directory" in c) ?? config.connection[0];
|
|
33
|
+
else connectionConfig = config.connection[0];
|
|
34
|
+
else connectionConfig = config.connection;
|
|
27
35
|
if (!connectionConfig) throw new DatabaseError("Connection config is required");
|
|
28
36
|
const driver = createDriver(config.database, connectionConfig);
|
|
29
37
|
const cache = new CacheManager(config.cache);
|
|
@@ -82,6 +90,18 @@ function database(config) {
|
|
|
82
90
|
transaction: async (fn) => {
|
|
83
91
|
await ensureInitialized();
|
|
84
92
|
return driver.transaction(fn);
|
|
93
|
+
},
|
|
94
|
+
migrateUp: async () => {
|
|
95
|
+
await ensureInitialized();
|
|
96
|
+
if (config.migrations) {
|
|
97
|
+
const migrations = normalizeMigrations(config.migrations);
|
|
98
|
+
if (migrations.length > 0) await runMigrations(driver, registry, migrations);
|
|
99
|
+
}
|
|
100
|
+
},
|
|
101
|
+
migrateDown: async (steps = 1) => {
|
|
102
|
+
await ensureInitialized();
|
|
103
|
+
if (config.migrations) return rollbackMigrations(driver, registry, normalizeMigrations(config.migrations), steps);
|
|
104
|
+
return [];
|
|
85
105
|
}
|
|
86
106
|
};
|
|
87
107
|
for (const schema of schemas) {
|
|
@@ -98,8 +118,8 @@ function database(config) {
|
|
|
98
118
|
}
|
|
99
119
|
return instance;
|
|
100
120
|
}
|
|
101
|
-
|
|
102
|
-
|
|
121
|
+
function getMigrationsTableMeta() {
|
|
122
|
+
return {
|
|
103
123
|
name: MIGRATIONS_TABLE,
|
|
104
124
|
columns: [
|
|
105
125
|
{
|
|
@@ -132,40 +152,74 @@ async function runMigrations(driver, registry, migrations) {
|
|
|
132
152
|
}
|
|
133
153
|
]
|
|
134
154
|
};
|
|
135
|
-
|
|
155
|
+
}
|
|
156
|
+
function createMigrationContext(driver, registry) {
|
|
157
|
+
return {
|
|
158
|
+
schema: {
|
|
159
|
+
createTable: async (tableDef) => {
|
|
160
|
+
const meta = registry.getTable(tableDef.__name);
|
|
161
|
+
if (meta) await driver.createTable(meta);
|
|
162
|
+
},
|
|
163
|
+
dropTable: async (name) => {
|
|
164
|
+
await driver.dropTable(name);
|
|
165
|
+
},
|
|
166
|
+
addColumn: async (table, _name, column) => {
|
|
167
|
+
await driver.addColumn(table, column);
|
|
168
|
+
},
|
|
169
|
+
dropColumn: async (table, name) => {
|
|
170
|
+
await driver.dropColumn(table, name);
|
|
171
|
+
},
|
|
172
|
+
renameColumn: async (table, oldName, newName) => {
|
|
173
|
+
await driver.renameColumn(table, oldName, newName);
|
|
174
|
+
},
|
|
175
|
+
addIndex: async () => {},
|
|
176
|
+
dropIndex: async () => {}
|
|
177
|
+
},
|
|
178
|
+
sql: async (query, params) => {
|
|
179
|
+
return driver.execute(query, params);
|
|
180
|
+
}
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
async function ensureMigrationsTable(driver) {
|
|
184
|
+
if (!await driver.tableExists("__hedystia_migrations")) await driver.createTable(getMigrationsTableMeta());
|
|
185
|
+
}
|
|
186
|
+
async function runMigrations(driver, registry, migrations) {
|
|
187
|
+
await ensureMigrationsTable(driver);
|
|
136
188
|
const executed = await driver.query(`SELECT name FROM \`${MIGRATIONS_TABLE}\``);
|
|
137
189
|
const executedNames = new Set(executed.map((r) => r.name));
|
|
190
|
+
const ctx = createMigrationContext(driver, registry);
|
|
138
191
|
for (const migration of migrations) {
|
|
139
192
|
if (executedNames.has(migration.name)) continue;
|
|
140
|
-
await migration.up(
|
|
141
|
-
schema: {
|
|
142
|
-
createTable: async (tableDef) => {
|
|
143
|
-
const meta = registry.getTable(tableDef.__name);
|
|
144
|
-
if (meta) await driver.createTable(meta);
|
|
145
|
-
},
|
|
146
|
-
dropTable: async (name) => {
|
|
147
|
-
await driver.dropTable(name);
|
|
148
|
-
},
|
|
149
|
-
addColumn: async (table, _name, column) => {
|
|
150
|
-
await driver.addColumn(table, column);
|
|
151
|
-
},
|
|
152
|
-
dropColumn: async (table, name) => {
|
|
153
|
-
await driver.dropColumn(table, name);
|
|
154
|
-
},
|
|
155
|
-
renameColumn: async (table, oldName, newName) => {
|
|
156
|
-
await driver.renameColumn(table, oldName, newName);
|
|
157
|
-
},
|
|
158
|
-
addIndex: async () => {},
|
|
159
|
-
dropIndex: async () => {}
|
|
160
|
-
},
|
|
161
|
-
sql: async (query, params) => {
|
|
162
|
-
return driver.execute(query, params);
|
|
163
|
-
}
|
|
164
|
-
});
|
|
193
|
+
await migration.up(ctx);
|
|
165
194
|
await driver.execute(`INSERT INTO \`${MIGRATIONS_TABLE}\` (\`name\`, \`executed_at\`) VALUES (?, ?)`, [migration.name, /* @__PURE__ */ new Date()]);
|
|
166
195
|
}
|
|
167
196
|
}
|
|
197
|
+
async function rollbackMigrations(driver, registry, migrations, steps = 1) {
|
|
198
|
+
await ensureMigrationsTable(driver);
|
|
199
|
+
const executedNames = (await driver.query(`SELECT name FROM \`${MIGRATIONS_TABLE}\` ORDER BY id DESC`)).map((r) => r.name);
|
|
200
|
+
const ctx = createMigrationContext(driver, registry);
|
|
201
|
+
const migrationMap = new Map(migrations.map((m) => [m.name, m]));
|
|
202
|
+
const rolledBack = [];
|
|
203
|
+
const toRollback = executedNames.slice(0, steps);
|
|
204
|
+
for (const name of toRollback) {
|
|
205
|
+
const migration = migrationMap.get(name);
|
|
206
|
+
if (!migration) continue;
|
|
207
|
+
await migration.down(ctx);
|
|
208
|
+
await driver.execute(`DELETE FROM \`${MIGRATIONS_TABLE}\` WHERE \`name\` = ?`, [name]);
|
|
209
|
+
rolledBack.push(name);
|
|
210
|
+
}
|
|
211
|
+
return rolledBack;
|
|
212
|
+
}
|
|
213
|
+
var init_database = __esmMin((() => {
|
|
214
|
+
init_cache();
|
|
215
|
+
init_constants();
|
|
216
|
+
init_drivers();
|
|
217
|
+
init_errors();
|
|
218
|
+
init_schema();
|
|
219
|
+
init_repository();
|
|
220
|
+
}));
|
|
168
221
|
//#endregion
|
|
169
|
-
|
|
222
|
+
init_database();
|
|
223
|
+
export { database, init_database };
|
|
170
224
|
|
|
171
225
|
//# sourceMappingURL=database.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"database.mjs","names":[],"sources":["../../src/core/database.ts"],"sourcesContent":["import { CacheManager } from \"../cache\";\nimport { MIGRATIONS_TABLE } from \"../constants\";\nimport { createDriver } from \"../drivers\";\nimport { DatabaseError } from \"../errors\";\nimport { SchemaRegistry } from \"../schema\";\nimport type {\n AnyTableDef,\n ConnectionConfig,\n DatabaseConfig,\n DatabaseDriver,\n DeleteOptions,\n InferRow,\n InferSchemas,\n MigrationDefinition,\n QueryOptions,\n RelationQueryMap,\n ResolveResult,\n TableMetadata,\n UpdateOptions,\n WhereClause,\n} from \"../types\";\nimport { TableRepository } from \"./repository\";\n\ntype TypedTableRepository<S extends readonly AnyTableDef[], T extends AnyTableDef> = {\n find<O extends QueryOptions<InferRow<T>, RelationQueryMap<S, T>> = {}>(\n options?: O,\n ): Promise<ResolveResult<S, T, O>[]>;\n\n findMany<O extends QueryOptions<InferRow<T>, RelationQueryMap<S, T>> = {}>(\n options?: O,\n ): Promise<ResolveResult<S, T, O>[]>;\n\n findFirst<O extends QueryOptions<InferRow<T>, RelationQueryMap<S, T>> = {}>(\n options?: O,\n ): Promise<ResolveResult<S, T, O> | null>;\n\n insert(data: Partial<InferRow<T>> | Partial<InferRow<T>>[]): Promise<InferRow<T>>;\n insertMany(data: Partial<InferRow<T>>[]): Promise<InferRow<T>[]>;\n update(options: UpdateOptions<InferRow<T>>): Promise<InferRow<T>[]>;\n delete(options: DeleteOptions<InferRow<T>>): Promise<number>;\n count(options?: Pick<QueryOptions<InferRow<T>>, \"where\">): Promise<number>;\n exists(options: Pick<QueryOptions<InferRow<T>>, \"where\">): Promise<boolean>;\n upsert(options: {\n where: WhereClause<InferRow<T>>;\n create: Partial<InferRow<T>>;\n update: Partial<InferRow<T>>;\n }): Promise<InferRow<T>>;\n truncate(): Promise<void>;\n};\n\ntype ExtractRepos<S> = S extends readonly AnyTableDef[]\n ? { [T in S[number] as T[\"__name\"]]: TypedTableRepository<S, T> }\n : S extends Record<string, any>\n ? {\n [K in keyof S as S[K] extends AnyTableDef ? K : never]: TypedTableRepository<\n InferSchemas<S>,\n Extract<S[K], AnyTableDef>\n >;\n }\n : never;\n\ntype DatabaseInstance<S> = ExtractRepos<S> & {\n /**\n * Initialize the database connection, create tables and run migrations\n * @returns {Promise<void>}\n */\n initialize(): Promise<void>;\n /**\n * Close the database connection\n * @returns {Promise<void>}\n */\n close(): Promise<void>;\n /**\n * Get the underlying database driver\n * @returns {DatabaseDriver} The database driver\n */\n getDriver(): DatabaseDriver;\n /**\n * Get the schema registry\n * @returns {SchemaRegistry} The schema registry\n */\n getRegistry(): SchemaRegistry;\n /**\n * Get the cache manager\n * @returns {CacheManager} The cache manager\n */\n getCache(): CacheManager;\n /**\n * Execute a raw SQL query\n * @param {string} sql - SQL query\n * @param {unknown[]} [params] - Query parameters\n * @returns {Promise<any[]>} Query results\n */\n raw(sql: string, params?: unknown[]): Promise<any[]>;\n /**\n * Execute within a transaction\n * @param {() => Promise<T>} fn - Function to execute\n * @returns {Promise<T>} Result\n */\n transaction<T>(fn: () => Promise<T>): Promise<T>;\n};\n\n/**\n * Create a database instance with typed repositories for each schema\n * @param {DatabaseConfig} config - Database configuration\n * @returns {DatabaseInstance<S>} Database instance with table repositories\n */\nfunction normalizeMigrations(\n migrations: MigrationDefinition[] | Record<string, unknown>,\n): MigrationDefinition[] {\n if (Array.isArray(migrations)) {\n return migrations;\n }\n return Object.values(migrations).filter(\n (v): v is MigrationDefinition =>\n v != null && typeof v === \"object\" && \"name\" in v && \"up\" in v && \"down\" in v,\n );\n}\n\nfunction normalizeSchemas<S extends readonly AnyTableDef[]>(schemas: any): S {\n if (Array.isArray(schemas)) {\n return schemas as any as S;\n }\n return Object.values(schemas).filter(\n (v): v is AnyTableDef => v != null && typeof v === \"object\" && (v as any).__table === true,\n ) as any;\n}\n\nexport function database<const S extends readonly AnyTableDef[] | Record<string, any>>(\n config: DatabaseConfig & { schemas: S },\n): DatabaseInstance<S> {\n const schemas = normalizeSchemas(config.schemas) as any;\n const registry = new SchemaRegistry();\n registry.register(schemas);\n\n const connectionConfig = Array.isArray(config.connection)\n ? config.connection[0]\n : config.connection;\n\n if (!connectionConfig) {\n throw new DatabaseError(\"Connection config is required\");\n }\n\n const driver = createDriver(config.database, connectionConfig as ConnectionConfig);\n const cache = new CacheManager(config.cache);\n\n let initialized = false;\n let initPromise: Promise<void> | null = null;\n\n const ensureInitialized = async () => {\n if (initialized) {\n return;\n }\n if (initPromise) {\n return initPromise;\n }\n initPromise = doInit();\n await initPromise;\n initialized = true;\n };\n\n const doInit = async () => {\n await driver.connect();\n\n if (config.syncSchemas) {\n const allMetadata = driver.getAllTableColumns ? await driver.getAllTableColumns() : null;\n\n const syncPromises = Array.from(registry.getAllTables()).map(async ([, tableMeta]) => {\n const existingCols = allMetadata ? allMetadata[tableMeta.name] : null;\n const exists = allMetadata ? !!existingCols : await driver.tableExists(tableMeta.name);\n\n if (!exists) {\n await driver.createTable(tableMeta);\n } else {\n const cols = existingCols || (await driver.getTableColumns(tableMeta.name));\n const existingNames = new Set(cols.map((c) => c.name));\n const addColumnPromises = tableMeta.columns\n .filter((colMeta) => !existingNames.has(colMeta.name))\n .map((colMeta) => driver.addColumn(tableMeta.name, colMeta));\n await Promise.all(addColumnPromises);\n }\n });\n await Promise.all(syncPromises);\n }\n\n if (config.runMigrations && config.migrations) {\n const migrations = normalizeMigrations(config.migrations);\n if (migrations.length > 0) {\n await runMigrations(driver, registry, migrations);\n }\n }\n };\n\n const repos = new Map<string, TableRepository<any>>();\n for (const schema of schemas) {\n const repo = new TableRepository(schema.__name, driver, cache, registry, schema.__cache);\n repos.set(schema.__name, repo);\n }\n\n const instance: any = {\n initialize: async () => {\n await ensureInitialized();\n },\n close: async () => {\n await driver.disconnect();\n cache.clear();\n initialized = false;\n initPromise = null;\n },\n getDriver: () => driver,\n getRegistry: () => registry,\n getCache: () => cache,\n raw: async (sql: string, params?: unknown[]) => {\n await ensureInitialized();\n return driver.query(sql, params);\n },\n transaction: async <T>(fn: () => Promise<T>) => {\n await ensureInitialized();\n return driver.transaction(fn);\n },\n };\n\n for (const schema of schemas) {\n const repo = repos.get(schema.__name)!;\n const proxy = new Proxy(repo, {\n get(target, prop, receiver) {\n const original = Reflect.get(target, prop, receiver);\n if (typeof original === \"function\") {\n return async (...args: any[]) => {\n await ensureInitialized();\n return original.apply(target, args);\n };\n }\n return original;\n },\n });\n instance[schema.__name] = proxy;\n }\n\n return instance as any as DatabaseInstance<S>;\n}\n\nasync function runMigrations(\n driver: DatabaseDriver,\n registry: SchemaRegistry,\n migrations: MigrationDefinition[],\n): Promise<void> {\n const migrationsTableMeta: TableMetadata = {\n name: MIGRATIONS_TABLE,\n columns: [\n {\n name: \"id\",\n type: \"integer\",\n primaryKey: true,\n autoIncrement: true,\n notNull: true,\n unique: true,\n defaultValue: undefined,\n },\n {\n name: \"name\",\n type: \"varchar\",\n primaryKey: false,\n autoIncrement: false,\n notNull: true,\n unique: true,\n defaultValue: undefined,\n length: 255,\n },\n {\n name: \"executed_at\",\n type: \"datetime\",\n primaryKey: false,\n autoIncrement: false,\n notNull: true,\n unique: false,\n defaultValue: undefined,\n },\n ],\n };\n\n const exists = await driver.tableExists(MIGRATIONS_TABLE);\n if (!exists) {\n await driver.createTable(migrationsTableMeta);\n }\n\n const executed = await driver.query(`SELECT name FROM \\`${MIGRATIONS_TABLE}\\``);\n const executedNames = new Set(executed.map((r: any) => r.name));\n\n for (const migration of migrations) {\n if (executedNames.has(migration.name)) {\n continue;\n }\n\n const ctx = {\n schema: {\n createTable: async (tableDef: AnyTableDef) => {\n const meta = registry.getTable(tableDef.__name);\n if (meta) {\n await driver.createTable(meta);\n }\n },\n dropTable: async (name: string) => {\n await driver.dropTable(name);\n },\n addColumn: async (table: string, _name: string, column: any) => {\n await driver.addColumn(table, column);\n },\n dropColumn: async (table: string, name: string) => {\n await driver.dropColumn(table, name);\n },\n renameColumn: async (table: string, oldName: string, newName: string) => {\n await driver.renameColumn(table, oldName, newName);\n },\n addIndex: async () => {},\n dropIndex: async () => {},\n },\n sql: async (query: string, params?: unknown[]) => {\n return driver.execute(query, params);\n },\n };\n\n await migration.up(ctx);\n\n await driver.execute(\n `INSERT INTO \\`${MIGRATIONS_TABLE}\\` (\\`name\\`, \\`executed_at\\`) VALUES (?, ?)`,\n [migration.name, new Date()],\n );\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"database.mjs","names":[],"sources":["../../src/core/database.ts"],"sourcesContent":["import { CacheManager } from \"../cache\";\nimport { MIGRATIONS_TABLE } from \"../constants\";\nimport { createDriver } from \"../drivers\";\nimport { DatabaseError } from \"../errors\";\nimport { SchemaRegistry } from \"../schema\";\nimport type {\n AnyTableDef,\n ConnectionConfig,\n DatabaseConfig,\n DatabaseDriver,\n DeleteOptions,\n InferRow,\n InferSchemas,\n MigrationDefinition,\n QueryOptions,\n RelationQueryMap,\n ResolveResult,\n TableMetadata,\n UpdateOptions,\n WhereClause,\n} from \"../types\";\nimport { TableRepository } from \"./repository\";\n\ntype TypedTableRepository<S extends readonly AnyTableDef[], T extends AnyTableDef> = {\n /**\n * Find all rows matching the given options\n * @param options - Filter, sort, paginate, and eagerly load relations\n * @returns Array of matching rows\n */\n find<O extends QueryOptions<InferRow<T>, RelationQueryMap<S, T>> = {}>(\n options?: O,\n ): Promise<ResolveResult<S, T, O>[]>;\n\n /**\n * Find all rows matching the given options (alias for {@link find})\n * @param options - Filter, sort, paginate, and eagerly load relations\n * @returns Array of matching rows\n */\n findMany<O extends QueryOptions<InferRow<T>, RelationQueryMap<S, T>> = {}>(\n options?: O,\n ): Promise<ResolveResult<S, T, O>[]>;\n\n /**\n * Find the first row matching the given options\n * @param options - Filter, sort, and eagerly load relations\n * @returns The first matching row, or `null` if none found\n */\n findFirst<O extends QueryOptions<InferRow<T>, RelationQueryMap<S, T>> = {}>(\n options?: O,\n ): Promise<ResolveResult<S, T, O> | null>;\n\n /**\n * Insert one or more rows into the table\n * @param data - Row data (or array of row data) to insert\n * @returns The inserted row\n */\n insert(data: Partial<InferRow<T>> | Partial<InferRow<T>>[]): Promise<InferRow<T>>;\n\n /**\n * Insert multiple rows into the table\n * @param data - Array of row data to insert\n * @returns Array of inserted rows\n */\n insertMany(data: Partial<InferRow<T>>[]): Promise<InferRow<T>[]>;\n\n /**\n * Update rows matching the where clause\n * @param options - Where clause and partial data to apply\n * @returns Array of updated rows\n */\n update(options: UpdateOptions<InferRow<T>>): Promise<InferRow<T>[]>;\n\n /**\n * Delete rows matching the where clause\n * @param options - Where clause to select rows for deletion\n * @returns Number of deleted rows\n */\n delete(options: DeleteOptions<InferRow<T>>): Promise<number>;\n\n /**\n * Count rows matching the where clause\n * @param options - Optional where clause to filter rows\n * @returns Number of matching rows\n */\n count(options?: Pick<QueryOptions<InferRow<T>>, \"where\">): Promise<number>;\n\n /**\n * Check whether at least one row matches the where clause\n * @param options - Where clause to check\n * @returns `true` if a matching row exists, `false` otherwise\n */\n exists(options: Pick<QueryOptions<InferRow<T>>, \"where\">): Promise<boolean>;\n\n /**\n * Insert a row if it doesn't exist, or update it if it does\n * @param options - Where clause to check, data to create, and data to update\n * @returns The created or updated row\n */\n upsert(options: {\n where: WhereClause<InferRow<T>>;\n create: Partial<InferRow<T>>;\n update: Partial<InferRow<T>>;\n }): Promise<InferRow<T>>;\n\n /**\n * Remove all rows from the table\n * @returns Resolves when the table has been truncated\n */\n truncate(): Promise<void>;\n};\n\ntype ExtractRepos<S> = S extends readonly AnyTableDef[]\n ? { [T in S[number] as T[\"__name\"]]: TypedTableRepository<S, T> }\n : S extends Record<string, any>\n ? {\n [K in keyof S as S[K] extends AnyTableDef ? K : never]: TypedTableRepository<\n InferSchemas<S>,\n Extract<S[K], AnyTableDef>\n >;\n }\n : never;\n\ntype DatabaseInstance<S> = ExtractRepos<S> & {\n /**\n * Initialize the database connection, create tables and run migrations\n * @returns {Promise<void>}\n */\n initialize(): Promise<void>;\n /**\n * Close the database connection\n * @returns {Promise<void>}\n */\n close(): Promise<void>;\n /**\n * Get the underlying database driver\n * @returns {DatabaseDriver} The database driver\n */\n getDriver(): DatabaseDriver;\n /**\n * Get the schema registry\n * @returns {SchemaRegistry} The schema registry\n */\n getRegistry(): SchemaRegistry;\n /**\n * Get the cache manager\n * @returns {CacheManager} The cache manager\n */\n getCache(): CacheManager;\n /**\n * Execute a raw SQL query\n * @param {string} sql - SQL query\n * @param {unknown[]} [params] - Query parameters\n * @returns {Promise<any[]>} Query results\n */\n raw(sql: string, params?: unknown[]): Promise<any[]>;\n /**\n * Execute within a transaction\n * @param {() => Promise<T>} fn - Function to execute\n * @returns {Promise<T>} Result\n */\n transaction<T>(fn: () => Promise<T>): Promise<T>;\n /**\n * Run pending migrations manually\n * @returns {Promise<void>}\n */\n migrateUp(): Promise<void>;\n /**\n * Rollback migrations\n * @param {number} [steps=1] - Number of migrations to rollback\n * @returns {Promise<string[]>} Names of rolled back migrations\n */\n migrateDown(steps?: number): Promise<string[]>;\n};\n\n/**\n * Create a database instance with typed repositories for each schema\n * @param {DatabaseConfig} config - Database configuration\n * @returns {DatabaseInstance<S>} Database instance with table repositories\n */\nfunction normalizeMigrations(\n migrations: MigrationDefinition[] | Record<string, unknown>,\n): MigrationDefinition[] {\n if (Array.isArray(migrations)) {\n return migrations;\n }\n return Object.values(migrations).filter(\n (v): v is MigrationDefinition =>\n v != null && typeof v === \"object\" && \"name\" in v && \"up\" in v && \"down\" in v,\n );\n}\n\nfunction normalizeSchemas<S extends readonly AnyTableDef[]>(schemas: any): S {\n if (Array.isArray(schemas)) {\n return schemas as any as S;\n }\n return Object.values(schemas).filter(\n (v): v is AnyTableDef => v != null && typeof v === \"object\" && (v as any).__table === true,\n ) as any;\n}\n\nexport function database<const S extends readonly AnyTableDef[] | Record<string, any>>(\n config: DatabaseConfig & { schemas: S },\n): DatabaseInstance<S> {\n const schemas = normalizeSchemas(config.schemas) as any;\n const registry = new SchemaRegistry();\n registry.register(schemas);\n\n const dbName = typeof config.database === \"string\" ? config.database : config.database.name;\n\n let connectionConfig: ConnectionConfig | undefined;\n if (Array.isArray(config.connection)) {\n if (dbName === \"sqlite\") {\n connectionConfig = config.connection.find((c) => \"filename\" in c) ?? config.connection[0];\n } else if (dbName === \"mysql\" || dbName === \"mariadb\") {\n connectionConfig = config.connection.find((c) => \"host\" in c) ?? config.connection[0];\n } else if (dbName === \"file\") {\n connectionConfig = config.connection.find((c) => \"directory\" in c) ?? config.connection[0];\n } else {\n connectionConfig = config.connection[0];\n }\n } else {\n connectionConfig = config.connection;\n }\n\n if (!connectionConfig) {\n throw new DatabaseError(\"Connection config is required\");\n }\n\n const driver = createDriver(config.database, connectionConfig as ConnectionConfig);\n const cache = new CacheManager(config.cache);\n\n let initialized = false;\n let initPromise: Promise<void> | null = null;\n\n const ensureInitialized = async () => {\n if (initialized) {\n return;\n }\n if (initPromise) {\n return initPromise;\n }\n initPromise = doInit();\n await initPromise;\n initialized = true;\n };\n\n const doInit = async () => {\n await driver.connect();\n\n if (config.syncSchemas) {\n const allMetadata = driver.getAllTableColumns ? await driver.getAllTableColumns() : null;\n\n const syncPromises = Array.from(registry.getAllTables()).map(async ([, tableMeta]) => {\n const existingCols = allMetadata ? allMetadata[tableMeta.name] : null;\n const exists = allMetadata ? !!existingCols : await driver.tableExists(tableMeta.name);\n\n if (!exists) {\n await driver.createTable(tableMeta);\n } else {\n const cols = existingCols || (await driver.getTableColumns(tableMeta.name));\n const existingNames = new Set(cols.map((c) => c.name));\n const addColumnPromises = tableMeta.columns\n .filter((colMeta) => !existingNames.has(colMeta.name))\n .map((colMeta) => driver.addColumn(tableMeta.name, colMeta));\n await Promise.all(addColumnPromises);\n }\n });\n await Promise.all(syncPromises);\n }\n\n if (config.runMigrations && config.migrations) {\n const migrations = normalizeMigrations(config.migrations);\n if (migrations.length > 0) {\n await runMigrations(driver, registry, migrations);\n }\n }\n };\n\n const repos = new Map<string, TableRepository<any>>();\n for (const schema of schemas) {\n const repo = new TableRepository(schema.__name, driver, cache, registry, schema.__cache);\n repos.set(schema.__name, repo);\n }\n\n const instance: any = {\n initialize: async () => {\n await ensureInitialized();\n },\n close: async () => {\n await driver.disconnect();\n cache.clear();\n initialized = false;\n initPromise = null;\n },\n getDriver: () => driver,\n getRegistry: () => registry,\n getCache: () => cache,\n raw: async (sql: string, params?: unknown[]) => {\n await ensureInitialized();\n return driver.query(sql, params);\n },\n transaction: async <T>(fn: () => Promise<T>) => {\n await ensureInitialized();\n return driver.transaction(fn);\n },\n migrateUp: async () => {\n await ensureInitialized();\n if (config.migrations) {\n const migrations = normalizeMigrations(config.migrations);\n if (migrations.length > 0) {\n await runMigrations(driver, registry, migrations);\n }\n }\n },\n migrateDown: async (steps = 1) => {\n await ensureInitialized();\n if (config.migrations) {\n const migrations = normalizeMigrations(config.migrations);\n return rollbackMigrations(driver, registry, migrations, steps);\n }\n return [];\n },\n };\n\n for (const schema of schemas) {\n const repo = repos.get(schema.__name)!;\n const proxy = new Proxy(repo, {\n get(target, prop, receiver) {\n const original = Reflect.get(target, prop, receiver);\n if (typeof original === \"function\") {\n return async (...args: any[]) => {\n await ensureInitialized();\n return original.apply(target, args);\n };\n }\n return original;\n },\n });\n instance[schema.__name] = proxy;\n }\n\n return instance as any as DatabaseInstance<S>;\n}\n\nfunction getMigrationsTableMeta(): TableMetadata {\n return {\n name: MIGRATIONS_TABLE,\n columns: [\n {\n name: \"id\",\n type: \"integer\",\n primaryKey: true,\n autoIncrement: true,\n notNull: true,\n unique: true,\n defaultValue: undefined,\n },\n {\n name: \"name\",\n type: \"varchar\",\n primaryKey: false,\n autoIncrement: false,\n notNull: true,\n unique: true,\n defaultValue: undefined,\n length: 255,\n },\n {\n name: \"executed_at\",\n type: \"datetime\",\n primaryKey: false,\n autoIncrement: false,\n notNull: true,\n unique: false,\n defaultValue: undefined,\n },\n ],\n };\n}\n\nfunction createMigrationContext(\n driver: DatabaseDriver,\n registry: SchemaRegistry,\n): MigrationDefinition[\"up\"] extends (ctx: infer C) => any ? C : never {\n return {\n schema: {\n createTable: async (tableDef: AnyTableDef) => {\n const meta = registry.getTable(tableDef.__name);\n if (meta) {\n await driver.createTable(meta);\n }\n },\n dropTable: async (name: string) => {\n await driver.dropTable(name);\n },\n addColumn: async (table: string, _name: string, column: any) => {\n await driver.addColumn(table, column);\n },\n dropColumn: async (table: string, name: string) => {\n await driver.dropColumn(table, name);\n },\n renameColumn: async (table: string, oldName: string, newName: string) => {\n await driver.renameColumn(table, oldName, newName);\n },\n addIndex: async () => {},\n dropIndex: async () => {},\n },\n sql: async (query: string, params?: unknown[]) => {\n return driver.execute(query, params);\n },\n };\n}\n\nasync function ensureMigrationsTable(driver: DatabaseDriver): Promise<void> {\n const exists = await driver.tableExists(MIGRATIONS_TABLE);\n if (!exists) {\n await driver.createTable(getMigrationsTableMeta());\n }\n}\n\nasync function runMigrations(\n driver: DatabaseDriver,\n registry: SchemaRegistry,\n migrations: MigrationDefinition[],\n): Promise<void> {\n await ensureMigrationsTable(driver);\n\n const executed = await driver.query(`SELECT name FROM \\`${MIGRATIONS_TABLE}\\``);\n const executedNames = new Set(executed.map((r: any) => r.name));\n\n const ctx = createMigrationContext(driver, registry);\n\n for (const migration of migrations) {\n if (executedNames.has(migration.name)) {\n continue;\n }\n\n await migration.up(ctx);\n\n await driver.execute(\n `INSERT INTO \\`${MIGRATIONS_TABLE}\\` (\\`name\\`, \\`executed_at\\`) VALUES (?, ?)`,\n [migration.name, new Date()],\n );\n }\n}\n\nasync function rollbackMigrations(\n driver: DatabaseDriver,\n registry: SchemaRegistry,\n migrations: MigrationDefinition[],\n steps = 1,\n): Promise<string[]> {\n await ensureMigrationsTable(driver);\n\n const executed = await driver.query(`SELECT name FROM \\`${MIGRATIONS_TABLE}\\` ORDER BY id DESC`);\n const executedNames = executed.map((r: any) => r.name as string);\n\n const ctx = createMigrationContext(driver, registry);\n const migrationMap = new Map(migrations.map((m) => [m.name, m]));\n const rolledBack: string[] = [];\n\n const toRollback = executedNames.slice(0, steps);\n\n for (const name of toRollback) {\n const migration = migrationMap.get(name);\n if (!migration) {\n continue;\n }\n\n await migration.down(ctx);\n\n await driver.execute(`DELETE FROM \\`${MIGRATIONS_TABLE}\\` WHERE \\`name\\` = ?`, [name]);\n rolledBack.push(name);\n }\n\n return rolledBack;\n}\n"],"mappings":"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"}
|