mevn-orm 3.2.2 → 4.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,63 +1,385 @@
1
1
  # Mevn ORM
2
2
 
3
- ![npm](https://img.shields.io/npm/v/mevn-orm?style=for-the-badge) [![GitHub license](https://img.shields.io/github/license/stanleymasinde/mevn-orm?style=for-the-badge)](https://github.com/StanleyMasinde/mevn-orm/blob/master/LICENSE) ![GitHub issues](https://img.shields.io/github/issues/stanleymasinde/mevn-orm?style=for-the-badge)
3
+ ![npm](https://img.shields.io/npm/v/mevn-orm?style=for-the-badge)
4
+ [![GitHub license](https://img.shields.io/github/license/stanleymasinde/mevn-orm?style=for-the-badge)](https://github.com/StanleyMasinde/mevn-orm/blob/master/LICENSE)
5
+ ![GitHub issues](https://img.shields.io/github/issues/stanleymasinde/mevn-orm?style=for-the-badge)
4
6
 
5
- ### Do not use This
6
- When I started this, I had so much intertest in the JS ecosytem and ORMs. I still have some intertest in javascript
7
- bit not ORMs.
7
+ Mevn ORM is a small ActiveRecord-style ORM built on top of Knex.
8
8
 
9
- **Mevn ORM** is a lightweight ORM for Express.js and MySQL that provides a clean, fluent interface for building queries and managing models.
10
- It is under maintenance mode and receives security updates. Development is paused, but the core ORM functionality is complete and usable.
9
+ It exports:
10
+ - `Model`: base class for your models
11
+ - `configureDatabase`: initialize with simple DB options by dialect
12
+ - `configure`: initialize with raw Knex config (advanced)
13
+ - migration helpers: `makeMigration`, `migrateLatest`, `migrateRollback`, `migrateList`, `migrateCurrentVersion`
14
+ - `DB`: initialized Knex instance (after `configure`)
11
15
 
12
- ## Getting Started
16
+ ## Status
13
17
 
14
- ```javascript
15
- const { Model } = require('mevn-orm')
18
+ This project is in maintenance mode. Core functionality works, but new features are limited.
16
19
 
17
- class User extends Model {}
20
+ ## Requirements
18
21
 
19
- const user = await User.create({
20
- name: 'John Doe',
21
- email: 'john@example.com',
22
- password: 'secret' // hash before storing
22
+ - Node.js 20+ (ESM runtime)
23
+ - Database driver for your selected client (`mysql2`, `sqlite3`, etc.)
24
+
25
+ ## Installation
26
+
27
+ ```bash
28
+ npm install mevn-orm knex mysql2
29
+ ```
30
+
31
+ For SQLite development/testing:
32
+
33
+ ```bash
34
+ npm install sqlite3
35
+ ```
36
+
37
+ ## Quick Start
38
+
39
+ ### 1) Configure Mevn ORM
40
+
41
+ ```ts
42
+ import { configureDatabase } from 'mevn-orm'
43
+
44
+ configureDatabase({
45
+ dialect: 'sqlite',
46
+ filename: './dev.sqlite'
47
+ })
48
+ ```
49
+
50
+ Supported dialects:
51
+ - `sqlite`, `better-sqlite3`
52
+ - `mysql`, `mysql2`
53
+ - `postgres`, `postgresql`, `pg`, `pgnative`
54
+ - `cockroachdb`, `redshift`
55
+ - `mssql`
56
+ - `oracledb`, `oracle`
57
+
58
+ Connection styles:
59
+ - `connectionString` for one-string connection setup
60
+ - field-based setup (`host`, `port`, `user`, `password`, `database`)
61
+ - sqlite file setup via `filename`
62
+
63
+ ### 2) Define a model
64
+
65
+ ```ts
66
+ import { Model } from 'mevn-orm'
67
+
68
+ class User extends Model {
69
+ override fillable = ['name', 'email', 'password']
70
+ override hidden = ['password']
71
+ }
72
+ ```
73
+
74
+ ### 3) Use it
75
+
76
+ ```ts
77
+ const created = await User.create({
78
+ name: 'Jane Doe',
79
+ email: 'jane@example.com',
80
+ password: 'hash-me-first'
81
+ })
82
+
83
+ const found = await User.find(created.id as number)
84
+ await found?.update({ name: 'Jane Updated' })
85
+ ```
86
+
87
+ ## API Reference
88
+
89
+ ### Exports
90
+
91
+ - `Model`
92
+ - `configureDatabase(config): Knex`
93
+ - `createKnexConfig(config): Knex.Config`
94
+ - `configure(config: Knex.Config | Knex): Knex`
95
+ - `getDB(): Knex`
96
+ - `DB` (Knex instance once configured)
97
+ - `setMigrationConfig(config): MigrationConfig`
98
+ - `getMigrationConfig(): MigrationConfig`
99
+ - `makeMigration(name, config?): Promise<string>`
100
+ - `migrateLatest(config?): Promise<{ batch: number; log: string[] }>`
101
+ - `migrateRollback(config?, all?): Promise<{ batch: number; log: string[] }>`
102
+ - `migrateCurrentVersion(config?): Promise<string>`
103
+ - `migrateList(config?): Promise<{ completed: string[]; pending: string[] }>`
104
+
105
+ ### Model instance members
106
+
107
+ - `fillable: string[]`
108
+ - Attributes allowed through `save()`.
109
+ - `hidden: string[]`
110
+ - Attributes removed when serializing model results.
111
+ - `table: string`
112
+ - Inferred from class name using pluralization (for `User` -> `users`).
113
+ - `id?: number`
114
+
115
+ ### Instance methods
116
+
117
+ - `save(): Promise<this>`
118
+ - Inserts record using only `fillable` fields.
119
+ - `update(properties): Promise<this>`
120
+ - Updates by `id`, then reloads from DB.
121
+ - `delete(): Promise<void>`
122
+ - Deletes current row by `id`.
123
+ - `hasOne(RelatedModel, localKey?, foreignKey?): Promise<Model | null>`
124
+ - Loads one related record.
125
+ - `hasMany(RelatedModel, localKey?, foreignKey?): Promise<Model[]>`
126
+ - Loads related records by foreign key.
127
+ - `belongsTo(RelatedModel, foreignKey?, ownerKey?): Promise<Model | null>`
128
+ - Loads the owning/parent record.
129
+
130
+ ### Static methods
131
+
132
+ - `find(id, columns = '*'): Promise<Model | null>`
133
+ - `findOrFail(id, columns = '*'): Promise<Model>`
134
+ - `create(properties): Promise<Model>`
135
+ - `createMany(properties[]): Promise<Model[]>`
136
+ - `firstOrCreate(attributes, values = {}): Promise<Model>`
137
+ - `where(conditions = {}): typeof Model`
138
+ - `first(columns = '*'): Promise<Model | null>`
139
+ - `all(columns = '*'): Promise<Model[]>`
140
+ - `count(column = '*'): Promise<number>`
141
+ - `update(properties): Promise<number | undefined>`
142
+ - `destroy(): Promise<number | undefined>`
143
+
144
+ ## Using `DB` directly
145
+
146
+ You can always drop down to Knex after configuration:
147
+
148
+ ```ts
149
+ import { configureDatabase, DB } from 'mevn-orm'
150
+
151
+ configureDatabase({
152
+ dialect: 'sqlite',
153
+ filename: './dev.sqlite'
154
+ })
155
+ const users = await DB('users').select('*')
156
+ ```
157
+
158
+ ## More Configuration Examples
159
+
160
+ ```ts
161
+ import { configureDatabase } from 'mevn-orm'
162
+
163
+ // MySQL / mysql2
164
+ configureDatabase({
165
+ dialect: 'mysql',
166
+ host: '127.0.0.1',
167
+ port: 3306,
168
+ user: 'root',
169
+ password: 'secret',
170
+ database: 'app_db'
171
+ })
172
+
173
+ // Postgres
174
+ configureDatabase({
175
+ dialect: 'postgres',
176
+ connectionString: process.env.DATABASE_URL
177
+ })
178
+
179
+ // MSSQL
180
+ configureDatabase({
181
+ dialect: 'mssql',
182
+ host: '127.0.0.1',
183
+ user: 'sa',
184
+ password: 'StrongPassword!',
185
+ database: 'app_db',
186
+ ssl: true
187
+ })
188
+ ```
189
+
190
+ ## Nuxt/Nitro Example
191
+
192
+ Use a server plugin to initialize the ORM once at Nitro startup.
193
+ You can also run idempotent migrations (and optional rollback) during boot.
194
+
195
+ Because Nitro bundles server code, migration files must be copied into the build output.
196
+
197
+ `nuxt.config.ts`:
198
+
199
+ ```ts
200
+ import { cp } from 'node:fs/promises'
201
+
202
+ export default defineNuxtConfig({
203
+ nitro: {
204
+ hooks: {
205
+ compiled: async () => {
206
+ await cp('server/assets/migrations', '.output/server/assets/migrations', {
207
+ recursive: true
208
+ })
209
+ }
210
+ }
211
+ }
212
+ })
213
+ ```
214
+
215
+ `server/plugins/mevn-orm.ts`:
216
+
217
+ ```ts
218
+ import { defineNitroPlugin } from 'nitropack/runtime'
219
+ import { existsSync } from 'node:fs'
220
+ import {
221
+ configureDatabase,
222
+ setMigrationConfig,
223
+ migrateLatest,
224
+ migrateRollback
225
+ } from 'mevn-orm'
226
+
227
+ const isIgnorableMigrationError = (error: unknown): boolean => {
228
+ const message = error instanceof Error ? error.message.toLowerCase() : String(error).toLowerCase()
229
+ return (
230
+ message.includes('already exists') ||
231
+ message.includes('duplicate') ||
232
+ message.includes('does not exist') ||
233
+ message.includes('no such table') ||
234
+ message.includes('the migration directory is corrupt')
235
+ )
236
+ }
237
+
238
+ export default defineNitroPlugin(async () => {
239
+ configureDatabase({
240
+ dialect: 'postgres',
241
+ connectionString: process.env.DATABASE_URL
242
+ })
243
+
244
+ // Nitro runtime path differs in dev vs built server.
245
+ const migrationDirectory = existsSync('./.output/server/assets/migrations')
246
+ ? './.output/server/assets/migrations'
247
+ : './server/assets/migrations'
248
+
249
+ setMigrationConfig({
250
+ directory: migrationDirectory,
251
+ extension: 'ts'
252
+ })
253
+
254
+ // Idempotent at boot: if already migrated, Knex returns empty log.
255
+ try {
256
+ await migrateLatest()
257
+ } catch (error) {
258
+ if (!isIgnorableMigrationError(error)) {
259
+ throw error
260
+ }
261
+ }
262
+
263
+ // Optional rollback at boot (usually only for dev/preview).
264
+ if (process.env.NITRO_ROLLBACK_ON_BOOT === 'true') {
265
+ try {
266
+ await migrateRollback(undefined, false)
267
+ } catch (error) {
268
+ if (!isIgnorableMigrationError(error)) {
269
+ throw error
270
+ }
271
+ }
272
+ }
273
+ })
274
+ ```
275
+
276
+ For fully idempotent behavior across SQL dialects, write migrations with guards
277
+ (`createTableIfNotExists`, checking column existence, or raw `IF EXISTS/IF NOT EXISTS`).
278
+
279
+ `server/models/User.ts`:
280
+
281
+ ```ts
282
+ import { Model } from 'mevn-orm'
283
+
284
+ export class User extends Model {
285
+ override fillable = ['name', 'email', 'password']
286
+ override hidden = ['password']
287
+ }
288
+ ```
289
+
290
+ `server/api/users.get.ts`:
291
+
292
+ ```ts
293
+ import { User } from '../models/User'
294
+
295
+ export default defineEventHandler(async () => {
296
+ return await User.all()
297
+ })
298
+ ```
299
+
300
+ `server/api/users.post.ts`:
301
+
302
+ ```ts
303
+ import { User } from '../models/User'
304
+
305
+ export default defineEventHandler(async (event) => {
306
+ const body = await readBody(event)
307
+ return await User.create({
308
+ name: body.name,
309
+ email: body.email,
310
+ password: body.password // hash before storing
311
+ })
312
+ })
313
+ ```
314
+
315
+ If you prefer Nuxt runtime config:
316
+
317
+ `nuxt.config.ts`:
318
+
319
+ ```ts
320
+ export default defineNuxtConfig({
321
+ runtimeConfig: {
322
+ db: {
323
+ dialect: 'postgres',
324
+ connectionString: process.env.DATABASE_URL
325
+ }
326
+ }
327
+ })
328
+ ```
329
+
330
+ ## Migrations
331
+
332
+ Migrations are now programmatic and use Knex’s migration API under the hood.
333
+
334
+ ```ts
335
+ import {
336
+ configureDatabase,
337
+ setMigrationConfig,
338
+ makeMigration,
339
+ migrateLatest,
340
+ migrateRollback,
341
+ migrateList
342
+ } from 'mevn-orm'
343
+
344
+ configureDatabase({
345
+ dialect: 'sqlite',
346
+ filename: './dev.sqlite'
23
347
  })
24
- ````
25
348
 
26
- ## Features
349
+ setMigrationConfig({
350
+ directory: './migrations',
351
+ extension: 'ts'
352
+ })
27
353
 
28
- * Model-based abstraction
29
- * Create, Read, Update, Delete support
30
- * Chainable query builder (`where`, `first`, `all`)
31
- * Timestamps
32
- * Soft deletes
33
- * SQLite support for testing
34
- * Knex-based migration support
354
+ await makeMigration('create_users_table')
355
+ await migrateLatest()
356
+ const { completed, pending } = await migrateList()
357
+ await migrateRollback(undefined, false) // rollback last batch
358
+ ```
35
359
 
36
- ## ORM Basics Checklist
360
+ Repository migration commands (no `knexfile` required):
37
361
 
38
- * [x] `Model` base class
39
- * [x] `.create`, `.find`, `.update`, `.delete`
40
- * [x] `.where()`, `.first()`, `.all()` chaining
41
- * [x] Table name inference
42
- * [x] Timestamps
43
- * [x] Soft deletes
44
- * [x] Basic relationship hooks (`hasOne`, `hasMany`, `belongsTo`)
45
- * [x] Raw queries
46
- * [x] Knex passthrough
47
- * [x] SQLite3 test DB
48
- * [x] Uses `mysql2` for production
49
- * [x] `dotenv` support
362
+ ```bash
363
+ pnpm run migrate
364
+ pnpm run migrate:make -- create_users_table
365
+ pnpm run migrate:rollback
366
+ pnpm run migrate:list
367
+ pnpm run migrate:version
368
+ ```
50
369
 
51
- ## Testing
370
+ ## Security Notes
52
371
 
53
- Use Node.js 24.x (LTS) with pnpm.
372
+ - Hash passwords before calling `create()` or `save()`.
373
+ - Validate and sanitize input before persisting.
374
+ - Keep `knex`, DB drivers, and Node.js versions up to date.
54
375
 
55
- This project uses [Mocha](https://mochajs.org/) for testing.
376
+ ## Development (Repository)
56
377
 
57
378
  ```bash
58
379
  pnpm install
59
380
  pnpm run migrate
60
381
  pnpm run test
382
+ pnpm run typecheck
61
383
  ```
62
384
 
63
385
  ## License
@@ -0,0 +1,2 @@
1
+ import { Model, DB, getDB, configure, createKnexConfig, configureDatabase, setMigrationConfig, getMigrationConfig, makeMigration, migrateLatest, migrateRollback, migrateCurrentVersion, migrateList } from './src/model.js';
2
+ export { Model, DB, getDB, configure, createKnexConfig, configureDatabase, setMigrationConfig, getMigrationConfig, makeMigration, migrateLatest, migrateRollback, migrateCurrentVersion, migrateList, };
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ import { Model, DB, getDB, configure, createKnexConfig, configureDatabase, setMigrationConfig, getMigrationConfig, makeMigration, migrateLatest, migrateRollback, migrateCurrentVersion, migrateList, } from './src/model.js';
2
+ export { Model, DB, getDB, configure, createKnexConfig, configureDatabase, setMigrationConfig, getMigrationConfig, makeMigration, migrateLatest, migrateRollback, migrateCurrentVersion, migrateList, };
@@ -0,0 +1,46 @@
1
+ import type { Knex } from 'knex';
2
+ declare let DB: Knex | undefined;
3
+ type SimpleDialect = 'sqlite' | 'better-sqlite3' | 'mysql' | 'mysql2' | 'postgres' | 'postgresql' | 'pg' | 'pgnative' | 'cockroachdb' | 'redshift' | 'mssql' | 'oracledb' | 'oracle';
4
+ interface SimpleDatabaseConfig {
5
+ dialect: SimpleDialect;
6
+ connectionString?: string;
7
+ filename?: string;
8
+ host?: string;
9
+ port?: number;
10
+ user?: string;
11
+ password?: string;
12
+ database?: string;
13
+ ssl?: boolean | Record<string, unknown>;
14
+ debug?: boolean;
15
+ pool?: Knex.PoolConfig;
16
+ }
17
+ interface MigrationResult {
18
+ batch: number;
19
+ log: string[];
20
+ }
21
+ /** Returns the active Knex instance or throws if the ORM has not been configured. */
22
+ declare const getDB: () => Knex;
23
+ /** Configures the ORM using a Knex config object or an existing Knex instance. */
24
+ declare const configure: (config: Knex.Config | Knex) => Knex;
25
+ /** Sets default migration options used by migration helpers. */
26
+ declare const setMigrationConfig: (config: Knex.MigratorConfig) => Knex.MigratorConfig;
27
+ /** Returns the currently configured default migration options. */
28
+ declare const getMigrationConfig: () => Knex.MigratorConfig;
29
+ /** Builds a Knex config from a simplified, dialect-first configuration object. */
30
+ declare const createKnexConfig: (config: SimpleDatabaseConfig) => Knex.Config;
31
+ /** Configures the ORM from simplified database options. */
32
+ declare const configureDatabase: (config: SimpleDatabaseConfig) => Knex;
33
+ /** Generates a migration file and returns its path. */
34
+ declare const makeMigration: (name: string, config?: Knex.MigratorConfig) => Promise<string>;
35
+ /** Runs pending migrations and returns the batch number and migration filenames. */
36
+ declare const migrateLatest: (config?: Knex.MigratorConfig) => Promise<MigrationResult>;
37
+ /** Rolls back migrations. Set `all` to true to rollback all completed batches. */
38
+ declare const migrateRollback: (config?: Knex.MigratorConfig, all?: boolean) => Promise<MigrationResult>;
39
+ /** Returns the current migration version recorded by Knex. */
40
+ declare const migrateCurrentVersion: (config?: Knex.MigratorConfig) => Promise<string>;
41
+ /** Returns completed and pending migration filenames. */
42
+ declare const migrateList: (config?: Knex.MigratorConfig) => Promise<{
43
+ completed: string[];
44
+ pending: string[];
45
+ }>;
46
+ export { DB, getDB, configure, createKnexConfig, configureDatabase, setMigrationConfig, getMigrationConfig, makeMigration, migrateLatest, migrateRollback, migrateCurrentVersion, migrateList, };
@@ -0,0 +1,196 @@
1
+ import knexModule from 'knex';
2
+ const knexFactory = knexModule.knex ??
3
+ knexModule;
4
+ const toError = (error) => {
5
+ if (error instanceof Error) {
6
+ return error;
7
+ }
8
+ return new Error(String(error));
9
+ };
10
+ let DB;
11
+ let defaultMigrationConfig = {};
12
+ /** Returns the active Knex instance or throws if the ORM has not been configured. */
13
+ const getDB = () => {
14
+ if (!DB) {
15
+ throw new Error('Mevn ORM is not configured. Call configure({ client, connection, ... }) before using Model.');
16
+ }
17
+ return DB;
18
+ };
19
+ /** Configures the ORM using a Knex config object or an existing Knex instance. */
20
+ const configure = (config) => {
21
+ if (typeof config === 'function') {
22
+ DB = config;
23
+ return DB;
24
+ }
25
+ DB = knexFactory(config);
26
+ return DB;
27
+ };
28
+ /** Sets default migration options used by migration helpers. */
29
+ const setMigrationConfig = (config) => {
30
+ defaultMigrationConfig = { ...config };
31
+ return { ...defaultMigrationConfig };
32
+ };
33
+ /** Returns the currently configured default migration options. */
34
+ const getMigrationConfig = () => ({ ...defaultMigrationConfig });
35
+ const resolveMigrationConfig = (config) => ({
36
+ ...defaultMigrationConfig,
37
+ ...(config ?? {}),
38
+ });
39
+ const normalizeDialect = (dialect) => {
40
+ switch (dialect) {
41
+ case 'sqlite':
42
+ return 'sqlite3';
43
+ case 'mysql':
44
+ return 'mysql2';
45
+ case 'postgres':
46
+ case 'postgresql':
47
+ case 'pg':
48
+ return 'pg';
49
+ case 'oracle':
50
+ return 'oracledb';
51
+ default:
52
+ return dialect;
53
+ }
54
+ };
55
+ const requireField = (value, field, dialect) => {
56
+ if (value === undefined || value === null || value === '') {
57
+ throw new Error(`Missing required field "${field}" for dialect "${dialect}".`);
58
+ }
59
+ };
60
+ const buildConnection = (config) => {
61
+ if (config.connectionString) {
62
+ return config.connectionString;
63
+ }
64
+ const client = normalizeDialect(config.dialect);
65
+ if (client === 'sqlite3' || client === 'better-sqlite3') {
66
+ requireField(config.filename, 'filename', config.dialect);
67
+ return { filename: config.filename };
68
+ }
69
+ if (client === 'mssql') {
70
+ const server = config.host;
71
+ requireField(server, 'host', config.dialect);
72
+ requireField(config.user, 'user', config.dialect);
73
+ requireField(config.database, 'database', config.dialect);
74
+ const connection = {
75
+ server: server,
76
+ user: config.user,
77
+ database: config.database,
78
+ };
79
+ if (typeof config.port === 'number') {
80
+ connection.port = config.port;
81
+ }
82
+ if (config.password !== undefined) {
83
+ connection.password = config.password;
84
+ }
85
+ if (config.ssl) {
86
+ connection.options = { encrypt: true };
87
+ }
88
+ return connection;
89
+ }
90
+ requireField(config.host, 'host', config.dialect);
91
+ requireField(config.user, 'user', config.dialect);
92
+ requireField(config.database, 'database', config.dialect);
93
+ const connection = {
94
+ host: config.host,
95
+ user: config.user,
96
+ database: config.database,
97
+ };
98
+ if (typeof config.port === 'number') {
99
+ connection.port = config.port;
100
+ }
101
+ if (config.password !== undefined) {
102
+ connection.password = config.password;
103
+ }
104
+ if (config.ssl !== undefined) {
105
+ connection.ssl = config.ssl;
106
+ }
107
+ return connection;
108
+ };
109
+ /** Builds a Knex config from a simplified, dialect-first configuration object. */
110
+ const createKnexConfig = (config) => {
111
+ const client = normalizeDialect(config.dialect);
112
+ const base = {
113
+ client,
114
+ connection: buildConnection(config),
115
+ };
116
+ if (config.pool) {
117
+ base.pool = config.pool;
118
+ }
119
+ if (typeof config.debug === 'boolean') {
120
+ base.debug = config.debug;
121
+ }
122
+ if (client === 'sqlite3') {
123
+ base.useNullAsDefault = true;
124
+ }
125
+ return base;
126
+ };
127
+ /** Configures the ORM from simplified database options. */
128
+ const configureDatabase = (config) => configure(createKnexConfig(config));
129
+ /** Generates a migration file and returns its path. */
130
+ const makeMigration = async (name, config) => {
131
+ try {
132
+ return await getDB().migrate.make(name, resolveMigrationConfig(config));
133
+ }
134
+ catch (error) {
135
+ throw toError(error);
136
+ }
137
+ };
138
+ /** Runs pending migrations and returns the batch number and migration filenames. */
139
+ const migrateLatest = async (config) => {
140
+ try {
141
+ const [batch, log] = await getDB().migrate.latest(resolveMigrationConfig(config));
142
+ return { batch, log };
143
+ }
144
+ catch (error) {
145
+ throw toError(error);
146
+ }
147
+ };
148
+ /** Rolls back migrations. Set `all` to true to rollback all completed batches. */
149
+ const migrateRollback = async (config, all = false) => {
150
+ try {
151
+ const [batch, log] = all
152
+ ? await getDB().migrate.rollback(resolveMigrationConfig(config), true)
153
+ : await getDB().migrate.rollback(resolveMigrationConfig(config));
154
+ return { batch, log };
155
+ }
156
+ catch (error) {
157
+ throw toError(error);
158
+ }
159
+ };
160
+ /** Returns the current migration version recorded by Knex. */
161
+ const migrateCurrentVersion = async (config) => {
162
+ try {
163
+ return await getDB().migrate.currentVersion(resolveMigrationConfig(config));
164
+ }
165
+ catch (error) {
166
+ throw toError(error);
167
+ }
168
+ };
169
+ /** Returns completed and pending migration filenames. */
170
+ const migrateList = async (config) => {
171
+ try {
172
+ const [completed, pending] = await getDB().migrate.list(resolveMigrationConfig(config));
173
+ const toName = (entry) => {
174
+ if (typeof entry === 'string') {
175
+ return entry;
176
+ }
177
+ if (entry && typeof entry === 'object') {
178
+ if ('name' in entry) {
179
+ return String(entry.name);
180
+ }
181
+ if ('file' in entry) {
182
+ return String(entry.file);
183
+ }
184
+ }
185
+ return String(entry);
186
+ };
187
+ return {
188
+ completed: completed.map(toName),
189
+ pending: pending.map(toName),
190
+ };
191
+ }
192
+ catch (error) {
193
+ throw toError(error);
194
+ }
195
+ };
196
+ export { DB, getDB, configure, createKnexConfig, configureDatabase, setMigrationConfig, getMigrationConfig, makeMigration, migrateLatest, migrateRollback, migrateCurrentVersion, migrateList, };