neopg 0.0.0

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.
@@ -0,0 +1,506 @@
1
+ 'use strict';
2
+
3
+ const path = require('path');
4
+ const process = require('node:process');
5
+ const randstring = require('./randstring.js');
6
+ const forbidColumns = require('./forbidColumns.js')
7
+
8
+ // 静态映射表 (保持原逻辑)
9
+ const DataTypeMap = {
10
+ 'varchar': 'character varying',
11
+ 'char': 'character',
12
+ 'text': 'text',
13
+ 'decimal': 'numeric',
14
+ 'numeric': 'numeric',
15
+ 'integer': 'integer',
16
+ 'int' : 'integer',
17
+ 'smallint': 'smallint',
18
+ 'bigint': 'bigint',
19
+ 'boolean': 'boolean',
20
+ 'bytea': 'bytea',
21
+ 'jsonb': 'jsonb',
22
+ 'date': 'date',
23
+ 'time': 'time without time zone',
24
+ 'timestamp': 'timestamp without time zone',
25
+ 'timestamptz': 'timestamp with time zone',
26
+ };
27
+
28
+ const Numerics = ['smallint','bigint','integer','decimal','numeric', 'int'];
29
+ const Strings = ['char', 'varchar', 'text'];
30
+ const TypeWithBrackets = ['character varying', 'character', 'decimal', 'numeric'];
31
+ const DefaultWithType = ['varchar', 'char', 'text', 'bytea', 'timestamp', 'timestampz', 'date', 'time'];
32
+
33
+ class SchemaSync {
34
+
35
+ /**
36
+ * 入口方法
37
+ */
38
+ static async execute(sql, def, ctx, options = {}) {
39
+ const debug = options.debug || false;
40
+ const force = options.force || false;
41
+ const dropNotExistCol = options.dropNotExistCol || false;
42
+ const schema = ctx.defaultSchema || 'public';
43
+ const tableName = def.tableName;
44
+ const curTableName = `${schema}.${tableName}`;
45
+
46
+ if (debug) console.log(`检测数据表 ${tableName} 的column...`);
47
+
48
+ // 0. 检查列定义的合法性 (移植自 _checkFixColumn)
49
+ // 简单复刻:NeoPG 的 ModelDef 已经做了一部分,这里补充检查
50
+ for (let k in def.columns) {
51
+ if (k.toLowerCase() !== k) {
52
+ console.warn(`[NeoPG Warning] ${tableName} column ${k} 包含大写,Postgres会转小写,建议代码中改为小写。`);
53
+ }
54
+ }
55
+
56
+ // 1. 获取 Schema OID (用于外键查询)
57
+ let schemaOid = null;
58
+ const nsRes = await sql`SELECT oid FROM pg_namespace WHERE nspname = ${schema}`;
59
+ if (nsRes.length > 0) schemaOid = nsRes[0].oid;
60
+
61
+ // 2. 检查表是否存在
62
+ const tableInfo = await sql`
63
+ SELECT * FROM information_schema.tables
64
+ WHERE table_catalog = ${sql.options.database}
65
+ AND table_schema = ${schema}
66
+ AND table_name = ${tableName}
67
+ `;
68
+
69
+ // A. 表不存在 -> 创建
70
+ if (tableInfo.length === 0) {
71
+ await this.createTable(sql, def, schema, curTableName, debug);
72
+ // 同步索引、约束、外键
73
+ await this.syncIndex(sql, def, schema, curTableName, debug);
74
+ await this.syncUnique(sql, def, schema, curTableName, debug);
75
+ await this.syncReferences(sql, def, schema, curTableName, schemaOid, debug, ctx);
76
+ return;
77
+ }
78
+
79
+ // B. 表存在 -> 增量同步
80
+ // 获取现有列信息
81
+ const cols = await sql`
82
+ SELECT column_name, data_type, column_default, character_maximum_length,
83
+ numeric_precision, numeric_scale, is_nullable
84
+ FROM information_schema.columns
85
+ WHERE table_name = ${tableName}
86
+ AND table_schema = ${schema}
87
+ AND table_catalog = ${sql.options.database}
88
+ `;
89
+
90
+ const inf = {};
91
+ for (const c of cols) inf[c.column_name] = c;
92
+
93
+ // 预处理 rename 逻辑需要
94
+ // 若存在 dropIndex 但是不存在 removeIndex 则指向 dropIndex (原逻辑)
95
+ // NeoPG 中这部分配置可能需要从 def 传递进来,假设 def.rawSchema 包含这些配置
96
+ // 为了简化,我们假设 def 上挂载了 extra 属性用于存储 index/unique 等非 column 配置
97
+
98
+ await this.syncColumn(sql, def, inf, curTableName, debug, force, dropNotExistCol);
99
+ await this.syncIndex(sql, def, schema, curTableName, debug);
100
+ await this.syncUnique(sql, def, schema, curTableName, debug);
101
+ await this.autoRemoveIndex(sql, def, schema, tableName, debug);
102
+ await this.syncReferences(sql, def, schema, curTableName, schemaOid, debug, ctx);
103
+
104
+ if (debug) console.log(` - 表结构同步完成 (${tableName}) - `);
105
+ }
106
+
107
+ // --- 创建表逻辑 ---
108
+ static async createTable(sql, def, schema, curTableName, debug) {
109
+ let colSqls = [];
110
+ const qtag = randstring(12);
111
+
112
+ for (let k in def.columns) {
113
+ const col = def.columns[k];
114
+ if (col.drop || col.ignore) continue;
115
+
116
+ let line = `${this.fmtColName(k)} ${col.type}`;
117
+
118
+ if (k === def.primaryKey) {
119
+ line += ' primary key';
120
+ } else {
121
+ if (col.notNull !== false) line += ' not null';
122
+
123
+ // 自动检测默认值逻辑
124
+ let pt = this._parseType(col.type);
125
+ if (col.default === undefined) {
126
+ if (col.type.includes('[')) col.default = '{}';
127
+ else if (Numerics.includes(pt)) col.default = 0;
128
+ else if (Strings.includes(pt)) col.default = '';
129
+ }
130
+
131
+ if (col.default !== undefined) {
132
+ if (col.default === null) line += ' default null';
133
+ else line += ` default $${qtag}$${col.default}$${qtag}$`;
134
+ }
135
+ }
136
+ colSqls.push(line);
137
+ }
138
+
139
+ // 联合主键
140
+ if (Array.isArray(def.primaryKey)) {
141
+ colSqls.push(`primary key (${def.primaryKey.join(',')})`);
142
+ }
143
+
144
+ const createSql = `CREATE TABLE IF NOT EXISTS ${curTableName} (${colSqls.join(',')})`;
145
+ if (debug) console.log(createSql);
146
+ await sql.unsafe(createSql);
147
+ }
148
+
149
+ // --- 列同步逻辑 (核心复杂逻辑) ---
150
+ static async syncColumn(sql, def, inf, curTableName, debug, force, dropNotExistCol) {
151
+ const qtag = randstring(12);
152
+ let renameTable = {};
153
+
154
+ for (let k in def.columns) {
155
+ const col = def.columns[k];
156
+ if (col.ignore) continue;
157
+
158
+ // 1. Drop Column
159
+ if (col.drop) {
160
+ try {
161
+ await sql.unsafe(`ALTER TABLE ${curTableName} DROP COLUMN IF EXISTS ${this.fmtColName(k)}`);
162
+ } catch (e) {}
163
+ continue;
164
+ }
165
+
166
+ // 2. Rename Check
167
+ if (col.oldName && typeof col.oldName === 'string' && col.oldName.trim()) {
168
+ const oldName = col.oldName.trim();
169
+ if (inf[k] === undefined && inf[oldName]) {
170
+ await sql.unsafe(`ALTER TABLE ${curTableName} RENAME ${this.fmtColName(oldName)} TO ${this.fmtColName(k)}`);
171
+ inf[k] = inf[oldName]; // 更新内存信息
172
+ renameTable[oldName] = true;
173
+ }
174
+ }
175
+
176
+ let pt = this._parseType(col.type);
177
+ let real_type = DataTypeMap[pt] || null;
178
+
179
+ // 3. Add Column
180
+ if (inf[k] === undefined) {
181
+ let addSql = `ALTER TABLE ${curTableName} ADD COLUMN ${this.fmtColName(k)} ${col.type}`;
182
+ if (col.notNull !== false) addSql += ' not null';
183
+
184
+ // 默认值补全
185
+ if (col.default === undefined) {
186
+ if (col.type.includes('[')) col.default = '{}';
187
+ else if (Numerics.includes(pt)) col.default = 0;
188
+ else if (Strings.includes(pt)) col.default = '';
189
+ }
190
+
191
+ if (col.default !== undefined) {
192
+ if (col.default === null) addSql += ' default null';
193
+ else addSql += ` default $${qtag}$${col.default}$${qtag}$`;
194
+ }
195
+
196
+ if (debug) console.log(addSql);
197
+ await sql.unsafe(addSql);
198
+ continue;
199
+ }
200
+
201
+ if (col.typeLock) continue;
202
+ if (real_type === null) continue; // 未知类型跳过
203
+
204
+ // 4. Check Type Change
205
+ if (this._compareType(inf[k], col, real_type) === false) {
206
+ let alterSql = `ALTER TABLE ${curTableName} ALTER COLUMN ${this.fmtColName(k)} TYPE ${col.type}`;
207
+
208
+ // 特殊处理字符串转非字符串的问题
209
+ const isDbString = inf[k].data_type === 'text' || inf[k].data_type.includes('character');
210
+ const isTargetString = Strings.includes(this._parseType(col.type));
211
+
212
+ if (isDbString && !isTargetString) {
213
+ if (col.force) {
214
+ // 强制重建列
215
+ await sql.unsafe(`ALTER TABLE ${curTableName} DROP COLUMN ${this.fmtColName(k)}`);
216
+ let reAddSql = `ALTER TABLE ${curTableName} ADD COLUMN ${this.fmtColName(k)} ${col.type}`;
217
+ if (col.notNull !== false) reAddSql += ' not null';
218
+ if (col.default !== undefined) reAddSql += ` default $${qtag}$${col.default}$${qtag}$`;
219
+ await sql.unsafe(reAddSql);
220
+ col.changed = true; // 标记变更,供外键处理使用
221
+ continue;
222
+ } else {
223
+ console.error(`Error: ${k} 从字符串转向其他类型无转换规则,且未设置force选项。`);
224
+ continue;
225
+ }
226
+ }
227
+
228
+ if (debug) console.log(alterSql);
229
+ try {
230
+ await sql.unsafe(alterSql);
231
+ col.changed = true;
232
+ } catch (err) {
233
+ console.error('Type alter error:', err.message);
234
+ continue;
235
+ }
236
+ }
237
+
238
+ // 5. Check Default Value
239
+ if (col.default !== undefined) {
240
+ // 简单比对逻辑 (注:PG存储的默认值格式可能不同,这里仅作简单触发)
241
+ // 实际生产中可能需要更复杂的解析,这里保留原逻辑结构
242
+ // 原逻辑用了 _realDefault 方法,这里我们简单处理,仅当需要时设置
243
+ let default_val_sql = col.default === null ? 'null' : `$${qtag}$${col.default}$${qtag}$`;
244
+ // 这里为了简化,每次都重设默认值(开销很小),或者你需要实现 _realDefault
245
+ await sql.unsafe(`ALTER TABLE ${curTableName} ALTER COLUMN ${this.fmtColName(k)} SET DEFAULT ${default_val_sql}`);
246
+ }
247
+
248
+ // 6. Check Not Null
249
+ if (col.notNull === undefined || col.notNull) {
250
+ if (inf[k].is_nullable === 'YES') {
251
+ await sql.unsafe(`ALTER TABLE ${curTableName} ALTER COLUMN ${this.fmtColName(k)} SET NOT NULL`);
252
+ }
253
+ } else {
254
+ if (inf[k].is_nullable === 'NO') {
255
+ // 难以恢复为 Nullable,跳过
256
+ }
257
+ }
258
+ }
259
+
260
+ // 7. Drop Not Exist (Force Mode)
261
+ if (dropNotExistCol) {
262
+ for (let k in inf) {
263
+ if (!def.columns[k] && !renameTable[k]) {
264
+ await sql.unsafe(`ALTER TABLE ${curTableName} DROP COLUMN ${this.fmtColName(k)}`);
265
+ }
266
+ }
267
+ }
268
+ }
269
+
270
+ // --- 索引同步 ---
271
+ static async syncIndex(sql, def, schema, curTableName, debug) {
272
+ // 假设索引定义在 def.rawSchema.index (数组)
273
+ // ModelDef 需要暴露这个属性,或 def.indices
274
+ const indices = def.rawSchema && def.rawSchema.index ? def.rawSchema.index : [];
275
+ if (!Array.isArray(indices)) return;
276
+
277
+ for (const indname of indices) {
278
+ // 检查 removeIndex 配置
279
+ const removeIndex = def.rawSchema.removeIndex || [];
280
+ if (removeIndex.includes(indname)) continue;
281
+
282
+ // 检查列是否存在
283
+ if (!this._checkColumnsExist(indname, def)) {
284
+ console.error(`Index ${indname} 包含不存在的列,跳过。`);
285
+ continue;
286
+ }
287
+
288
+ // 检查索引是否存在
289
+ const idxCols = indname.split(',').map(s=>s.trim()).filter(s=>s);
290
+ const idxNamePart = idxCols.join('_');
291
+ const targetIdxName = `${def.tableName}_${idxNamePart}_idx`;
292
+
293
+ // 使用 pg_indexes 查询
294
+ // 注意:pg_indexes 不支持 unsafe 拼 schema,只能查 schemaname 列
295
+ const exist = await sql`
296
+ SELECT * FROM pg_indexes
297
+ WHERE tablename = ${def.tableName}
298
+ AND schemaname = ${schema}
299
+ AND indexname = ${targetIdxName}
300
+ `;
301
+
302
+ if (exist.length > 0) continue;
303
+
304
+ // 创建索引
305
+ // 支持 using gin 等 (这里简化处理,假设无特殊 using)
306
+ // 你的原代码有 indexType 检测,这里简单复刻
307
+ // let ind_using = ...
308
+ await sql.unsafe(`CREATE INDEX ON ${curTableName} (${idxCols.map(c=>this.fmtColName(c)).join(',')})`);
309
+ }
310
+ }
311
+
312
+ static async syncUnique(sql, def, schema, curTableName, debug) {
313
+ const uniques = def.rawSchema && def.rawSchema.unique ? def.rawSchema.unique : [];
314
+ if (!Array.isArray(uniques)) return;
315
+
316
+ for (const indname of uniques) {
317
+ if (!this._checkColumnsExist(indname, def)) continue;
318
+
319
+ const idxCols = indname.split(',').map(s=>s.trim()).filter(s=>s);
320
+ const idxNamePart = idxCols.join('_');
321
+ const targetIdxName = `${def.tableName}_${idxNamePart}_idx`; // Unique 索引命名通常也遵循此规则,或有 _key 后缀,这里假设一致
322
+
323
+ const exist = await sql`
324
+ SELECT * FROM pg_indexes
325
+ WHERE tablename = ${def.tableName}
326
+ AND schemaname = ${schema}
327
+ AND indexname = ${targetIdxName}
328
+ `;
329
+
330
+ if (exist.length > 0) continue;
331
+
332
+ await sql.unsafe(`CREATE UNIQUE INDEX ON ${curTableName} (${idxCols.map(c=>this.fmtColName(c)).join(',')})`);
333
+ }
334
+ }
335
+
336
+ static async autoRemoveIndex(sql, def, schema, tableName, debug) {
337
+ // 1. 获取当前所有索引
338
+ const allIdx = await sql`
339
+ SELECT indexname FROM pg_indexes
340
+ WHERE tablename = ${tableName}
341
+ AND schemaname = ${schema}
342
+ AND indexname != ${tableName + '_pkey'}
343
+ `;
344
+
345
+ if (allIdx.length === 0) return;
346
+
347
+ const currentIdxNames = allIdx.map(i => i.indexname);
348
+
349
+ // 2. 计算应该保留的索引名
350
+ const indices = def.rawSchema && def.rawSchema.index ? def.rawSchema.index : [];
351
+ const uniques = def.rawSchema && def.rawSchema.unique ? def.rawSchema.unique : [];
352
+
353
+ const keepSet = new Set();
354
+ const makeName = (n) => `${tableName}_${n.split(',').map(x=>x.trim()).filter(x=>x).join('_')}_idx`;
355
+
356
+ indices.forEach(n => keepSet.add(makeName(n)));
357
+ uniques.forEach(n => keepSet.add(makeName(n)));
358
+
359
+ // 3. 差集删除
360
+ for (const idxName of currentIdxNames) {
361
+ if (!keepSet.has(idxName)) {
362
+ if (debug) console.log('Auto removing index:', idxName);
363
+ await sql.unsafe(`DROP INDEX ${schema}.${idxName}`);
364
+ }
365
+ }
366
+ }
367
+
368
+ // --- 外键同步 ---
369
+ static async syncReferences(sql, def, schema, curTableName, schemaOid, debug, ctx) {
370
+ // 1. 收集定义中的外键
371
+ // 格式: { fkName: "xxx", createSql: "..." }
372
+ let targetFKs = new Map();
373
+ const qtag = randstring(8);
374
+
375
+ for (let k in def.columns) {
376
+ const col = def.columns[k];
377
+ if (!col.ref) continue;
378
+
379
+ // 解析 ref: "ModelName:colName"
380
+ const [refModelName, refColName] = this._parseRef(col.ref, k);
381
+
382
+ // 加载目标模型 (这里需要通过 ctx (NeoPG实例) 获取其他模型)
383
+ // 假设 ctx.registry.get(refModelName) 能拿到
384
+ // 或者如果是文件路径,尝试 require
385
+
386
+ // 为了简化复刻,这里假设我们能拿到目标表名
387
+ // 在原逻辑中是 require 文件,这里建议 NeoPG 注册机制解决
388
+ // 这里做一个适配:
389
+ let targetTableName = '';
390
+ if (ctx.registry && ctx.registry.get(refModelName)) {
391
+ targetTableName = ctx.registry.get(refModelName).def.tableName;
392
+ } else {
393
+ // 尝试作为表名直接使用 (Fallback)
394
+ targetTableName = refModelName.toLowerCase();
395
+ }
396
+
397
+ // 构建外键名
398
+ const fkName = `${def.tableName}_${k}_fkey`;
399
+
400
+ // 构建 REFERENCES 子句
401
+ let refSql = `REFERENCES ${schema}.${targetTableName} (${refColName})`;
402
+ if (col.refActionUpdate) refSql += ` ON UPDATE ${col.refActionUpdate}`;
403
+ else refSql += ` ON UPDATE CASCADE`; // 默认
404
+
405
+ if (col.refActionDelete) refSql += ` ON DELETE ${col.refActionDelete}`;
406
+ else refSql += ` ON DELETE CASCADE`; // 默认
407
+
408
+ targetFKs.set(fkName, { col: k, sql: refSql, changed: col.changed });
409
+ }
410
+
411
+ // 2. 获取数据库现有外键
412
+ const existFKs = new Set();
413
+ if (targetFKs.size > 0 && schemaOid) {
414
+ // 构建 IN 查询
415
+ const names = Array.from(targetFKs.keys());
416
+ const rows = await sql`
417
+ SELECT conname FROM pg_constraint
418
+ WHERE connamespace = ${schemaOid}
419
+ AND contype = 'f'
420
+ AND conname IN ${sql(names)}
421
+ `;
422
+ rows.forEach(r => existFKs.add(r.conname));
423
+ }
424
+
425
+ // 3. 同步
426
+ for (const [fkName, conf] of targetFKs) {
427
+ // 如果变更了列类型,必须先删后加
428
+ if (existFKs.has(fkName) && conf.changed) {
429
+ await sql.unsafe(`ALTER TABLE ${curTableName} DROP CONSTRAINT ${fkName}`);
430
+ existFKs.delete(fkName);
431
+ }
432
+
433
+ if (!existFKs.has(fkName)) {
434
+ const addSql = `ALTER TABLE ${curTableName} ADD CONSTRAINT ${fkName} FOREIGN KEY (${conf.col}) ${conf.sql}`;
435
+ if (debug) console.log(addSql);
436
+ await sql.unsafe(addSql);
437
+ }
438
+ }
439
+ }
440
+
441
+ // --- 辅助方法 ---
442
+
443
+ static fmtColName(col) {
444
+ // 简单处理引用
445
+ if (forbidColumns.quote.includes(col.toLowerCase())) {
446
+ return `"${col}"`;
447
+ }
448
+
449
+ return `"${col}"`;
450
+ }
451
+
452
+ static _parseType(t) {
453
+ const idx = t.indexOf('(');
454
+ if (idx > 0) return t.substring(0, idx).trim().toLowerCase();
455
+ const idx2 = t.indexOf('[');
456
+ if (idx2 > 0) return t.substring(0, idx2).trim().toLowerCase();
457
+ return t.trim().toLowerCase();
458
+ }
459
+
460
+ static _compareType(f, col, real_type) {
461
+ if (!TypeWithBrackets.includes(real_type)) {
462
+ return f.data_type === real_type;
463
+ }
464
+
465
+ // 括号解析
466
+ // 原逻辑 _parseBrackets
467
+ const idx = col.type.indexOf('(');
468
+ const brackets = idx > 0 ? col.type.substring(idx).trim() : '';
469
+
470
+ if (f.data_type.startsWith('character')) {
471
+ return `${f.data_type}(${f.character_maximum_length})` === `${real_type}${brackets}`;
472
+ }
473
+
474
+ // numeric(p,s)
475
+ if (f.data_type === 'numeric' || f.data_type === 'decimal') {
476
+ // 注意 PG 返回的 precision 可能是 null
477
+ const p = f.numeric_precision;
478
+ const s = f.numeric_scale;
479
+ if (!p) return `${real_type}${brackets}` === real_type; // 无精度对比
480
+ return `${f.data_type}(${p},${s})` === `${real_type}${brackets}`;
481
+ }
482
+
483
+ return false; // Fallback
484
+ }
485
+
486
+ static _checkColumnsExist(colsStr, def) {
487
+ const parts = colsStr.split(',').map(x=>x.trim()).filter(x=>x);
488
+ for (const p of parts) {
489
+ if (!def.columns[p]) return false;
490
+ }
491
+ return true;
492
+ }
493
+
494
+ static _parseRef(refstr, curColumn) {
495
+ if (refstr.includes(':')) {
496
+ const parts = refstr.split(':');
497
+ // 处理 Model:col 格式,取最后一部分做 col,前面做 Model
498
+ const col = parts.pop();
499
+ const model = parts.join(':');
500
+ return [model, col];
501
+ }
502
+ return [refstr, curColumn];
503
+ }
504
+ }
505
+
506
+ module.exports = SchemaSync;
@@ -0,0 +1,29 @@
1
+ 'use strict';
2
+
3
+ class TransactionScope {
4
+ constructor(parent, trxSql) {
5
+ this.parent = parent
6
+ this.driver = trxSql
7
+ this.sql = trxSql
8
+ }
9
+
10
+ table(tableName, schema = null) {
11
+ const target = schema || this.parent.defaultSchema
12
+ return new this.parent.ModelChain(this.driver, {tableName, isRaw: true}, target)
13
+ }
14
+
15
+ model(name, schema = null) {
16
+ const item = this.parent.registry.get(name)
17
+ if (!item) throw new Error(`[NeoPG] Model '${name}' not found.`)
18
+ const target = schema || this.parent.defaultSchema
19
+ return new item.Class(this.driver, item.def, target)
20
+ }
21
+
22
+ async transaction(callback) {
23
+ return await this.driver.begin(async (sp) => {
24
+ return await callback(new TransactionScope(this.parent, sp))
25
+ })
26
+ }
27
+ }
28
+
29
+ module.exports = TransactionScope
@@ -0,0 +1,60 @@
1
+ 'use strict'
2
+
3
+ let types = {
4
+ STRING: (len=200) => {
5
+ if (typeof len !== 'number' || len <= 0) { len = 200 }
6
+ return `varchar(${len})`
7
+ },
8
+
9
+ NUMBER: (l, p=2) => {
10
+ if (typeof l === 'number' && typeof p === 'number') {
11
+ return `numeric(${l},${p})`
12
+ }
13
+
14
+ return `numeric(11,2)`
15
+ },
16
+
17
+ CHAR: (len=100) => {
18
+ if (typeof len !== 'number' || len <= 0) { len = 100 }
19
+ return `char(${len})`
20
+ },
21
+
22
+ ARRAY: (t) => {
23
+ return `${t}[]`
24
+ },
25
+
26
+ TEXT: 'text',
27
+ INT: 'int',
28
+ BIGINT: 'bigint',
29
+ BigInt: 'bigint',
30
+ TIMESTAMP: 'timestamp',
31
+ TIMESTAMPZ: 'timestamp with time zone',
32
+ TIME: 'time',
33
+ DATE: 'date',
34
+ SMALLINT: 'smallint',
35
+ BOOLEAN: 'boolean',
36
+ BOOL: 'boolean',
37
+ BYTE: 'bytea',
38
+ BINARY: 'bytea',
39
+ BLOB: 'bytea',
40
+ JSONB: 'jsonb',
41
+ ID: 'varchar(16)',
42
+ OPENID: 'varchar(32)',
43
+ UID: 'varchar(18)',
44
+ BID: 'bigint',
45
+ SERIAL: 'serial',
46
+ BIGSERIAL: 'bigserial',
47
+ BigSerial: 'bigserial',
48
+ }
49
+
50
+ types.DECIMAL = types.NUMBER
51
+ types.NUMERIC = types.NUMBER
52
+
53
+ for (let k in types) {
54
+ let lk = k.toLowerCase()
55
+ if (!types[lk]) {
56
+ types[lk] = types[k]
57
+ }
58
+ }
59
+
60
+ module.exports = types
@@ -0,0 +1,29 @@
1
+ 'use strict'
2
+
3
+ module.exports = {
4
+ quote: [
5
+ "select", "from", "where", "group", "order",
6
+ "having", "join", "left", "right",
7
+ "inner", "outer", "full", "between",
8
+ "case", "when", "then", "end", "to",
9
+ "union", "all", "limit", "offset", "desc",
10
+ "type", "like", "ilike",
11
+
12
+ "insert", "update", "delete", "into",
13
+ "set", "add", "alter", "column", "table",
14
+ "default", "check", "unique", "primary", "foreign",
15
+ "key", "index", "constraint", "using",
16
+
17
+ "user", "session", "trigger", "view", "schema",
18
+
19
+ "over", "window", "range", "fetch",
20
+ "only", "cascade", "references",
21
+ "grant", "revoke", "return", "call",
22
+
23
+ "current_user", "session_user",
24
+ ],
25
+
26
+ forbid: [
27
+ "null", "not", "and", "or", "asc", "else", "by", "on", "if",
28
+ ]
29
+ }