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 CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "forj",
3
3
  "description": "SQLite ORM and Query Builder whitout dependencies",
4
- "version": "0.1.4",
4
+ "version": "0.1.6",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
7
7
  "files": ["src"],
@@ -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 = tableName(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 { tableName, tableSlug } from '../utils'
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 = tableName(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 = tableName(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 ' : ''}${tableName(table)};`
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 ' : ''}[${tableName(view)}];`
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 ${tableName(from)} RENAME TO ${tableName(to)};`
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='${tableName(table)}';`
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(${tableName(table)});`
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(${tableName(table)});`
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 ${tableName(table)};`)
183
+ return tables.map(table => `DROP TABLE IF EXISTS ${sqlName(table)};`)
184
184
  }
185
185
  }
@@ -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)
@@ -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)) { // @ts-ignore
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('.') ? name : table +'.'+ name
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
- // if (!schema) return typeof val == 'string' && val?.includes('.')
129
- if (!schema || typeof val != 'string' || !val?.includes('.'))
130
+ if (typeof val != 'string' || !val?.includes('.'))
130
131
  return false
131
132
 
132
- const keys = zGet(val, schema)
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 tableName(name: string) {
162
+ export function sqlName(name?: string) {
157
163
  return !name
158
164
  || !name.match(/^[a-zA-Z_]/)
159
165
  || name.match(/\W/)