@bunnykit/orm 0.1.24 → 0.1.26
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 +100 -1
- package/dist/bin/bunny.js +41 -0
- package/dist/src/config/BunnyConfig.d.ts +1 -0
- package/dist/src/connection/Connection.d.ts +4 -1
- package/dist/src/connection/Connection.js +23 -1
- package/dist/src/connection/ConnectionManager.d.ts +15 -4
- package/dist/src/connection/ConnectionManager.js +50 -5
- package/dist/src/connection/TenantContext.d.ts +4 -0
- package/dist/src/index.d.ts +5 -2
- package/dist/src/index.js +2 -0
- package/dist/src/migration/Migrator.d.ts +30 -6
- package/dist/src/migration/Migrator.js +230 -45
- package/dist/src/schema/Schema.d.ts +24 -0
- package/dist/src/schema/Schema.js +182 -0
- package/dist/src/seeding/Factory.d.ts +19 -0
- package/dist/src/seeding/Factory.js +56 -0
- package/dist/src/seeding/Seeder.d.ts +16 -0
- package/dist/src/seeding/Seeder.js +80 -0
- package/package.json +1 -1
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
export class Factory {
|
|
2
|
+
model;
|
|
3
|
+
definition;
|
|
4
|
+
amount = 1;
|
|
5
|
+
states = [];
|
|
6
|
+
constructor(model, definition) {
|
|
7
|
+
this.model = model;
|
|
8
|
+
this.definition = definition;
|
|
9
|
+
}
|
|
10
|
+
count(amount) {
|
|
11
|
+
const next = this.clone();
|
|
12
|
+
next.amount = Math.max(0, amount);
|
|
13
|
+
return next;
|
|
14
|
+
}
|
|
15
|
+
state(state) {
|
|
16
|
+
const next = this.clone();
|
|
17
|
+
next.states = [...next.states, state];
|
|
18
|
+
return next;
|
|
19
|
+
}
|
|
20
|
+
make(overrides = {}) {
|
|
21
|
+
const models = Array.from({ length: this.amount }, (_, index) => {
|
|
22
|
+
const attributes = this.attributesFor(index + 1, overrides);
|
|
23
|
+
return new this.model(attributes);
|
|
24
|
+
});
|
|
25
|
+
return this.amount === 1 ? models[0] : models;
|
|
26
|
+
}
|
|
27
|
+
async create(overrides = {}) {
|
|
28
|
+
const records = Array.from({ length: this.amount }, (_, index) => this.attributesFor(index + 1, overrides));
|
|
29
|
+
const models = [];
|
|
30
|
+
for (const attributes of records) {
|
|
31
|
+
models.push(await this.model.create(attributes));
|
|
32
|
+
}
|
|
33
|
+
return this.amount === 1 ? models[0] : models;
|
|
34
|
+
}
|
|
35
|
+
raw(overrides = {}) {
|
|
36
|
+
const records = Array.from({ length: this.amount }, (_, index) => this.attributesFor(index + 1, overrides));
|
|
37
|
+
return this.amount === 1 ? records[0] : records;
|
|
38
|
+
}
|
|
39
|
+
attributesFor(sequence, overrides) {
|
|
40
|
+
let attributes = { ...this.definition(sequence) };
|
|
41
|
+
for (const state of this.states) {
|
|
42
|
+
const next = typeof state === "function" ? state(attributes, sequence) : state;
|
|
43
|
+
attributes = { ...attributes, ...next };
|
|
44
|
+
}
|
|
45
|
+
return { ...attributes, ...overrides };
|
|
46
|
+
}
|
|
47
|
+
clone() {
|
|
48
|
+
const next = new Factory(this.model, this.definition);
|
|
49
|
+
next.amount = this.amount;
|
|
50
|
+
next.states = [...this.states];
|
|
51
|
+
return next;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
export function factory(model, definition) {
|
|
55
|
+
return new Factory(model, definition);
|
|
56
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Connection } from "../connection/Connection.js";
|
|
2
|
+
export declare abstract class Seeder {
|
|
3
|
+
protected connection: Connection;
|
|
4
|
+
constructor(connection?: Connection);
|
|
5
|
+
abstract run(): Promise<void> | void;
|
|
6
|
+
protected call(seeders: (Seeder | (new (connection?: Connection) => Seeder))[]): Promise<void>;
|
|
7
|
+
}
|
|
8
|
+
export declare class SeederRunner {
|
|
9
|
+
private connection;
|
|
10
|
+
constructor(connection?: Connection);
|
|
11
|
+
run(seeders: (Seeder | (new (connection?: Connection) => Seeder))[]): Promise<void>;
|
|
12
|
+
runPaths(paths: string | string[]): Promise<void>;
|
|
13
|
+
runFile(file: string): Promise<void>;
|
|
14
|
+
runTarget(target: string, searchPaths?: string | string[]): Promise<void>;
|
|
15
|
+
private getSeederFiles;
|
|
16
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { existsSync } from "fs";
|
|
2
|
+
import { readdir, stat } from "fs/promises";
|
|
3
|
+
import { basename, extname, resolve } from "path";
|
|
4
|
+
import { pathToFileURL } from "url";
|
|
5
|
+
import { Schema } from "../schema/Schema.js";
|
|
6
|
+
import { normalizePathList, toPosixPath } from "../utils.js";
|
|
7
|
+
export class Seeder {
|
|
8
|
+
connection;
|
|
9
|
+
constructor(connection = Schema.getConnection()) {
|
|
10
|
+
this.connection = connection;
|
|
11
|
+
}
|
|
12
|
+
async call(seeders) {
|
|
13
|
+
for (const seeder of seeders) {
|
|
14
|
+
const instance = typeof seeder === "function" ? new seeder(this.connection) : seeder;
|
|
15
|
+
await instance.run();
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
export class SeederRunner {
|
|
20
|
+
connection;
|
|
21
|
+
constructor(connection = Schema.getConnection()) {
|
|
22
|
+
this.connection = connection;
|
|
23
|
+
}
|
|
24
|
+
async run(seeders) {
|
|
25
|
+
for (const seeder of seeders) {
|
|
26
|
+
const instance = typeof seeder === "function" ? new seeder(this.connection) : seeder;
|
|
27
|
+
await instance.run();
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
async runPaths(paths) {
|
|
31
|
+
const files = await this.getSeederFiles(paths);
|
|
32
|
+
for (const file of files) {
|
|
33
|
+
await this.runFile(file);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
async runFile(file) {
|
|
37
|
+
const resolved = resolve(file);
|
|
38
|
+
const module = await import(pathToFileURL(resolved).href);
|
|
39
|
+
const SeederClass = module.default || Object.values(module)[0];
|
|
40
|
+
if (!SeederClass) {
|
|
41
|
+
throw new Error(`Seeder ${file} does not export a class.`);
|
|
42
|
+
}
|
|
43
|
+
await this.run([SeederClass]);
|
|
44
|
+
}
|
|
45
|
+
async runTarget(target, searchPaths = "./database/seeders") {
|
|
46
|
+
const resolved = resolve(target);
|
|
47
|
+
if (existsSync(resolved) && (await stat(resolved)).isFile()) {
|
|
48
|
+
await this.runFile(resolved);
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
const files = await this.getSeederFiles(searchPaths);
|
|
52
|
+
const normalizedTarget = target.replace(/\.(ts|js|mts|mjs|cts|cjs)$/i, "");
|
|
53
|
+
const match = files.find((file) => {
|
|
54
|
+
const name = basename(file, extname(file));
|
|
55
|
+
return name === normalizedTarget || file.endsWith(target) || file.endsWith(`${target}.ts`) || file.endsWith(`${target}.js`);
|
|
56
|
+
});
|
|
57
|
+
if (!match) {
|
|
58
|
+
throw new Error(`Seeder "${target}" could not be found in ${normalizePathList(searchPaths).join(", ")}.`);
|
|
59
|
+
}
|
|
60
|
+
await this.runFile(match);
|
|
61
|
+
}
|
|
62
|
+
async getSeederFiles(paths) {
|
|
63
|
+
const files = [];
|
|
64
|
+
for (const path of normalizePathList(paths)) {
|
|
65
|
+
const root = resolve(path);
|
|
66
|
+
if (!existsSync(root))
|
|
67
|
+
continue;
|
|
68
|
+
for (const entry of await readdir(root, { withFileTypes: true })) {
|
|
69
|
+
if (!entry.isFile())
|
|
70
|
+
continue;
|
|
71
|
+
if (entry.name.endsWith(".d.ts") || entry.name.endsWith(".test.ts") || entry.name.endsWith(".spec.ts"))
|
|
72
|
+
continue;
|
|
73
|
+
if (![".ts", ".js", ".mts", ".mjs", ".cts", ".cjs"].includes(extname(entry.name)))
|
|
74
|
+
continue;
|
|
75
|
+
files.push(toPosixPath(resolve(root, entry.name)));
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return files.sort((a, b) => basename(a).localeCompare(basename(b)) || a.localeCompare(b));
|
|
79
|
+
}
|
|
80
|
+
}
|
package/package.json
CHANGED