forj 0.1.4 → 0.1.6
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 +1 -1
- package/src/clause-builder.ts +1 -2
- package/src/migrations/blueprint.ts +1 -2
- package/src/migrations/builder.ts +18 -18
- package/src/migrations/schema.ts +1 -0
- package/src/query-builder.ts +6 -6
- package/src/utils.ts +11 -5
package/package.json
CHANGED
package/src/clause-builder.ts
CHANGED
|
@@ -79,9 +79,8 @@ export default class ClauseBuilder<
|
|
|
79
79
|
// @ts-ignore
|
|
80
80
|
column = parseColumn(String(column), this.#table)
|
|
81
81
|
|
|
82
|
-
if (this.#schema && !zSame(column, value, this.#schema))
|
|
82
|
+
if (this.#schema && !zSame(column.replace(/"/g, ''), value, this.#schema))
|
|
83
83
|
throw new Error(`Table column '${String(column)}' of type '${zType(column, this.#schema)}' is not assignable as type of '${typeof value}'.`)
|
|
84
|
-
}
|
|
85
84
|
|
|
86
85
|
return isJoinCompare(value, this.#schema) // @ts-ignore
|
|
87
86
|
? this.#clause(`${column} ${operator} ${value}`, [], logical) // @ts-ignore
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import pluralize from 'pluralize'
|
|
2
2
|
import Column from './column'
|
|
3
3
|
import ForeignKey from './foreign-key'
|
|
4
|
-
import { tableName } from '../utils'
|
|
5
4
|
import type {
|
|
6
5
|
ColumnDefinition, IndexDefinition, ForeignKeyDefinition,
|
|
7
6
|
} from './types'
|
|
@@ -15,7 +14,7 @@ export class Blueprint {
|
|
|
15
14
|
#renameColumns: Map<string, string> = new Map()
|
|
16
15
|
|
|
17
16
|
constructor(table: string) {
|
|
18
|
-
this.#table =
|
|
17
|
+
this.#table = table
|
|
19
18
|
}
|
|
20
19
|
|
|
21
20
|
#column(definition: ColumnDefinition) {
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { Blueprint } from './blueprint'
|
|
2
|
-
import {
|
|
2
|
+
import { sqlName, tableSlug } from '../utils'
|
|
3
3
|
import type { ColumnDefinition, IndexDefinition, ForeignKeyDefinition } from './types'
|
|
4
4
|
|
|
5
5
|
export default class SchemaBuilder {
|
|
6
6
|
static create(blueprint: Blueprint, exist: boolean = false): string {
|
|
7
|
-
const table = blueprint.table
|
|
7
|
+
const table = sqlName(blueprint.table)
|
|
8
8
|
const columns = blueprint.columns
|
|
9
9
|
const indexes = blueprint.indexes
|
|
10
10
|
const foreignKeys = blueprint.foreignKeys
|
|
@@ -23,7 +23,7 @@ export default class SchemaBuilder {
|
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
static alter(blueprint: Blueprint): string[] {
|
|
26
|
-
const table = blueprint.table
|
|
26
|
+
const table = sqlName(blueprint.table)
|
|
27
27
|
const statements: string[] = []
|
|
28
28
|
|
|
29
29
|
const columns = blueprint.columns
|
|
@@ -31,10 +31,10 @@ export default class SchemaBuilder {
|
|
|
31
31
|
columns.forEach(col => statements.push(`ALTER TABLE ${table} ADD COLUMN ${this.#column(col)};`))
|
|
32
32
|
|
|
33
33
|
const dropColumns = blueprint.dropColumns
|
|
34
|
-
dropColumns.forEach(col => statements.push(`ALTER TABLE ${table} DROP COLUMN ${col};`))
|
|
34
|
+
dropColumns.forEach(col => statements.push(`ALTER TABLE ${table} DROP COLUMN ${sqlName(col)};`))
|
|
35
35
|
|
|
36
36
|
const renameColumns = blueprint.renameColumns
|
|
37
|
-
renameColumns.forEach((newName, oldName) => statements.push(`ALTER TABLE ${table} RENAME COLUMN ${oldName} TO ${newName};`))
|
|
37
|
+
renameColumns.forEach((newName, oldName) => statements.push(`ALTER TABLE ${table} RENAME COLUMN ${sqlName(oldName)} TO ${sqlName(newName)};`))
|
|
38
38
|
|
|
39
39
|
const indexes = blueprint.indexes
|
|
40
40
|
indexes.forEach(idx => {
|
|
@@ -49,7 +49,7 @@ export default class SchemaBuilder {
|
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
static #column(column: ColumnDefinition) {
|
|
52
|
-
let sql = `${column.name} ${column.type}`
|
|
52
|
+
let sql = `${sqlName(column.name)} ${column.type}`
|
|
53
53
|
|
|
54
54
|
if (column.length && !column.type.includes('('))
|
|
55
55
|
sql += `(${column.length})`
|
|
@@ -99,8 +99,8 @@ export default class SchemaBuilder {
|
|
|
99
99
|
|
|
100
100
|
static #index(index: IndexDefinition, table: string): string {
|
|
101
101
|
const indexName = index.name || tableSlug(table) +`_${index.columns.join('_')}_${index.type}`
|
|
102
|
-
const columns = index.columns.join(', ')
|
|
103
|
-
table =
|
|
102
|
+
const columns = index.columns.map(column => sqlName(column)).join(', ')
|
|
103
|
+
table = sqlName(table)
|
|
104
104
|
|
|
105
105
|
switch (index.type) {
|
|
106
106
|
case 'primary':
|
|
@@ -116,8 +116,8 @@ export default class SchemaBuilder {
|
|
|
116
116
|
|
|
117
117
|
static #indexStatement(index: IndexDefinition, table: string): string {
|
|
118
118
|
const indexName = index.name || tableSlug(table) +`_${index.columns.join('_')}_${index.type}`
|
|
119
|
-
const columns = index.columns.join(', ')
|
|
120
|
-
table =
|
|
119
|
+
const columns = index.columns.map(column => sqlName(column)).join(', ')
|
|
120
|
+
table = sqlName(table)
|
|
121
121
|
|
|
122
122
|
switch (index.type) {
|
|
123
123
|
case 'primary':
|
|
@@ -132,7 +132,7 @@ export default class SchemaBuilder {
|
|
|
132
132
|
}
|
|
133
133
|
|
|
134
134
|
static #foreignKey(fk: ColumnDefinition | ForeignKeyDefinition, column: boolean = false): string {
|
|
135
|
-
let sql = (column ? '' : `FOREIGN KEY (${fk.name})`) +` REFERENCES ${fk.on}(${fk.references})`
|
|
135
|
+
let sql = (column ? '' : `FOREIGN KEY (${sqlName(fk.name)})`) +` REFERENCES ${sqlName(fk.on)}(${sqlName(fk.references)})`
|
|
136
136
|
|
|
137
137
|
if (fk.onDelete)
|
|
138
138
|
sql += ` ON DELETE ${fk.onDelete.toUpperCase()}`
|
|
@@ -144,7 +144,7 @@ export default class SchemaBuilder {
|
|
|
144
144
|
}
|
|
145
145
|
|
|
146
146
|
static drop(table: string, exist: boolean = false) {
|
|
147
|
-
return `DROP TABLE ${exist ? 'IF EXISTS ' : ''}${
|
|
147
|
+
return `DROP TABLE ${exist ? 'IF EXISTS ' : ''}${sqlName(table)};`
|
|
148
148
|
}
|
|
149
149
|
|
|
150
150
|
static dropIfExists(table: string) {
|
|
@@ -152,7 +152,7 @@ export default class SchemaBuilder {
|
|
|
152
152
|
}
|
|
153
153
|
|
|
154
154
|
static dropView(view: string, exist: boolean = false) {
|
|
155
|
-
return `DROP VIEW ${exist ? 'IF EXISTS ' : ''}[${
|
|
155
|
+
return `DROP VIEW ${exist ? 'IF EXISTS ' : ''}[${sqlName(view)}];`
|
|
156
156
|
}
|
|
157
157
|
|
|
158
158
|
static dropViewIfExists(view: string) {
|
|
@@ -160,15 +160,15 @@ export default class SchemaBuilder {
|
|
|
160
160
|
}
|
|
161
161
|
|
|
162
162
|
static rename(from: string, to: string) {
|
|
163
|
-
return `ALTER TABLE ${
|
|
163
|
+
return `ALTER TABLE ${sqlName(from)} RENAME TO ${sqlName(to)};`
|
|
164
164
|
}
|
|
165
165
|
|
|
166
166
|
static hasTable(table: string) {
|
|
167
|
-
return `SELECT name FROM sqlite_master WHERE type='table' AND name='${
|
|
167
|
+
return `SELECT name FROM sqlite_master WHERE type='table' AND name='${sqlName(table)}';`
|
|
168
168
|
}
|
|
169
169
|
|
|
170
170
|
static hasColumn(table: string, columnName: string) { // TODO refactor..
|
|
171
|
-
return `PRAGMA table_info(${
|
|
171
|
+
return `PRAGMA table_info(${sqlName(table)});`
|
|
172
172
|
}
|
|
173
173
|
|
|
174
174
|
static getAllTables() {
|
|
@@ -176,10 +176,10 @@ export default class SchemaBuilder {
|
|
|
176
176
|
}
|
|
177
177
|
|
|
178
178
|
static getColumns(table: string): string {
|
|
179
|
-
return `PRAGMA table_info(${
|
|
179
|
+
return `PRAGMA table_info(${sqlName(table)});`
|
|
180
180
|
}
|
|
181
181
|
|
|
182
182
|
static dropAllTables(tables: string[]) {
|
|
183
|
-
return tables.map(table => `DROP TABLE IF EXISTS ${
|
|
183
|
+
return tables.map(table => `DROP TABLE IF EXISTS ${sqlName(table)};`)
|
|
184
184
|
}
|
|
185
185
|
}
|
package/src/migrations/schema.ts
CHANGED
|
@@ -56,6 +56,7 @@ export class Schema {
|
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
static createPivot(table: string, fn: BlueprintFn): void
|
|
59
|
+
static createPivot(table: string, columns: string[]): void
|
|
59
60
|
static createPivot(table: string, columns: string[], fn: BlueprintFn): void
|
|
60
61
|
static createPivot(table: string, columns: string[] | BlueprintFn, fn?: BlueprintFn) {
|
|
61
62
|
const hasColumn = Array.isArray(columns)
|
package/src/query-builder.ts
CHANGED
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
formatValue,
|
|
6
6
|
isJoinCompare,
|
|
7
7
|
zSame, zType,
|
|
8
|
+
sqlName,
|
|
8
9
|
} from './utils'
|
|
9
10
|
import type {
|
|
10
11
|
IJoinBuilder, IClauseBuilder,
|
|
@@ -89,7 +90,7 @@ export default class QueryBuilder<
|
|
|
89
90
|
...args: JoinArgs<S, J>
|
|
90
91
|
) {
|
|
91
92
|
this.#hasJoin = true
|
|
92
|
-
const query = (type ? type + ' ' : '') + `JOIN ${table as string} ON `
|
|
93
|
+
const query = (type ? type + ' ' : '') + `JOIN ${sqlName(table as string)} ON `
|
|
93
94
|
|
|
94
95
|
if (typeof args[0] == 'function') {
|
|
95
96
|
const join = new ClauseBuilder<S[J]>(table as string, this.#schema)
|
|
@@ -107,7 +108,6 @@ export default class QueryBuilder<
|
|
|
107
108
|
value = operator
|
|
108
109
|
operator = '='
|
|
109
110
|
} else if (length == 3 && !isOperator(operator)) { // @ts-ignore
|
|
110
|
-
// console.log(column, operator, value, value2) // @ts-ignore
|
|
111
111
|
value = parseColumn(value as string, operator as string) // TODO: check if value is a valid column
|
|
112
112
|
|
|
113
113
|
if (this.#schema && !isJoinCompare(value, this.#schema))
|
|
@@ -115,16 +115,16 @@ export default class QueryBuilder<
|
|
|
115
115
|
|
|
116
116
|
operator = '='
|
|
117
117
|
} else if (length == 4) { // @ts-ignore
|
|
118
|
-
// console.log(column, operator, value, value2) // @ts-ignore
|
|
119
118
|
value = parseColumn(value2 as string, value as string)
|
|
120
119
|
operator = '='
|
|
121
120
|
}
|
|
122
121
|
|
|
123
122
|
const col = parseColumn(String(column), String(table))
|
|
124
|
-
if (this.#schema && !zSame(col, value, this.#schema))
|
|
125
|
-
throw new Error(`Table column '${col}' of type '${zType(col, this.#schema)}' is not assignable as type of '${typeof value}'.`)
|
|
126
123
|
|
|
127
|
-
if (!isJoinCompare(value, this.#schema)) {
|
|
124
|
+
if (!isJoinCompare(value, this.#schema)) {
|
|
125
|
+
if (this.#schema && !zSame(col.replace(/"/g, ''), value, this.#schema))
|
|
126
|
+
throw new Error(`Table column '${col}' of type '${zType(col, this.#schema)}' is not assignable as type of '${typeof value}'.`)
|
|
127
|
+
// @ts-ignore
|
|
128
128
|
this.#clauses.args = [value] // @ts-ignore // TODO: https://developers.cloudflare.com/d1/worker-api/#type-conversion
|
|
129
129
|
value = '?'
|
|
130
130
|
}
|
package/src/utils.ts
CHANGED
|
@@ -25,7 +25,9 @@ export function parseSelectColumn(
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
export function parseColumn(name: string, table: string, hasJoin: boolean = true) {
|
|
28
|
-
return !hasJoin || name.includes('.')
|
|
28
|
+
return !hasJoin || name.includes('.')
|
|
29
|
+
? name.split('.').map(col => sqlName(col)).join('.')
|
|
30
|
+
: sqlName(table) + '.' + sqlName(name)
|
|
29
31
|
}
|
|
30
32
|
|
|
31
33
|
export function formatValue(value: any): string {
|
|
@@ -125,13 +127,17 @@ export const zSame = (key: string, val: any, schema?: any, deep: boolean = false
|
|
|
125
127
|
}
|
|
126
128
|
|
|
127
129
|
export function isJoinCompare(val: any, schema?: DBSchema) {
|
|
128
|
-
|
|
129
|
-
if (!schema || typeof val != 'string' || !val?.includes('.'))
|
|
130
|
+
if (typeof val != 'string' || !val?.includes('.'))
|
|
130
131
|
return false
|
|
131
132
|
|
|
132
|
-
|
|
133
|
+
if (!schema)
|
|
134
|
+
return true
|
|
135
|
+
|
|
136
|
+
const keys = zGet(val.replace(/"/g, ''), schema)
|
|
137
|
+
// const keys = zGet(val, schema)
|
|
133
138
|
return keys && keys?.length
|
|
134
139
|
}
|
|
140
|
+
|
|
135
141
|
// List taken from `aKeywordTable` in https://github.com/sqlite/sqlite/blob/378bf82e2bc09734b8c5869f9b148efe37d29527/tool/mkkeywordhash.c#L172
|
|
136
142
|
// prettier-ignore
|
|
137
143
|
export const SQLITE_KEYWORDS = new Set([
|
|
@@ -153,7 +159,7 @@ export const SQLITE_KEYWORDS = new Set([
|
|
|
153
159
|
'WHERE', 'WINDOW', 'WITH', 'WITHOUT',
|
|
154
160
|
])
|
|
155
161
|
|
|
156
|
-
export function
|
|
162
|
+
export function sqlName(name?: string) {
|
|
157
163
|
return !name
|
|
158
164
|
|| !name.match(/^[a-zA-Z_]/)
|
|
159
165
|
|| name.match(/\W/)
|