forj 0.0.4 → 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "forj",
3
3
  "description": "SQLite ORM and Query Builder whitout dependencies",
4
- "version": "0.0.4",
4
+ "version": "0.0.5",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
7
7
  "files": ["src"],
@@ -10,7 +10,8 @@
10
10
  "./d1": "./src/d1/index.ts",
11
11
  "./d1/types": "./src/d1/types.ts",
12
12
  "./dynamodb": "./src/dynamodb/index.ts",
13
- "./dynamodb/types": "./src/dynamodb/types.ts"
13
+ "./dynamodb/types": "./src/dynamodb/types.ts",
14
+ "./migrate": "./src/migrations/index.ts"
14
15
  },
15
16
  "-exports": {
16
17
  ".": {
@@ -61,6 +62,8 @@
61
62
  "resources",
62
63
  "support",
63
64
  "sqlite",
65
+ "migration",
66
+ "schema",
64
67
  "orm",
65
68
  "query",
66
69
  "builder",
@@ -73,9 +76,15 @@
73
76
  "postgres",
74
77
  "postgresql",
75
78
  "typescript",
79
+ "serverless",
80
+ "dynamo",
81
+ "dynamodb",
76
82
  "aws",
77
83
  "lambda",
78
84
  "llrt",
85
+ "d1",
86
+ "cloudflare",
87
+ "workers",
79
88
  "deno",
80
89
  "bun",
81
90
  "nodejs"
package/src/index.ts CHANGED
@@ -1 +1,2 @@
1
+ export { Migrator, Migration, Schema, Blueprint } from './migrations'
1
2
  export { default as QueryBuilder } from './query-builder'
@@ -0,0 +1,170 @@
1
+ import Column from './column'
2
+ import ForeignKey from './foreign-key'
3
+ import type {
4
+ ColumnDefinition, IndexDefinition, ForeignKeyDefinition,
5
+ } from './types'
6
+
7
+ export class Blueprint {
8
+ #table: string
9
+ #columns: ColumnDefinition[] = []
10
+ #indexes: IndexDefinition[] = []
11
+ #foreignKeys: ForeignKeyDefinition[] = []
12
+ #dropColumns: string[] = []
13
+ #renameColumns: Map<string, string> = new Map()
14
+
15
+ constructor(table: string) {
16
+ this.#table = table
17
+ }
18
+
19
+ #column(definition: ColumnDefinition) {
20
+ const column: ColumnDefinition = definition
21
+ this.#columns.push(column)
22
+ return new Column(column)
23
+ }
24
+
25
+ id(name: string = 'id') { // Auto-increment ID (bigint unsigned)
26
+ return this.#column({ name, type: 'BIGINT', unsigned: true, autoIncrement: true, primary: true, nullable: false })
27
+ }
28
+
29
+ string(name: string, length: number = 255) {
30
+ return this.#column({ name, type: 'VARCHAR', length, nullable: false })
31
+ }
32
+
33
+ text(name: string) {
34
+ return this.#column({ name, type: 'TEXT', nullable: false })
35
+ }
36
+
37
+ integer(name: string) {
38
+ return this.#column({ name, type: 'INTEGER', nullable: false })
39
+ }
40
+
41
+ bigInteger(name: string) {
42
+ return this.#column({ name, type: 'BIGINT', nullable: false })
43
+ }
44
+
45
+ tinyInteger(name: string) {
46
+ return this.#column({ name, type: 'TINYINT', nullable: false })
47
+ }
48
+
49
+ boolean(name: string) {
50
+ return this.#column({ name, type: 'BOOLEAN', nullable: false })
51
+ }
52
+
53
+ decimal(name: string, precision: number = 8, scale: number = 2) {
54
+ return this.#column({ name, type: `DECIMAL(${precision},${scale})`, nullable: false })
55
+ }
56
+
57
+ float(name: string) {
58
+ return this.#column({ name, type: 'FLOAT', nullable: false })
59
+ }
60
+
61
+ double(name: string) {
62
+ return this.#column({ name, type: 'DOUBLE', nullable: false })
63
+ }
64
+
65
+ date(name: string) {
66
+ return this.#column({ name, type: 'DATE', nullable: false })
67
+ }
68
+
69
+ dateTime(name: string) {
70
+ return this.#column({ name, type: 'DATETIME', nullable: false })
71
+ }
72
+
73
+ timestamp(name: string) {
74
+ return this.#column({ name, type: 'TIMESTAMP', nullable: false })
75
+ }
76
+
77
+ time(name: string) {
78
+ return this.#column({ name, type: 'TIME', nullable: false })
79
+ }
80
+
81
+ json(name: string) {
82
+ return this.#column({ name, type: 'JSON', nullable: false })
83
+ }
84
+
85
+ enum(name: string, values: string[]) {
86
+ return this.#column({ name, type: `ENUM(${values.map(v => `'${v}'`).join(', ')})`, nullable: false })
87
+ }
88
+
89
+ timestamps() {
90
+ this.timestamp('created_at')
91
+ this.timestamp('updated_at')
92
+ return this
93
+ }
94
+
95
+ softDelete(name: string = 'deleted_at') {
96
+ this.timestamp(name).nullable()
97
+ return this
98
+ }
99
+
100
+ softDeletes(name: string = 'deleted_at') {
101
+ return this.softDelete(name)
102
+ }
103
+
104
+ foreign(column: string) {
105
+ const fk: ForeignKeyDefinition = { column, references: '', on: '' }
106
+ this.#foreignKeys.push(fk)
107
+ return new ForeignKey(fk)
108
+ }
109
+
110
+ index(columns: string | string[], name?: string): this {
111
+ this.#indexes.push({
112
+ columns: Array.isArray(columns) ? columns : [columns],
113
+ type: 'index',
114
+ name
115
+ })
116
+ return this
117
+ }
118
+
119
+ unique(columns: string | string[], name?: string): this {
120
+ this.#indexes.push({
121
+ columns: Array.isArray(columns) ? columns : [columns],
122
+ type: 'unique',
123
+ name
124
+ })
125
+ return this
126
+ }
127
+
128
+ primary(columns: string | string[], name?: string): this {
129
+ this.#indexes.push({
130
+ columns: Array.isArray(columns) ? columns : [columns],
131
+ type: 'primary',
132
+ name
133
+ })
134
+ return this
135
+ }
136
+
137
+ dropColumn(...name: string[] | string[][]): this {
138
+ this.#dropColumns.push(...name.flat(Infinity) as string[])
139
+ return this
140
+ }
141
+
142
+ renameColumn(from: string, to: string): this {
143
+ this.#renameColumns.set(from, to)
144
+ return this
145
+ }
146
+
147
+ get table(): string {
148
+ return this.#table
149
+ }
150
+
151
+ get columns() {
152
+ return this.#columns
153
+ }
154
+
155
+ get indexes() {
156
+ return this.#indexes
157
+ }
158
+
159
+ get foreignKeys() {
160
+ return this.#foreignKeys
161
+ }
162
+
163
+ get dropColumns() {
164
+ return this.#dropColumns
165
+ }
166
+
167
+ get renameColumns() {
168
+ return this.#renameColumns
169
+ }
170
+ }
@@ -0,0 +1,167 @@
1
+ import { Blueprint } from './blueprint'
2
+ import type { ColumnDefinition, IndexDefinition, ForeignKeyDefinition } from './types'
3
+
4
+ export default class SchemaBuilder {
5
+ static create(blueprint: Blueprint): string {
6
+ const tableName = blueprint.table
7
+ const columns = blueprint.columns
8
+ const indexes = blueprint.indexes
9
+ const foreignKeys = blueprint.foreignKeys
10
+
11
+ const columnDefinitions = columns.map(col => this.#column(col))
12
+ const indexDefinitions = indexes.map(idx => this.#index(idx, tableName))
13
+ const foreignKeyDefinitions = foreignKeys.map(fk => this.#foreignKey(fk))
14
+
15
+ const allDefinitions = [
16
+ ...columnDefinitions,
17
+ ...indexDefinitions,
18
+ ...foreignKeyDefinitions
19
+ ].filter(Boolean)
20
+
21
+ return `CREATE TABLE ${tableName} (\n ${allDefinitions.join(',\n ')}\n);`
22
+ }
23
+
24
+ static alter(blueprint: Blueprint): string[] {
25
+ const tableName = blueprint.table
26
+ const statements: string[] = []
27
+
28
+ const columns = blueprint.columns
29
+ if (columns.length > 0)
30
+ columns.forEach(col => statements.push(`ALTER TABLE ${tableName} ADD COLUMN ${this.#column(col)};`))
31
+
32
+ const dropColumns = blueprint.dropColumns
33
+ dropColumns.forEach(col => statements.push(`ALTER TABLE ${tableName} DROP COLUMN ${col};`))
34
+
35
+ const renameColumns = blueprint.renameColumns
36
+ renameColumns.forEach((newName, oldName) => statements.push(`ALTER TABLE ${tableName} RENAME COLUMN ${oldName} TO ${newName};`))
37
+
38
+ const indexes = blueprint.indexes
39
+ indexes.forEach(idx => {
40
+ const indexSql = this.#indexStatement(idx, tableName)
41
+ if (indexSql) statements.push(indexSql)
42
+ })
43
+
44
+ const foreignKeys = blueprint.foreignKeys
45
+ foreignKeys.forEach(fk => statements.push(`ALTER TABLE ${tableName} ADD ${this.#foreignKey(fk)};`))
46
+
47
+ return statements
48
+ }
49
+
50
+ static #column(column: ColumnDefinition) {
51
+ let sql = `${column.name} ${column.type}`
52
+
53
+ if (column.length && !column.type.includes('('))
54
+ sql += `(${column.length})`
55
+
56
+ if (column.unsigned)
57
+ sql += ' UNSIGNED'
58
+
59
+ if (column.nullable) {
60
+ sql += ' NULL'
61
+ } else {
62
+ sql += ' NOT NULL'
63
+ }
64
+
65
+ if (column.autoIncrement)
66
+ sql += ' AUTO_INCREMENT'
67
+
68
+ if (column.default !== undefined) {
69
+ if (column.default === null) {
70
+ sql += ' DEFAULT NULL'
71
+ } else if (typeof column.default === 'string') {
72
+ sql += ` DEFAULT '${column.default}'`
73
+ } else if (typeof column.default === 'boolean') {
74
+ sql += ` DEFAULT ${column.default ? 1 : 0}`
75
+ } else {
76
+ sql += ` DEFAULT ${column.default}`
77
+ }
78
+ }
79
+
80
+ if (column.unique)
81
+ sql += ' UNIQUE'
82
+
83
+ if (column.primary)
84
+ sql += ' PRIMARY KEY'
85
+
86
+ if (column.comment)
87
+ sql += ` COMMENT '${column.comment.replace(/'/g, "''")}'`
88
+
89
+ return sql
90
+ }
91
+
92
+ static #index(index: IndexDefinition, tableName: string): string {
93
+ const indexName = index.name || `${tableName}_${index.columns.join('_')}_${index.type}`
94
+ const columns = index.columns.join(', ')
95
+
96
+ switch (index.type) {
97
+ case 'primary':
98
+ return `PRIMARY KEY (${columns})`
99
+ case 'unique':
100
+ return `UNIQUE KEY ${indexName} (${columns})`
101
+ case 'index':
102
+ return `KEY ${indexName} (${columns})`
103
+ default:
104
+ return ''
105
+ }
106
+ }
107
+
108
+ static #indexStatement(index: IndexDefinition, tableName: string): string {
109
+ const indexName = index.name || `${tableName}_${index.columns.join('_')}_${index.type}`
110
+ const columns = index.columns.join(', ')
111
+
112
+ switch (index.type) {
113
+ case 'primary':
114
+ return `ALTER TABLE ${tableName} ADD PRIMARY KEY (${columns});`
115
+ case 'unique':
116
+ return `CREATE UNIQUE INDEX ${indexName} ON ${tableName} (${columns});`
117
+ case 'index':
118
+ return `CREATE INDEX ${indexName} ON ${tableName} (${columns});`
119
+ default:
120
+ return ''
121
+ }
122
+ }
123
+
124
+ static #foreignKey(fk: ForeignKeyDefinition): string {
125
+ let sql = `FOREIGN KEY (${fk.column}) REFERENCES ${fk.on}(${fk.references})`
126
+
127
+ if (fk.onDelete)
128
+ sql += ` ON DELETE ${fk.onDelete.toUpperCase()}`
129
+
130
+ if (fk.onUpdate)
131
+ sql += ` ON UPDATE ${fk.onUpdate.toUpperCase()}`
132
+
133
+ return sql
134
+ }
135
+
136
+ static drop(tableName: string) {
137
+ return `DROP TABLE ${tableName};`
138
+ }
139
+
140
+ static dropIfExists(tableName: string) {
141
+ return `DROP TABLE IF EXISTS ${tableName};`
142
+ }
143
+
144
+ static rename(from: string, to: string) {
145
+ return `ALTER TABLE ${from} RENAME TO ${to};`
146
+ }
147
+
148
+ static hasTable(tableName: string) {
149
+ return `SELECT name FROM sqlite_master WHERE type='table' AND name='${tableName}';`
150
+ }
151
+
152
+ static hasColumn(tableName: string, columnName: string) { // TODO refactor..
153
+ return `PRAGMA table_info(${tableName});`
154
+ }
155
+
156
+ static getAllTables() {
157
+ return `SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%';`
158
+ }
159
+
160
+ static getColumns(tableName: string): string {
161
+ return `PRAGMA table_info(${tableName});`
162
+ }
163
+
164
+ static dropAllTables(tables: string[]) {
165
+ return tables.map(table => `DROP TABLE IF EXISTS ${table};`)
166
+ }
167
+ }
@@ -0,0 +1,45 @@
1
+ import { ColumnDefinition } from './types'
2
+
3
+ export default class Column {
4
+ constructor(private column: ColumnDefinition) {}
5
+
6
+ nullable() {
7
+ this.column.nullable = true
8
+ return this
9
+ }
10
+
11
+ unique() {
12
+ this.column.unique = true
13
+ return this
14
+ }
15
+
16
+ default(value: any) {
17
+ this.column.default = value
18
+ return this
19
+ }
20
+
21
+ unsigned() {
22
+ this.column.unsigned = true
23
+ return this
24
+ }
25
+
26
+ index() {
27
+ this.column.index = true
28
+ return this
29
+ }
30
+
31
+ comment(text: string) {
32
+ this.column.comment = text
33
+ return this
34
+ }
35
+
36
+ primary() {
37
+ this.column.primary = true
38
+ return this
39
+ }
40
+
41
+ autoIncrement() {
42
+ this.column.autoIncrement = true
43
+ return this
44
+ }
45
+ }
@@ -0,0 +1,25 @@
1
+ import type { ForeignKeyDefinition } from './types'
2
+
3
+ export default class ForeignKey {
4
+ constructor(private fk: ForeignKeyDefinition) {}
5
+
6
+ references(column: string) {
7
+ this.fk.references = column
8
+ return this
9
+ }
10
+
11
+ on(table: string) {
12
+ this.fk.on = table
13
+ return this
14
+ }
15
+
16
+ onDelete(action: 'cascade' | 'set null' | 'restrict' | 'no action') {
17
+ this.fk.onDelete = action;
18
+ return this;
19
+ }
20
+
21
+ onUpdate(action: 'cascade' | 'set null' | 'restrict' | 'no action') {
22
+ this.fk.onUpdate = action
23
+ return this
24
+ }
25
+ }
@@ -0,0 +1,5 @@
1
+ export { Migration } from './migration'
2
+ export { Migrator } from './migrator'
3
+
4
+ export { Schema } from './schema'
5
+ export { Blueprint } from './blueprint'
@@ -0,0 +1,5 @@
1
+ export abstract class Migration {
2
+ static async run(): Promise<void> {
3
+ throw new Error('Method run() must be implemented in migration class')
4
+ }
5
+ }
@@ -0,0 +1,110 @@
1
+ import glob from 'tiny-glob'
2
+ import { mkdirSync, existsSync, writeFileSync } from 'node:fs'
3
+ import { dirname, join, resolve } from 'node:path'
4
+ import { Datte, IMPORT } from 't0n'
5
+ import { Schema } from './schema'
6
+ import { MigrationInfo, MigrationClass } from './types'
7
+
8
+ const __root = resolve(dirname(new URL(import.meta.url).pathname), '../../../..')
9
+
10
+ export class Migrator {
11
+ static #dir: string = ''
12
+ static #folder: string = 'migrations'
13
+ static #sqlFolder: string = 'sql'
14
+
15
+ static dir(dir: string) {
16
+ this.#dir = dir
17
+ return this
18
+ }
19
+
20
+ static folder(dir: string) {
21
+ this.#dir = dir
22
+ return this
23
+ }
24
+
25
+ static async toSql(outputDir: string = '') {
26
+ const dir = this.#dir || join(__root, this.#folder)
27
+ outputDir ||= join(dir, this.#sqlFolder)
28
+
29
+ this.#ensureDir(dir)
30
+ this.#ensureDir(outputDir)
31
+ const files = (await glob(join(dir, '/*.{ts,js}'))).filter(file => !file.includes('.d.')) // TODO: sort
32
+
33
+ for (const file of files) {
34
+ const info = await this.#info(file)
35
+ if (!info)
36
+ continue // TODO: trigger a warn
37
+
38
+ const sql = await this.run(info.handler)
39
+ const path = join(outputDir, info.name +'.sql')
40
+ if (!existsSync(path))
41
+ writeFileSync(path, `-- Migration: ${info.name}\n\n${sql}\n`)
42
+ }
43
+
44
+ }
45
+
46
+ static async run(handler: MigrationClass) {
47
+ // try {
48
+ // await migrationClass.up()
49
+ // } catch (error) {
50
+ // // Try run() if up() is not implemented
51
+ // if (migrationClass.run) {
52
+ // await migrationClass.run()
53
+ // } else {
54
+ // throw error
55
+ // }
56
+ // }
57
+
58
+ if (!handler?.run) return ''
59
+ Schema.clearStatements()
60
+ await handler.run()
61
+ return Schema.sql
62
+ }
63
+
64
+ static async #info(fileName: string): Promise<MigrationInfo | null> {
65
+ const name = fileName.replace(/\.[jt]s$/, '')
66
+ const match = name.match(/\/(\d{4})_(\d{2})_(\d{2})_(\d{2})(\d{2})(\d{2})_(.+)$/)
67
+
68
+ if (!match) return null
69
+ const [, year, month, day, hour, minute, second, slugName] = match
70
+
71
+ const mod = await IMPORT(join(__root, fileName))
72
+ const handler = mod.default as MigrationClass
73
+
74
+ return {
75
+ timestamp: new Date(
76
+ parseInt(year),
77
+ parseInt(month) - 1, // Js months are 0-indexed
78
+ parseInt(day),
79
+ parseInt(hour),
80
+ parseInt(minute),
81
+ parseInt(second)
82
+ ).getTime(),
83
+ name: name.split('/').at(-1) as string,
84
+ fileName,
85
+ className: this.#toClassName(slugName),
86
+ handler,
87
+ }
88
+ }
89
+
90
+ static #toClassName(name: string) {
91
+ return name
92
+ .split(/[-_.]/)
93
+ .map(s => s.charAt(0).toUpperCase() + s.slice(1).toLowerCase())
94
+ .join('')
95
+ }
96
+
97
+ static fileName(name: string) {
98
+ return (
99
+ name.replace(/([A-Z])/g, '_$1') // snake_case
100
+ .replace(/\s+/g, '_')
101
+ .toLowerCase()
102
+ + '_'
103
+ + Datte.dateTime().replace(/[:.-]/g, '_').replace(/_+/g, '_')
104
+ ).replace(/^_+|_+$/g, '')
105
+ }
106
+
107
+ static #ensureDir(dir: string) {
108
+ if (!existsSync(dir)) mkdirSync(dir, { recursive: true })
109
+ }
110
+ }
@@ -0,0 +1,151 @@
1
+
2
+ import { Blueprint } from './blueprint'
3
+ import Builder from './builder'
4
+
5
+ import type {
6
+ BlueprintFn,
7
+ // SchemaConnection,
8
+ } from './types'
9
+
10
+ export class Schema {
11
+ // static #c: SchemaConnection | null = null
12
+ static #statements: string[] = []
13
+ static #foreignKeyConstraintsEnabled = true
14
+
15
+ // static setConnection(connection: SchemaConnection) {
16
+ // this.#c = connection
17
+ // return this
18
+ // }
19
+
20
+ static get statements() {
21
+ return this.#statements
22
+ }
23
+
24
+ static clearStatements() {
25
+ this.#statements = []
26
+ return this
27
+ }
28
+
29
+ static #addStatement(...sql: string[] | string[][]) {
30
+ this.#statements.push(...sql.flat(Infinity) as string[])
31
+ }
32
+
33
+ // mudei tudo this.#executeSql -> this.#addStatement
34
+ // static async #executeSql(...sql: string[] | string[][]): Promise<void> {
35
+ // sql = sql.flat(Infinity) as string[]
36
+ // // if (this.#c) {
37
+ // // for (const statement of sql) {
38
+ // // await this.#c.execute(statement)
39
+ // // }
40
+ // // }
41
+ // this.#addStatement(...sql)
42
+ // }
43
+
44
+ static async create(tableName: string, fn: BlueprintFn): Promise<void> {
45
+ const blueprint = new Blueprint(tableName)
46
+ fn(blueprint)
47
+ await this.#addStatement(Builder.create(blueprint))
48
+ }
49
+
50
+ static async table(tableName: string, fn: BlueprintFn): Promise<void> {
51
+ const blueprint = new Blueprint(tableName)
52
+ fn(blueprint)
53
+ await this.#addStatement(Builder.alter(blueprint))
54
+ }
55
+
56
+ static async drop(tableName: string): Promise<void> {
57
+ await this.#addStatement(Builder.drop(tableName))
58
+ }
59
+
60
+ static async dropIfExists(tableName: string): Promise<void> {
61
+ await this.#addStatement(Builder.dropIfExists(tableName))
62
+ }
63
+
64
+ static async rename(from: string, to: string): Promise<void> {
65
+ await this.#addStatement(Builder.rename(from, to))
66
+ }
67
+
68
+ static async disableForeignKeyConstraints(): Promise<void> {
69
+ this.#foreignKeyConstraintsEnabled = false
70
+ await this.#addStatement('PRAGMA foreign_keys = OFF;')
71
+ }
72
+
73
+ static async enableForeignKeyConstraints(): Promise<void> {
74
+ this.#foreignKeyConstraintsEnabled = true
75
+ await this.#addStatement('PRAGMA foreign_keys = ON;')
76
+ }
77
+
78
+ static isForeignKeyConstraintsEnabled(): boolean {
79
+ return this.#foreignKeyConstraintsEnabled
80
+ }
81
+
82
+ static get sql() {
83
+ return this.#statements.join('\n\n')
84
+ }
85
+ static get raw() {
86
+ return this.sql
87
+ }
88
+
89
+ // static async dropAllTables(): Promise<void> {
90
+ // const tables = await this.getAllTables()
91
+ // const sql = Builder.dropAllTables(tables)
92
+ // await this.#addStatement(sql)
93
+ // }
94
+
95
+ // static async hasTable(tableName: string): Promise<boolean> {
96
+ // if (!this.#c)
97
+ // throw new Error('Database connection not set')
98
+
99
+ // const sql = Builder.hasTable(tableName)
100
+ // const result = await this.#c.query(sql)
101
+ // return result.length > 0
102
+ // }
103
+
104
+ // static async hasColumn(tableName: string, columnName: string): Promise<boolean> {
105
+ // if (!this.#c)
106
+ // throw new Error('Database connection not set')
107
+
108
+ // const sql = Builder.hasColumn(tableName, columnName)
109
+ // const result = await this.#c.query(sql)
110
+ // return result.some((row: any) => row.name === columnName)
111
+ // }
112
+
113
+ // static async hasColumns(tableName: string, ...columnNames: string[]): Promise<boolean> {
114
+ // if (!this.#c)
115
+ // throw new Error('Database connection not set')
116
+
117
+ // const sql = Builder.hasColumn(tableName, '')
118
+ // const result = await this.#c.query(sql)
119
+ // const existingColumns = result.map((row: any) => row.name)
120
+
121
+ // return columnNames.every(col => existingColumns.includes(col))
122
+ // }
123
+
124
+ // static async getAllTables(): Promise<string[]> {
125
+ // if (!this.#c)
126
+ // throw new Error('Database connection not set')
127
+
128
+ // const sql = Builder.getAllTables()
129
+ // const result = await this.#c.query(sql)
130
+ // return result.map((row: any) => row.name)
131
+ // }
132
+
133
+ // static async getColumns(tableName: string): Promise<any[]> {
134
+ // if (!this.#c)
135
+ // throw new Error('Database connection not set')
136
+
137
+ // const sql = Builder.getColumns(tableName)
138
+ // return await this.#c.query(sql)
139
+ // }
140
+
141
+ // static async getColumnType(tableName: string, columnName: string): Promise<string | null> {
142
+ // if (!this.#c) {
143
+ // throw new Error('Database connection not set')
144
+ // }
145
+
146
+ // const sql = Builder.getColumns(tableName)
147
+ // const result = await this.#c.query(sql)
148
+ // const column = result.find((row: any) => row.name === columnName)
149
+ // return column ? column.type : null
150
+ // }
151
+ }
@@ -0,0 +1,64 @@
1
+ import { Blueprint } from './blueprint'
2
+ import { Migration } from './migration'
3
+
4
+ export type BlueprintFn = (table: Blueprint) => void
5
+
6
+
7
+ // TODO: refactor bellow
8
+
9
+ export interface ColumnDefinition {
10
+ name: string,
11
+ type: string,
12
+ length?: number,
13
+ nullable?: boolean,
14
+ unique?: boolean,
15
+ primary?: boolean,
16
+ autoIncrement?: boolean,
17
+ default?: any,
18
+ unsigned?: boolean,
19
+ index?: boolean,
20
+ comment?: string,
21
+ }
22
+
23
+ export interface IndexDefinition {
24
+ columns: string[],
25
+ type: 'index' | 'unique' | 'primary',
26
+ name?: string,
27
+ }
28
+
29
+ export interface ForeignKeyDefinition {
30
+ column: string,
31
+ references: string,
32
+ on: string,
33
+ onDelete?: 'cascade' | 'set null' | 'restrict' | 'no action',
34
+ onUpdate?: 'cascade' | 'set null' | 'restrict' | 'no action',
35
+ }
36
+
37
+ export interface MigrationInfo {
38
+ timestamp: number,
39
+ name: string,
40
+ fileName: string,
41
+ className: string,
42
+ handler: MigrationClass,
43
+ }
44
+
45
+ export interface MigrationRecord {
46
+ migration: string;
47
+ batch: number;
48
+ executed_at: Date;
49
+ }
50
+
51
+ export type MigrationClass = {
52
+ // new (): MigrationClass;
53
+ // new(): Migration;
54
+ // up(): Promise<void>;
55
+ // down(): Promise<void>;
56
+ run(): Promise<void>
57
+ // toSQL?(): Promise<string>;
58
+ // getMigrationName?(): string;
59
+ }
60
+
61
+ // export interface SchemaConnection {
62
+ // execute(sql: string): Promise<any>,
63
+ // query(sql: string): Promise<any[]>,
64
+ // }
package/src/model.ts CHANGED
@@ -15,7 +15,7 @@ export default abstract class Model<TB extends keyof DB, DB> {
15
15
  static $schema?: DBSchema
16
16
 
17
17
  static pipe<S, T>(): Pipe<S, T> {
18
- throw new Error(`Database connection not provided.`) // improv this message
18
+ throw new Error(`Database connection not provided.`) // TODO: improv this message
19
19
  }
20
20
 
21
21
  static builder<S, T>() {