Skip to content

Commit 9d8dd0c

Browse files
committed
+: methods description, finished alter table's checks with sqlite_schema that's now asked to the user, multiple case of duplicated code in a single function; tbf with tests on a real db
1 parent 1c218ca commit 9d8dd0c

File tree

1 file changed

+83
-34
lines changed

1 file changed

+83
-34
lines changed

src/manager.ts

Lines changed: 83 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,14 @@ enum AT {
2222
* When creating a new istance of the SQLiteManager class, the constructor:
2323
* - will get you in the alter table section if you pass an entire table
2424
* - will get you to the create table section if you just pass the name of the table or you pass nothing
25+
* IMPORTANT: if you don't call sqlite_schema before making any change, then old views, triggers and indexes will be lost
2526
*
2627
* */
2728
export class SQLiteManager {
2829
private table: SQLiteManagerTable
2930
private create = false
3031
private query = ''
32+
private sql: string[] = []
3133

3234
constructor(table?: SQLiteManagerTable) {
3335
if (typeof table === 'undefined') {
@@ -44,8 +46,9 @@ export class SQLiteManager {
4446
}
4547
}
4648

47-
reset(): void {
48-
this.table = {} as SQLiteManagerTable
49+
/** Pass to this method the result of this query: SELECT sql FROM sqlite_schema WHERE tbl_name='X'; where X is the name of the table you're using */
50+
sqlite_schema(sql: string[]): void {
51+
this.sql = sql
4952
}
5053

5154
/** If changing name in altertable you need to manually call the queryBuilder() */
@@ -98,8 +101,15 @@ export class SQLiteManager {
98101
}
99102
break
100103
case AT.DROP_COLUMN:
101-
if (this.isReferenced(column) || column.constraints?.PRIMARY_KEY || column.constraints?.UNIQUE) {
102-
query += this.queryBuilder('', {} as SQLiteManagerColumn)
104+
if (
105+
this.is(column, true) ||
106+
column.constraints?.PRIMARY_KEY ||
107+
column.constraints?.UNIQUE ||
108+
this.sql?.includes(column.name) ||
109+
this.is(column, false, true)
110+
// can't check for generated columns and outside this table CHECK constraints
111+
) {
112+
query += this.queryBuilder('' + AT[op], column)
103113
} else {
104114
this.query += 'ALTER TABLE "' + this.table.name + '" DROP COLUMN "' + column.name + '";\n'
105115
}
@@ -110,10 +120,6 @@ export class SQLiteManager {
110120
default:
111121
this.query += '\n\nPRAGMA foreign_keys = OFF;\n'
112122
this.query += 'BEGIN TRANSACTION;\n'
113-
/*
114-
this.query += 'WITH indexntriggernview AS (SELECT type, sql FROM sqlite_schema WHERE tbl_name="' + this.table.name + '");\n'
115-
DROP views, indexes and triggers
116-
*/
117123
this.create = true
118124
oldname = this.table.name
119125
if (typeof this.findColumn('new_' + this.table.name) == 'undefined') {
@@ -128,10 +134,21 @@ export class SQLiteManager {
128134
this.query += 'ALTER TABLE "' + this.table.name + '" RENAME TO "' + oldname + '";\n'
129135
this.table.name = oldname
130136
this.query += 'CREATE INDEX '
131-
/*
132-
Reconstruct using CREATE INDEX, CREATE TRIGGER, and CREATE VIEW
133-
If any views refer to table X in a way that is affected by the schema change, then drop those views using DROP VIEW and recreate them with whatever changes are necessary to accommodate the schema change using CREATE VIEW.
134-
*/
137+
138+
if (this.sql) {
139+
if (op == 'DROP_COLUMN' && column) {
140+
this.sql.forEach(element => {
141+
if (!element.includes(column.name)) {
142+
query += element + '\n'
143+
}
144+
})
145+
} else {
146+
this.sql.forEach(element => {
147+
query += element + '\n'
148+
})
149+
}
150+
}
151+
135152
this.query += 'PRAGMA foreign_key_check("' + this.table.name + '");\n'
136153
this.query += 'COMMIT;\n'
137154
this.query += 'PRAGMA foreign_keys = ON;\n'
@@ -214,18 +231,11 @@ export class SQLiteManager {
214231
return query
215232
}
216233

217-
private isReferenced(column: SQLiteManagerColumn): boolean {
218-
if (this.table.columns) {
219-
for (let i = 0; i < this.table.columns.length; i++) {
220-
if (this.table.columns[i].constraints?.ForeignKey?.column == column.name) {
221-
return true
222-
}
223-
}
224-
}
225-
return false
226-
}
227-
228-
addColumn(column: SQLiteManagerColumn): string {
234+
/**
235+
* column: the SQLiteManagerColumn you want to add to the table
236+
* sql[]: SELECT sql FROM sqlite_schema WHERE tbl_name='X'; where X is the name of the table you're using
237+
*/
238+
addColumn(column: SQLiteManagerColumn, sql: string[]): string {
229239
if (this.table.columns) {
230240
if (typeof this.findColumn(column.name) == 'undefined') {
231241
this.table.columns.push(column)
@@ -236,10 +246,15 @@ export class SQLiteManager {
236246
this.table.columns = [column]
237247
}
238248

249+
this.sqlite_schema(sql)
239250
return this.queryBuilder(AT.ADD_COLUMN, column)
240251
}
241252

242-
deleteColumn(name: string): string {
253+
/**
254+
* name: name of the column you want to delete
255+
* sql[]: SELECT sql FROM sqlite_schema WHERE tbl_name='X'; where X is the name of the table you're using
256+
*/
257+
deleteColumn(name: string, sql: string[]): string {
243258
let query = ''
244259
const i = this.findColumn(name)
245260

@@ -253,6 +268,7 @@ export class SQLiteManager {
253268
}
254269
}
255270

271+
this.sqlite_schema(sql)
256272
return query
257273
}
258274

@@ -270,24 +286,43 @@ export class SQLiteManager {
270286
return this.queryBuilder(AT.RENAME_COLUMN, { name: oldColumnName } as SQLiteManagerColumn, newColumnName)
271287
}
272288

273-
changeColumnType(name: string, type: SQLiteManagerType): string {
274-
const i = this.findColumn(name)
289+
/**
290+
* name: name of the column you want to change the type of
291+
* type: the new type you want to give to the column
292+
* sql[]: SELECT sql FROM sqlite_schema WHERE tbl_name='X'; where X is the name of the table you're using
293+
*/
294+
changeColumnType(name: string, type: SQLiteManagerType, sql: string[]): string {
295+
return this.generalFun(name, (column: SQLiteManagerColumn) => (column.type = type), sql)
296+
}
275297

276-
if (typeof i != 'undefined' && this.table.columns) {
277-
this.table.columns[i].type = type
278-
}
298+
/**
299+
* name: name of the column you want to change constraints of
300+
* constraits: edited constraints you get from getConstraints()
301+
* sql[]: SELECT sql FROM sqlite_schema WHERE tbl_name='X'; where X is the name of the table you're using
302+
*/
303+
changeColumnConstraints(name: string, constraints: SQLiteManagerConstraints, sql: string[]): string {
304+
return this.generalFun(name, (column: SQLiteManagerColumn) => (column.constraints = constraints), sql)
305+
}
279306

280-
return this.queryBuilder('', {} as SQLiteManagerColumn)
307+
/** name: name of the column you want to get the constraints of */
308+
getConstraints(name: string): SQLiteManagerConstraints | undefined {
309+
let rtconstraints
310+
this.generalFun(name, (column: SQLiteManagerColumn) => (rtconstraints = column.constraints))
311+
return rtconstraints
281312
}
282313

283-
changeColumnConstraints(name: string, constraints: SQLiteManagerConstraints): string {
314+
private generalFun(name: string, fun: (column: SQLiteManagerColumn) => void, sql?: string[], qb1?: any, qb2?: SQLiteManagerColumn): string {
284315
const i = this.findColumn(name)
285316

286317
if (typeof i != 'undefined' && this.table.columns) {
287-
this.table.columns[i].constraints = constraints
318+
fun(this.table.columns[i])
288319
}
289320

290-
return this.queryBuilder('', {} as SQLiteManagerColumn)
321+
if (sql) {
322+
this.sqlite_schema(sql)
323+
}
324+
325+
return this.queryBuilder(qb1 ? qb1 : '', qb2 ? qb2 : ({} as SQLiteManagerColumn))
291326
}
292327

293328
private findColumn(name: string): number | undefined {
@@ -298,4 +333,18 @@ export class SQLiteManager {
298333
}
299334
}
300335
}
336+
337+
private is(column: SQLiteManagerColumn, referenced?: boolean, checked?: boolean): boolean {
338+
if (this.table.columns) {
339+
for (let i = 0; i < this.table.columns.length; i++) {
340+
if (referenced && this.table.columns[i].constraints?.ForeignKey?.column == column.name) {
341+
return true
342+
}
343+
if (checked && this.table.columns[i].constraints?.Check?.includes(column.name)) {
344+
return true
345+
}
346+
}
347+
}
348+
return false
349+
}
301350
}

0 commit comments

Comments
 (0)