@veap/database 0.0.0-stage → 0.1.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.
Files changed (69) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +177 -2
  3. package/dist/casts.d.ts +9 -0
  4. package/dist/casts.js +78 -0
  5. package/dist/composition.d.ts +15 -0
  6. package/dist/composition.js +26 -0
  7. package/dist/connection.d.ts +49 -0
  8. package/dist/connection.js +193 -0
  9. package/dist/errors.d.ts +7 -0
  10. package/dist/errors.js +17 -0
  11. package/dist/events.d.ts +5 -0
  12. package/dist/events.js +7 -0
  13. package/dist/factory.d.ts +68 -0
  14. package/dist/factory.js +161 -0
  15. package/dist/index.d.ts +19 -0
  16. package/dist/index.js +19 -0
  17. package/dist/logger.d.ts +11 -0
  18. package/dist/logger.js +21 -0
  19. package/dist/migration-provider.d.ts +7 -0
  20. package/dist/migration-provider.js +36 -0
  21. package/dist/migrations/generator.d.ts +4 -0
  22. package/dist/migrations/generator.js +58 -0
  23. package/dist/migrations/index.d.ts +3 -0
  24. package/dist/migrations/index.js +3 -0
  25. package/dist/migrations/runner.d.ts +12 -0
  26. package/dist/migrations/runner.js +179 -0
  27. package/dist/migrations/schema-builder.d.ts +84 -0
  28. package/dist/migrations/schema-builder.js +409 -0
  29. package/dist/model.d.ts +379 -0
  30. package/dist/model.js +913 -0
  31. package/dist/provider.d.ts +13 -0
  32. package/dist/provider.js +112 -0
  33. package/dist/query-builder.d.ts +197 -0
  34. package/dist/query-builder.js +749 -0
  35. package/dist/relations/belongs-to-many.d.ts +15 -0
  36. package/dist/relations/belongs-to-many.js +80 -0
  37. package/dist/relations/belongs-to.d.ts +8 -0
  38. package/dist/relations/belongs-to.js +37 -0
  39. package/dist/relations/eager-loader.d.ts +5 -0
  40. package/dist/relations/eager-loader.js +68 -0
  41. package/dist/relations/has-many.d.ts +9 -0
  42. package/dist/relations/has-many.js +48 -0
  43. package/dist/relations/has-one.d.ts +8 -0
  44. package/dist/relations/has-one.js +37 -0
  45. package/dist/relations/index.d.ts +11 -0
  46. package/dist/relations/index.js +11 -0
  47. package/dist/relations/morph-many.d.ts +14 -0
  48. package/dist/relations/morph-many.js +65 -0
  49. package/dist/relations/morph-map.d.ts +32 -0
  50. package/dist/relations/morph-map.js +73 -0
  51. package/dist/relations/morph-one.d.ts +14 -0
  52. package/dist/relations/morph-one.js +65 -0
  53. package/dist/relations/morph-to-many.d.ts +44 -0
  54. package/dist/relations/morph-to-many.js +215 -0
  55. package/dist/relations/morph-to.d.ts +19 -0
  56. package/dist/relations/morph-to.js +90 -0
  57. package/dist/relations/relation.d.ts +22 -0
  58. package/dist/relations/relation.js +13 -0
  59. package/dist/scopes.d.ts +16 -0
  60. package/dist/scopes.js +1 -0
  61. package/dist/seeder.d.ts +25 -0
  62. package/dist/seeder.js +49 -0
  63. package/dist/tokens.d.ts +10 -0
  64. package/dist/tokens.js +8 -0
  65. package/dist/types.d.ts +31 -0
  66. package/dist/types.js +1 -0
  67. package/dist/utils.d.ts +9 -0
  68. package/dist/utils.js +20 -0
  69. package/package.json +58 -4
@@ -0,0 +1,161 @@
1
+ import { DatabaseError } from "./errors.js";
2
+ export class Factory {
3
+ static get registry() {
4
+ const g = globalThis;
5
+ if (!g.__VEAP_FACTORY_REGISTRY__) {
6
+ g.__VEAP_FACTORY_REGISTRY__ = new Map();
7
+ }
8
+ return g.__VEAP_FACTORY_REGISTRY__;
9
+ }
10
+ /**
11
+ * Registers a factory class/instance for a model.
12
+ */
13
+ static register(modelClass, factoryOrFactoryFn) {
14
+ this.registry.set(modelClass, factoryOrFactoryFn);
15
+ }
16
+ /**
17
+ * Gets the registered factory for a model if one exists.
18
+ */
19
+ static getForModel(modelClass) {
20
+ return this.registry.get(modelClass);
21
+ }
22
+ modelClass;
23
+ countNumber = 1;
24
+ states = [];
25
+ sequenceItems = [];
26
+ constructor(modelClass) {
27
+ if (modelClass) {
28
+ this.modelClass = modelClass;
29
+ }
30
+ }
31
+ /**
32
+ * Sets the number of models that should be generated.
33
+ */
34
+ count(amount) {
35
+ this.countNumber = Math.max(1, amount);
36
+ return this;
37
+ }
38
+ /**
39
+ * Applies an attribute state transformation to the factory.
40
+ */
41
+ state(override) {
42
+ this.states.push(override);
43
+ return this;
44
+ }
45
+ /**
46
+ * Applies sequential states rotating through the given items.
47
+ */
48
+ sequence(...items) {
49
+ this.sequenceItems.push(...items);
50
+ return this;
51
+ }
52
+ /**
53
+ * Generates the raw attributes dictionary for a single model instance.
54
+ */
55
+ async raw(override = {}, index = 0) {
56
+ let attributes = await this.definition();
57
+ // Apply sequence if provided
58
+ if (this.sequenceItems.length > 0) {
59
+ const seqState = this.sequenceItems[index % this.sequenceItems.length];
60
+ attributes = { ...attributes, ...seqState };
61
+ }
62
+ // Apply states
63
+ for (const stateItem of this.states) {
64
+ if (typeof stateItem === "function") {
65
+ attributes = { ...attributes, ...stateItem(attributes) };
66
+ }
67
+ else {
68
+ attributes = { ...attributes, ...stateItem };
69
+ }
70
+ }
71
+ // Apply direct overrides
72
+ attributes = { ...attributes, ...override };
73
+ return attributes;
74
+ }
75
+ /**
76
+ * Creates a single model instance in memory without saving to database.
77
+ */
78
+ async makeOne(override = {}, index = 0) {
79
+ if (!this.modelClass) {
80
+ throw DatabaseError.Internal("[veap:Factory] Model class is not defined for this factory.");
81
+ }
82
+ const attributes = await this.raw(override, index);
83
+ return new this.modelClass(attributes, true);
84
+ }
85
+ /**
86
+ * Creates model instance(s) in memory without saving to database.
87
+ */
88
+ async make(override = {}) {
89
+ if (this.countNumber === 1) {
90
+ return await this.makeOne(override, 0);
91
+ }
92
+ const instances = [];
93
+ for (let i = 0; i < this.countNumber; i++) {
94
+ instances.push(await this.makeOne(override, i));
95
+ }
96
+ return instances;
97
+ }
98
+ /**
99
+ * Creates and persists a single model instance to the database.
100
+ */
101
+ async createOne(override = {}, index = 0) {
102
+ const instance = await this.makeOne(override, index);
103
+ await instance.save();
104
+ return instance;
105
+ }
106
+ /**
107
+ * Creates and persists model instance(s) to the database.
108
+ */
109
+ async create(override = {}) {
110
+ if (this.countNumber === 1) {
111
+ return await this.createOne(override, 0);
112
+ }
113
+ const instances = [];
114
+ for (let i = 0; i < this.countNumber; i++) {
115
+ instances.push(await this.createOne(override, i));
116
+ }
117
+ return instances;
118
+ }
119
+ }
120
+ /**
121
+ * Generic factory implementation used by defineFactory helper.
122
+ */
123
+ class GenericFactory extends Factory {
124
+ definitionFn;
125
+ constructor(modelClass, definitionFn) {
126
+ super(modelClass);
127
+ this.definitionFn = definitionFn;
128
+ }
129
+ async definition() {
130
+ return await this.definitionFn();
131
+ }
132
+ }
133
+ /**
134
+ * Convenient helper to define a Model Factory in a single concise call.
135
+ */
136
+ export function defineFactory(modelClass, definitionFn) {
137
+ const FactoryClass = class extends GenericFactory {
138
+ constructor() {
139
+ super(modelClass, definitionFn);
140
+ }
141
+ };
142
+ const factoryCallable = function (count) {
143
+ const instance = new FactoryClass();
144
+ if (count !== undefined) {
145
+ instance.count(count);
146
+ }
147
+ return instance;
148
+ };
149
+ // Attach static factory shortcuts
150
+ factoryCallable.count = (amount) => factoryCallable().count(amount);
151
+ factoryCallable.state = (override) => factoryCallable().state(override);
152
+ factoryCallable.sequence = (...items) => factoryCallable().sequence(...items);
153
+ factoryCallable.make = (override) => factoryCallable().make(override);
154
+ factoryCallable.makeOne = (override) => factoryCallable().makeOne(override);
155
+ factoryCallable.create = (override) => factoryCallable().create(override);
156
+ factoryCallable.createOne = (override) => factoryCallable().createOne(override);
157
+ // Allow `new UserFactory()`
158
+ Object.setPrototypeOf(factoryCallable, FactoryClass);
159
+ factoryCallable.prototype = FactoryClass.prototype;
160
+ return factoryCallable;
161
+ }
@@ -0,0 +1,19 @@
1
+ export { default as knex, type Knex } from "knex";
2
+ export * from "./casts.js";
3
+ export * from "./composition.js";
4
+ export * from "./connection.js";
5
+ export * from "./errors.js";
6
+ export * from "./events.js";
7
+ export * from "./factory.js";
8
+ export * from "./logger.js";
9
+ export * from "./migration-provider.js";
10
+ export * from "./migrations/index.js";
11
+ export * from "./model.js";
12
+ export * from "./provider.js";
13
+ export * from "./query-builder.js";
14
+ export * from "./relations/index.js";
15
+ export * from "./scopes.js";
16
+ export * from "./seeder.js";
17
+ export * from "./tokens.js";
18
+ export * from "./types.js";
19
+ export * from "./utils.js";
package/dist/index.js ADDED
@@ -0,0 +1,19 @@
1
+ export { default as knex } from "knex";
2
+ export * from "./casts.js";
3
+ export * from "./composition.js";
4
+ export * from "./connection.js";
5
+ export * from "./errors.js";
6
+ export * from "./events.js";
7
+ export * from "./factory.js";
8
+ export * from "./logger.js";
9
+ export * from "./migration-provider.js";
10
+ export * from "./migrations/index.js";
11
+ export * from "./model.js";
12
+ export * from "./provider.js";
13
+ export * from "./query-builder.js";
14
+ export * from "./relations/index.js";
15
+ export * from "./scopes.js";
16
+ export * from "./seeder.js";
17
+ export * from "./tokens.js";
18
+ export * from "./types.js";
19
+ export * from "./utils.js";
@@ -0,0 +1,11 @@
1
+ export interface DatabaseLogger {
2
+ debug(channel: string, message: string, ...args: any[]): void;
3
+ info(channel: string, message: string, ...args: any[]): void;
4
+ warn(channel: string, message: string, ...args: any[]): void;
5
+ error(channel: string, message: string, ...args: any[]): void;
6
+ }
7
+ export declare function setDatabaseLogger(logger: DatabaseLogger): void;
8
+ export declare function debug(channel: string, message: string, ...args: any[]): void;
9
+ export declare function info(channel: string, message: string, ...args: any[]): void;
10
+ export declare function warn(channel: string, message: string, ...args: any[]): void;
11
+ export declare function error(channel: string, message: string, ...args: any[]): void;
package/dist/logger.js ADDED
@@ -0,0 +1,21 @@
1
+ let activeLogger = {
2
+ debug: (_channel, _message, ..._args) => { },
3
+ info: (channel, message, ..._args) => console.info(`[${channel}] ${message}`),
4
+ warn: (channel, message, ..._args) => console.warn(`[${channel}] ${message}`),
5
+ error: (channel, message, ..._args) => console.error(`[${channel}] ${message}`),
6
+ };
7
+ export function setDatabaseLogger(logger) {
8
+ activeLogger = logger;
9
+ }
10
+ export function debug(channel, message, ...args) {
11
+ activeLogger.debug(channel, message, ...args);
12
+ }
13
+ export function info(channel, message, ...args) {
14
+ activeLogger.info(channel, message, ...args);
15
+ }
16
+ export function warn(channel, message, ...args) {
17
+ activeLogger.warn(channel, message, ...args);
18
+ }
19
+ export function error(channel, message, ...args) {
20
+ activeLogger.error(channel, message, ...args);
21
+ }
@@ -0,0 +1,7 @@
1
+ import { ServiceProvider } from "@veap/kernel";
2
+ export declare class MigrationServiceProvider extends ServiceProvider {
3
+ private migrations?;
4
+ constructor(container: any, migrations?: any[]);
5
+ register(): void;
6
+ boot(): Promise<void>;
7
+ }
@@ -0,0 +1,36 @@
1
+ import { ServiceProvider } from "@veap/kernel";
2
+ import { runMigrations } from "./migrations/runner.js";
3
+ import { APP_MIGRATIONS } from "./tokens.js";
4
+ export class MigrationServiceProvider extends ServiceProvider {
5
+ migrations;
6
+ constructor(container, migrations) {
7
+ super(container);
8
+ this.migrations = migrations;
9
+ }
10
+ register() {
11
+ if (this.migrations?.length) {
12
+ this.container.register({
13
+ token: APP_MIGRATIONS,
14
+ useValue: this.migrations,
15
+ });
16
+ this.container.register({
17
+ token: "AppMigrations",
18
+ useValue: this.migrations,
19
+ });
20
+ }
21
+ }
22
+ async boot() {
23
+ let appMigrations = this.migrations;
24
+ if (!appMigrations?.length) {
25
+ if (this.container.has(APP_MIGRATIONS)) {
26
+ appMigrations = await this.container.resolve(APP_MIGRATIONS);
27
+ }
28
+ else if (this.container.has("AppMigrations")) {
29
+ appMigrations = await this.container.resolve("AppMigrations");
30
+ }
31
+ }
32
+ if (appMigrations?.length) {
33
+ await runMigrations("app", appMigrations);
34
+ }
35
+ }
36
+ }
@@ -0,0 +1,4 @@
1
+ export declare function generateMigration(name: string, targetDir?: string): Promise<{
2
+ fileName: string;
3
+ filePath: string;
4
+ }>;
@@ -0,0 +1,58 @@
1
+ import fs from "node:fs/promises";
2
+ import path from "node:path";
3
+ const stub = `import type { Schema } from "@veap/database";
4
+
5
+ export default {
6
+ name: "{{name}}",
7
+ async up(_db: any, schema: Schema) {
8
+ await schema.createTable("{{tableName}}", (table) => {
9
+ table.increments("id");
10
+
11
+ table.timestamps();
12
+ });
13
+ },
14
+ async down(_db: any, schema: Schema) {
15
+ await schema.dropTableIfExists("{{tableName}}");
16
+ },
17
+ };
18
+ `;
19
+ async function updateIndexFile(migrationsDir) {
20
+ const indexFile = path.join(migrationsDir, "index.ts");
21
+ const files = await fs.readdir(migrationsDir);
22
+ const migrationFiles = files
23
+ .filter((f) => f.endsWith(".ts") && f !== "index.ts")
24
+ .sort();
25
+ const imports = [];
26
+ const exports = [];
27
+ for (const file of migrationFiles) {
28
+ const name = file.replace(".ts", "");
29
+ const varName = `m${name.replace(/[^a-zA-Z0-9]/g, "_")}`;
30
+ imports.push(`import { default as ${varName} } from "./${name}";`);
31
+ exports.push(varName);
32
+ }
33
+ const content = `// This file is auto-generated by Veap CLI. Do not edit manually.
34
+ ${imports.join("\n")}
35
+
36
+ export const appMigrations = [
37
+ ${exports.join(",\n ")}
38
+ ];
39
+ `;
40
+ await fs.writeFile(indexFile, content, "utf-8");
41
+ }
42
+ export async function generateMigration(name, targetDir) {
43
+ const timestamp = new Date().toISOString().replace(/[-:T]/g, "").slice(0, 14);
44
+ const fileName = `${timestamp}_${name}`;
45
+ let tableName = name;
46
+ if (name.startsWith("create_") && name.endsWith("_table")) {
47
+ tableName = name.replace("create_", "").replace("_table", "");
48
+ }
49
+ const content = stub
50
+ .replace(/{{name}}/g, fileName)
51
+ .replace(/{{tableName}}/g, tableName);
52
+ const migrationsDir = targetDir || path.join(process.cwd(), "migrations");
53
+ await fs.mkdir(migrationsDir, { recursive: true });
54
+ const filePath = path.join(migrationsDir, `${fileName}.ts`);
55
+ await fs.writeFile(filePath, content, "utf-8");
56
+ await updateIndexFile(migrationsDir);
57
+ return { fileName, filePath };
58
+ }
@@ -0,0 +1,3 @@
1
+ export * from "./generator.js";
2
+ export * from "./runner.js";
3
+ export * from "./schema-builder.js";
@@ -0,0 +1,3 @@
1
+ export * from "./generator.js";
2
+ export * from "./runner.js";
3
+ export * from "./schema-builder.js";
@@ -0,0 +1,12 @@
1
+ import { Schema } from "./schema-builder.js";
2
+ export interface Migration {
3
+ name: string;
4
+ up: (db: any, schema: Schema) => Promise<void>;
5
+ down?: (db: any, schema: Schema) => Promise<void>;
6
+ }
7
+ export declare function runMigrations(scope: string, migrations: Migration[]): Promise<void>;
8
+ /**
9
+ * Modern static migration rollback runner.
10
+ * Reverts migrations in reverse order.
11
+ */
12
+ export declare function rollbackMigrations(scope: string, migrations: Migration[]): Promise<void>;
@@ -0,0 +1,179 @@
1
+ import crypto from "node:crypto";
2
+ import { getKnex } from "../connection.js";
3
+ import { debug, warn } from "../logger.js";
4
+ import { Schema } from "./schema-builder.js";
5
+ async function ensureMigrationsTable(knex = getKnex()) {
6
+ try {
7
+ const hasTable = await knex.schema.hasTable("migrations");
8
+ if (!hasTable) {
9
+ await knex.schema.createTable("migrations", (table) => {
10
+ table.text("id").primary();
11
+ table.text("name").notNullable();
12
+ table.integer("batch").notNullable();
13
+ table.timestamp("executed_at").defaultTo(knex.fn.now()).notNullable();
14
+ table.text("scope").notNullable().defaultTo("global");
15
+ });
16
+ }
17
+ else {
18
+ const hasScope = await knex.schema.hasColumn("migrations", "scope");
19
+ if (!hasScope) {
20
+ await knex.schema.alterTable("migrations", (table) => {
21
+ table.text("scope").notNullable().defaultTo("global");
22
+ });
23
+ }
24
+ }
25
+ }
26
+ catch (error) {
27
+ warn("veap:migration", "Failed to ensure migrations table:", error);
28
+ }
29
+ }
30
+ async function acquireAdvisoryLockIfPostgres(tx, knex) {
31
+ const clientName = knex?.client?.config?.client || "";
32
+ if (typeof clientName === "string" &&
33
+ (clientName.includes("pg") || clientName.includes("postgres"))) {
34
+ const lockId = 123456;
35
+ try {
36
+ await tx.raw("SELECT pg_advisory_xact_lock(?)", [lockId]);
37
+ }
38
+ catch (_e) {
39
+ debug("veap:migration", "Could not acquire advisory lock, continuing...");
40
+ }
41
+ }
42
+ }
43
+ /**
44
+ * Creates a compatibility DB adapter for migrations that provides `.execute(query)`
45
+ * wrapping `trx.raw(query)`, while also being directly callable as a Knex query builder
46
+ * on the active migration transaction `trx(tableName)`.
47
+ */
48
+ function createMigrationDbAdapter(trx) {
49
+ const adapter = (tableName) => trx(tableName);
50
+ adapter.raw = (query, ...bindings) => trx.raw(query, ...bindings);
51
+ adapter.execute = (query) => {
52
+ const sqlString = typeof query === "string"
53
+ ? query
54
+ : query?.query || query?.text || String(query);
55
+ return trx.raw(sqlString);
56
+ };
57
+ return new Proxy(adapter, {
58
+ get(target, prop, receiver) {
59
+ if (prop in target) {
60
+ return Reflect.get(target, prop, receiver);
61
+ }
62
+ return Reflect.get(trx, prop);
63
+ },
64
+ apply(target, thisArg, argArray) {
65
+ return trx(...argArray);
66
+ },
67
+ });
68
+ }
69
+ export async function runMigrations(scope, migrations) {
70
+ if (migrations.length === 0)
71
+ return;
72
+ let knex;
73
+ try {
74
+ knex = getKnex();
75
+ }
76
+ catch {
77
+ return;
78
+ }
79
+ if (!knex)
80
+ return;
81
+ await ensureMigrationsTable(knex);
82
+ await knex.transaction(async (tx) => {
83
+ // Acquire advisory lock only if running on PostgreSQL
84
+ await acquireAdvisoryLockIfPostgres(tx, knex);
85
+ debug("veap:migration", `Running migrations for scope: ${scope}`);
86
+ // 1. Get executed migrations for this scope
87
+ const executed = await tx("migrations")
88
+ .select("name")
89
+ .where("scope", scope);
90
+ const executedNames = executed.map((m) => m.name);
91
+ // 2. Find pending migrations
92
+ const pending = migrations.filter((m) => !executedNames.includes(m.name));
93
+ if (pending.length === 0) {
94
+ debug("veap:migration", `No new migrations for ${scope}.`);
95
+ return;
96
+ }
97
+ // 3. Get next batch number
98
+ const batchResult = await tx("migrations").max("batch as maxBatch").first();
99
+ const batch = (Number(batchResult?.maxBatch) || 0) + 1;
100
+ const dbAdapter = createMigrationDbAdapter(tx);
101
+ const schema = new Schema(tx);
102
+ // 4. Execute pending
103
+ for (const migration of pending) {
104
+ debug("veap:migration", `[${scope}] Running migration: ${migration.name}...`);
105
+ try {
106
+ await migration.up(dbAdapter, schema);
107
+ await tx("migrations").insert({
108
+ id: crypto.randomUUID(),
109
+ name: migration.name,
110
+ scope: scope,
111
+ batch: batch,
112
+ executed_at: new Date(),
113
+ });
114
+ debug("veap:migration", `[${scope}] Successfully ran ${migration.name}.`);
115
+ }
116
+ catch (error) {
117
+ warn("veap:migration", `[${scope}] Failed to run ${migration.name}:`, error);
118
+ throw error; // Rollback the whole batch on error
119
+ }
120
+ }
121
+ });
122
+ }
123
+ /**
124
+ * Modern static migration rollback runner.
125
+ * Reverts migrations in reverse order.
126
+ */
127
+ export async function rollbackMigrations(scope, migrations) {
128
+ if (migrations.length === 0)
129
+ return;
130
+ let knex;
131
+ try {
132
+ knex = getKnex();
133
+ }
134
+ catch {
135
+ return;
136
+ }
137
+ if (!knex)
138
+ return;
139
+ await ensureMigrationsTable(knex);
140
+ await knex.transaction(async (tx) => {
141
+ // Acquire advisory lock only if running on PostgreSQL
142
+ await acquireAdvisoryLockIfPostgres(tx, knex);
143
+ // 1. Get executed migrations for this scope ordered by batch desc
144
+ const executed = await tx("migrations")
145
+ .select("name", "batch")
146
+ .where("scope", scope)
147
+ .orderBy("batch", "desc");
148
+ if (executed.length === 0) {
149
+ debug("veap:migration", `No migrations to rollback for ${scope}.`);
150
+ return;
151
+ }
152
+ // Rollback the latest batch
153
+ const latestBatch = executed[0].batch;
154
+ const toRollbackNames = executed
155
+ .filter((m) => m.batch === latestBatch)
156
+ .map((m) => m.name);
157
+ const dbAdapter = createMigrationDbAdapter(tx);
158
+ const schema = new Schema(tx);
159
+ // Rollback in reverse order
160
+ for (const name of toRollbackNames) {
161
+ const migration = migrations.find((m) => m.name === name);
162
+ if (migration && migration.down) {
163
+ debug("veap:migration", `[${scope}] Rolling back migration: ${name}...`);
164
+ try {
165
+ await migration.down(dbAdapter, schema);
166
+ await tx("migrations")
167
+ .where("name", name)
168
+ .where("scope", scope)
169
+ .delete();
170
+ debug("veap:migration", `[${scope}] Rolled back ${name}.`);
171
+ }
172
+ catch (error) {
173
+ warn("veap:migration", `[${scope}] Failed to rollback ${name}:`, error);
174
+ throw error;
175
+ }
176
+ }
177
+ }
178
+ });
179
+ }
@@ -0,0 +1,84 @@
1
+ /**
2
+ * Lightweight SQL helper for migrations, compatible with sql`...` template strings.
3
+ */
4
+ export declare function sql(strings: TemplateStringsArray | string, ...values: any[]): any;
5
+ export declare namespace sql {
6
+ var raw: (str: string) => string;
7
+ }
8
+ export type DatabaseDialect = "postgres" | "sqlite" | "mysql";
9
+ export declare class ColumnBuilder {
10
+ type: string;
11
+ name: string;
12
+ private _notNull;
13
+ private _primaryKey;
14
+ private _unique;
15
+ private _default;
16
+ private _defaultNow;
17
+ private _references;
18
+ private _onDelete;
19
+ private _onUpdate;
20
+ constructor(type: string, name: string);
21
+ notNull(): this;
22
+ primaryKey(): this;
23
+ unique(): this;
24
+ default(value: any): this;
25
+ defaultNow(): this;
26
+ defaultFn(fn: any): this;
27
+ references(table: string, column?: string): this;
28
+ onDelete(action: "CASCADE" | "SET NULL" | "RESTRICT" | "NO ACTION"): this;
29
+ onUpdate(action: "CASCADE" | "SET NULL" | "RESTRICT" | "NO ACTION"): this;
30
+ toSql(dialect?: DatabaseDialect): string;
31
+ }
32
+ export declare class Blueprint {
33
+ private tableName;
34
+ private columns;
35
+ private _primaryKeys;
36
+ private _uniques;
37
+ constructor(tableName: string);
38
+ id(name?: string): ColumnBuilder;
39
+ uuid(name?: string): ColumnBuilder;
40
+ increments(name: string): ColumnBuilder;
41
+ text(name: string): ColumnBuilder;
42
+ varchar(name: string, length?: number): ColumnBuilder;
43
+ string(name: string, length?: number): ColumnBuilder;
44
+ integer(name: string): ColumnBuilder;
45
+ smallint(name: string): ColumnBuilder;
46
+ bigint(name: string): ColumnBuilder;
47
+ boolean(name: string): ColumnBuilder;
48
+ timestamp(name: string, precision?: number): ColumnBuilder;
49
+ timestamptz(name: string, precision?: number): ColumnBuilder;
50
+ timestamps(): void;
51
+ softDeletes(name?: string): ColumnBuilder;
52
+ date(name: string): ColumnBuilder;
53
+ json(name: string): ColumnBuilder;
54
+ jsonb(name: string): ColumnBuilder;
55
+ bytea(name: string): ColumnBuilder;
56
+ blob(name: string): ColumnBuilder;
57
+ decimal(name: string, precision?: number, scale?: number): ColumnBuilder;
58
+ float(name: string): ColumnBuilder;
59
+ double(name: string): ColumnBuilder;
60
+ custom(type: string, name: string): ColumnBuilder;
61
+ unique(columns: string[]): this;
62
+ primary(columns: string[]): this;
63
+ private addColumn;
64
+ toSql(dialect?: DatabaseDialect): string;
65
+ toAlterSql(dialect?: DatabaseDialect): string[];
66
+ }
67
+ export declare class Schema {
68
+ private db?;
69
+ constructor(db?: any | undefined);
70
+ getDialect(): DatabaseDialect;
71
+ get knex(): any;
72
+ private getKnexInstance;
73
+ hasTable(name: string): Promise<boolean>;
74
+ hasColumn(tableName: string, columnName: string): Promise<boolean>;
75
+ dropColumn(tableName: string, columnName: string): Promise<void>;
76
+ private runQuery;
77
+ createTable(name: string, callback: (table: Blueprint) => void): Promise<void>;
78
+ table(name: string, callback: (table: Blueprint) => void): Promise<void>;
79
+ dropTable(name: string): Promise<void>;
80
+ dropTableIfExists(name: string): Promise<void>;
81
+ createEnum(name: string, values: string[]): Promise<void>;
82
+ dropEnum(name: string): Promise<void>;
83
+ raw(query: string): Promise<void>;
84
+ }