dbgate-datalib 5.5.7-alpha.16 → 5.5.7-alpha.26

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.
@@ -9,6 +9,7 @@ export interface DataDuplicatorItem {
9
9
  export interface DataDuplicatorOptions {
10
10
  rollbackAfterFinish?: boolean;
11
11
  skipRowsWithUnresolvedRefs?: boolean;
12
+ setNullForUnresolvedNullableRefs?: boolean;
12
13
  }
13
14
  declare class DuplicatorReference {
14
15
  base: DuplicatorItemHolder;
@@ -18,11 +19,19 @@ declare class DuplicatorReference {
18
19
  constructor(base: DuplicatorItemHolder, ref: DuplicatorItemHolder, isMandatory: boolean, foreignKey: ForeignKeyInfo);
19
20
  get columnName(): string;
20
21
  }
22
+ declare class DuplicatorWeakReference {
23
+ base: DuplicatorItemHolder;
24
+ ref: TableInfo;
25
+ foreignKey: ForeignKeyInfo;
26
+ constructor(base: DuplicatorItemHolder, ref: TableInfo, foreignKey: ForeignKeyInfo);
27
+ get columnName(): string;
28
+ }
21
29
  declare class DuplicatorItemHolder {
22
30
  item: DataDuplicatorItem;
23
31
  duplicator: DataDuplicator;
24
32
  references: DuplicatorReference[];
25
33
  backReferences: DuplicatorReference[];
34
+ weakReferences: DuplicatorWeakReference[];
26
35
  table: TableInfo;
27
36
  isPlanned: boolean;
28
37
  idMap: {};
@@ -34,7 +43,8 @@ declare class DuplicatorItemHolder {
34
43
  get name(): string;
35
44
  constructor(item: DataDuplicatorItem, duplicator: DataDuplicator);
36
45
  initializeReferences(): void;
37
- createInsertObject(chunk: any): import("lodash").Omit<Pick<any, string>, string>;
46
+ createInsertObject(chunk: any, weakrefcols: string[]): import("lodash").Omit<Pick<any, string>, string>;
47
+ getMissingWeakRefsForRow(row: any): Promise<string[]>;
38
48
  runImport(): Promise<{
39
49
  inserted: number;
40
50
  mapped: number;
@@ -28,6 +28,16 @@ class DuplicatorReference {
28
28
  return this.foreignKey.columns[0].columnName;
29
29
  }
30
30
  }
31
+ class DuplicatorWeakReference {
32
+ constructor(base, ref, foreignKey) {
33
+ this.base = base;
34
+ this.ref = ref;
35
+ this.foreignKey = foreignKey;
36
+ }
37
+ get columnName() {
38
+ return this.foreignKey.columns[0].columnName;
39
+ }
40
+ }
31
41
  class DuplicatorItemHolder {
32
42
  get name() {
33
43
  return this.item.name;
@@ -38,6 +48,8 @@ class DuplicatorItemHolder {
38
48
  this.duplicator = duplicator;
39
49
  this.references = [];
40
50
  this.backReferences = [];
51
+ // not mandatory references to entities out of the model
52
+ this.weakReferences = [];
41
53
  this.isPlanned = false;
42
54
  this.idMap = {};
43
55
  this.refByColumn = {};
@@ -54,17 +66,23 @@ class DuplicatorItemHolder {
54
66
  if (((_a = fk.columns) === null || _a === void 0 ? void 0 : _a.length) != 1)
55
67
  continue;
56
68
  const refHolder = this.duplicator.itemHolders.find(y => y.name.toUpperCase() == fk.refTableName.toUpperCase());
57
- if (refHolder == null)
58
- continue;
59
69
  const isMandatory = (_b = this.table.columns.find(x => { var _a; return x.columnName == ((_a = fk.columns[0]) === null || _a === void 0 ? void 0 : _a.columnName); })) === null || _b === void 0 ? void 0 : _b.notNull;
60
- const newref = new DuplicatorReference(this, refHolder, isMandatory, fk);
61
- this.references.push(newref);
62
- this.refByColumn[newref.columnName] = newref;
63
- refHolder.isReferenced = true;
70
+ if (refHolder == null) {
71
+ if (!isMandatory) {
72
+ const weakref = new DuplicatorWeakReference(this, this.duplicator.db.tables.find(x => x.pureName == fk.refTableName), fk);
73
+ this.weakReferences.push(weakref);
74
+ }
75
+ }
76
+ else {
77
+ const newref = new DuplicatorReference(this, refHolder, isMandatory, fk);
78
+ this.references.push(newref);
79
+ this.refByColumn[newref.columnName] = newref;
80
+ refHolder.isReferenced = true;
81
+ }
64
82
  }
65
83
  }
66
- createInsertObject(chunk) {
67
- const res = (0, omit_1.default)((0, pick_1.default)(chunk, this.table.columns.map(x => x.columnName)), [this.autoColumn, ...this.backReferences.map(x => x.columnName)]);
84
+ createInsertObject(chunk, weakrefcols) {
85
+ const res = (0, omit_1.default)((0, pick_1.default)(chunk, this.table.columns.map(x => x.columnName)), [this.autoColumn, ...this.backReferences.map(x => x.columnName), ...weakrefcols]);
68
86
  for (const key in res) {
69
87
  const ref = this.refByColumn[key];
70
88
  if (ref) {
@@ -81,6 +99,23 @@ class DuplicatorItemHolder {
81
99
  }
82
100
  return res;
83
101
  }
102
+ // returns list of columns that are weak references and are not resolved
103
+ getMissingWeakRefsForRow(row) {
104
+ var _a;
105
+ return __awaiter(this, void 0, void 0, function* () {
106
+ if (!this.duplicator.options.setNullForUnresolvedNullableRefs || !((_a = this.weakReferences) === null || _a === void 0 ? void 0 : _a.length)) {
107
+ return [];
108
+ }
109
+ const qres = yield (0, dbgate_tools_1.runQueryOnDriver)(this.duplicator.pool, this.duplicator.driver, dmp => {
110
+ dmp.put('^select ');
111
+ dmp.putCollection(',', this.weakReferences, weakref => {
112
+ dmp.put('(^case ^when ^exists (^select * ^from %f where %i = %v) ^then 1 ^else 0 ^end) as %i', weakref.ref, weakref.foreignKey.columns[0].refColumnName, row[weakref.foreignKey.columns[0].columnName], weakref.foreignKey.columns[0].columnName);
113
+ });
114
+ });
115
+ const qrow = qres.rows[0];
116
+ return this.weakReferences.filter(x => qrow[x.columnName] == 0).map(x => x.columnName);
117
+ });
118
+ }
84
119
  runImport() {
85
120
  return __awaiter(this, void 0, void 0, function* () {
86
121
  const readStream = yield this.item.openStream();
@@ -91,6 +126,7 @@ class DuplicatorItemHolder {
91
126
  let missing = 0;
92
127
  let skipped = 0;
93
128
  let lastLogged = new Date();
129
+ const existingWeakRefs = {};
94
130
  const writeStream = (0, dbgate_tools_1.createAsyncWriteStream)(this.duplicator.stream, {
95
131
  processItem: (chunk) => __awaiter(this, void 0, void 0, function* () {
96
132
  var _a, _b, _c;
@@ -100,7 +136,8 @@ class DuplicatorItemHolder {
100
136
  const doCopy = () => __awaiter(this, void 0, void 0, function* () {
101
137
  var _d, _e, _f;
102
138
  // console.log('chunk', this.name, JSON.stringify(chunk));
103
- const insertedObj = this.createInsertObject(chunk);
139
+ const weakrefcols = yield this.getMissingWeakRefsForRow(chunk);
140
+ const insertedObj = this.createInsertObject(chunk, weakrefcols);
104
141
  // console.log('insertedObj', this.name, JSON.stringify(insertedObj));
105
142
  if (insertedObj == null) {
106
143
  skipped += 1;
@@ -34,7 +34,6 @@ export declare class FreeTableGridDisplay extends GridDisplay {
34
34
  undropColumnName?: string;
35
35
  contentHash?: string;
36
36
  engine?: string;
37
- undropPureName?: string;
38
37
  }[];
39
38
  getDisplayColumn(col: ColumnInfo): {
40
39
  pureName: string;
@@ -64,6 +63,5 @@ export declare class FreeTableGridDisplay extends GridDisplay {
64
63
  undropColumnName?: string;
65
64
  contentHash?: string;
66
65
  engine?: string;
67
- undropPureName?: string;
68
66
  };
69
67
  }
@@ -0,0 +1,32 @@
1
+ import { DatabaseModelFile } from 'dbgate-tools';
2
+ import { EngineDriver } from 'dbgate-types';
3
+ interface DeployScriptJournalItem {
4
+ id: number;
5
+ name: string;
6
+ category: string;
7
+ first_run_date: string;
8
+ last_run_date: string;
9
+ script_hash: string;
10
+ }
11
+ export declare class ScriptDrivedDeployer {
12
+ dbhan: any;
13
+ driver: EngineDriver;
14
+ files: DatabaseModelFile[];
15
+ predeploy: DatabaseModelFile[];
16
+ uninstall: DatabaseModelFile[];
17
+ install: DatabaseModelFile[];
18
+ once: DatabaseModelFile[];
19
+ postdeploy: DatabaseModelFile[];
20
+ isEmpty: boolean;
21
+ journalItems: DeployScriptJournalItem[];
22
+ constructor(dbhan: any, driver: EngineDriver, files: DatabaseModelFile[]);
23
+ loadJournalItems(): Promise<void>;
24
+ runPre(): Promise<void>;
25
+ runPost(): Promise<void>;
26
+ run(): Promise<void>;
27
+ runFiles(files: DatabaseModelFile[], category: string): Promise<void>;
28
+ saveToJournal(file: DatabaseModelFile, category: string, hash: string): Promise<void>;
29
+ runFileCore(file: DatabaseModelFile, category: string, hash: string): Promise<void>;
30
+ runFile(file: DatabaseModelFile, category: string): Promise<void>;
31
+ }
32
+ export {};
@@ -0,0 +1,171 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.ScriptDrivedDeployer = void 0;
16
+ const dbgate_tools_1 = require("dbgate-tools");
17
+ const crypto_1 = __importDefault(require("crypto"));
18
+ const sortBy_1 = __importDefault(require("lodash/sortBy"));
19
+ const logger = (0, dbgate_tools_1.getLogger)('ScriptDrivedDeployer');
20
+ class ScriptDrivedDeployer {
21
+ constructor(dbhan, driver, files) {
22
+ this.dbhan = dbhan;
23
+ this.driver = driver;
24
+ this.files = files;
25
+ this.predeploy = [];
26
+ this.uninstall = [];
27
+ this.install = [];
28
+ this.once = [];
29
+ this.postdeploy = [];
30
+ this.isEmpty = false;
31
+ this.journalItems = [];
32
+ this.predeploy = files.filter(x => x.name.endsWith('.predeploy.sql'));
33
+ this.uninstall = files.filter(x => x.name.endsWith('.uninstall.sql'));
34
+ this.install = files.filter(x => x.name.endsWith('.install.sql'));
35
+ this.once = files.filter(x => x.name.endsWith('.once.sql'));
36
+ this.postdeploy = files.filter(x => x.name.endsWith('.postdeploy.sql'));
37
+ this.isEmpty =
38
+ this.predeploy.length === 0 &&
39
+ this.uninstall.length === 0 &&
40
+ this.install.length === 0 &&
41
+ this.once.length === 0 &&
42
+ this.postdeploy.length === 0;
43
+ }
44
+ loadJournalItems() {
45
+ return __awaiter(this, void 0, void 0, function* () {
46
+ try {
47
+ const { rows } = yield (0, dbgate_tools_1.runQueryOnDriver)(this.dbhan, this.driver, dmp => dmp.put('select * from ~dbgate_deploy_journal'));
48
+ this.journalItems = rows;
49
+ logger.debug(`Loaded ${rows.length} items from DbGate deploy journal`);
50
+ }
51
+ catch (err) {
52
+ logger.warn((0, dbgate_tools_1.extractErrorLogData)(err), 'Error loading DbGate deploy journal, creating table dbgate_deploy_journal');
53
+ const dmp = this.driver.createDumper();
54
+ dmp.createTable({
55
+ pureName: 'dbgate_deploy_journal',
56
+ columns: [
57
+ { columnName: 'id', dataType: 'int', autoIncrement: true, notNull: true, pureName: 'dbgate_deploy_journal' },
58
+ { columnName: 'name', dataType: 'varchar(100)', notNull: true, pureName: 'dbgate_deploy_journal' },
59
+ { columnName: 'category', dataType: 'varchar(100)', notNull: true, pureName: 'dbgate_deploy_journal' },
60
+ { columnName: 'script_hash', dataType: 'varchar(100)', notNull: true, pureName: 'dbgate_deploy_journal' },
61
+ { columnName: 'first_run_date', dataType: 'varchar(100)', notNull: true, pureName: 'dbgate_deploy_journal' },
62
+ { columnName: 'last_run_date', dataType: 'varchar(100)', notNull: true, pureName: 'dbgate_deploy_journal' },
63
+ { columnName: 'run_count', dataType: 'int', notNull: true, pureName: 'dbgate_deploy_journal' },
64
+ ],
65
+ foreignKeys: [],
66
+ primaryKey: {
67
+ columns: [{ columnName: 'id' }],
68
+ constraintType: 'primaryKey',
69
+ pureName: 'dbgate_deploy_journal',
70
+ },
71
+ });
72
+ yield this.driver.query(this.dbhan, dmp.s, { discardResult: true });
73
+ }
74
+ });
75
+ }
76
+ runPre() {
77
+ return __awaiter(this, void 0, void 0, function* () {
78
+ // don't create journal table if no scripts are present
79
+ if (this.isEmpty)
80
+ return;
81
+ yield this.loadJournalItems();
82
+ yield this.runFiles(this.predeploy, 'predeploy');
83
+ });
84
+ }
85
+ runPost() {
86
+ return __awaiter(this, void 0, void 0, function* () {
87
+ yield this.runFiles(this.install, 'install');
88
+ yield this.runFiles(this.once, 'once');
89
+ yield this.runFiles(this.postdeploy, 'postdeploy');
90
+ });
91
+ }
92
+ run() {
93
+ return __awaiter(this, void 0, void 0, function* () {
94
+ yield this.runPre();
95
+ yield this.runPost();
96
+ });
97
+ }
98
+ runFiles(files, category) {
99
+ return __awaiter(this, void 0, void 0, function* () {
100
+ for (const file of (0, sortBy_1.default)(files, x => x.name)) {
101
+ yield this.runFile(file, category);
102
+ }
103
+ });
104
+ }
105
+ saveToJournal(file, category, hash) {
106
+ return __awaiter(this, void 0, void 0, function* () {
107
+ const existing = this.journalItems.find(x => x.name == file.name);
108
+ if (existing) {
109
+ yield (0, dbgate_tools_1.runCommandOnDriver)(this.dbhan, this.driver, dmp => {
110
+ dmp.put('update ~dbgate_deploy_journal set ~last_run_date = %v, ~script_hash = %v, ~run_count = ~run_count + 1 where ~id = %v', new Date().toISOString(), hash, existing.id);
111
+ });
112
+ }
113
+ else {
114
+ yield (0, dbgate_tools_1.runCommandOnDriver)(this.dbhan, this.driver, dmp => {
115
+ dmp.put('insert into ~dbgate_deploy_journal (~name, ~category, ~first_run_date, ~last_run_date, ~script_hash, ~run_count) values (%v, %v, %v, %v, %v, 1)', file.name, category, new Date().toISOString(), new Date().toISOString(), hash);
116
+ });
117
+ }
118
+ });
119
+ }
120
+ runFileCore(file, category, hash) {
121
+ return __awaiter(this, void 0, void 0, function* () {
122
+ if (this.driver.supportsTransactions) {
123
+ (0, dbgate_tools_1.runCommandOnDriver)(this.dbhan, this.driver, dmp => dmp.beginTransaction());
124
+ }
125
+ logger.debug(`Running ${category} script ${file.name}`);
126
+ try {
127
+ yield this.driver.script(this.dbhan, file.text);
128
+ yield this.saveToJournal(file, category, hash);
129
+ }
130
+ catch (err) {
131
+ logger.error((0, dbgate_tools_1.extractErrorLogData)(err), `Error running ${category} script ${file.name}`);
132
+ if (this.driver.supportsTransactions) {
133
+ (0, dbgate_tools_1.runCommandOnDriver)(this.dbhan, this.driver, dmp => dmp.rollbackTransaction());
134
+ return;
135
+ }
136
+ }
137
+ if (this.driver.supportsTransactions) {
138
+ (0, dbgate_tools_1.runCommandOnDriver)(this.dbhan, this.driver, dmp => dmp.commitTransaction());
139
+ }
140
+ });
141
+ }
142
+ runFile(file, category) {
143
+ return __awaiter(this, void 0, void 0, function* () {
144
+ const hash = crypto_1.default.createHash('md5').update(file.text.trim()).digest('hex');
145
+ const journalItem = this.journalItems.find(x => x.name == file.name);
146
+ const isEqual = journalItem && journalItem.script_hash == hash;
147
+ switch (category) {
148
+ case 'predeploy':
149
+ case 'postdeploy':
150
+ yield this.runFileCore(file, category, hash);
151
+ break;
152
+ case 'once':
153
+ if (journalItem)
154
+ return;
155
+ yield this.runFileCore(file, category, hash);
156
+ break;
157
+ case 'install':
158
+ if (isEqual)
159
+ return;
160
+ const uninstallFile = this.uninstall.find(x => x.name == file.name.replace('.install.sql', '.uninstall.sql'));
161
+ if (uninstallFile && journalItem) {
162
+ // file was previously installed, uninstall first
163
+ yield this.runFileCore(uninstallFile, 'uninstall', crypto_1.default.createHash('md5').update(uninstallFile.text.trim()).digest('hex'));
164
+ }
165
+ yield this.runFileCore(file, category, hash);
166
+ break;
167
+ }
168
+ });
169
+ }
170
+ }
171
+ exports.ScriptDrivedDeployer = ScriptDrivedDeployer;
@@ -56,7 +56,6 @@ export declare class TableGridDisplay extends GridDisplay {
56
56
  undropColumnName?: string;
57
57
  contentHash?: string;
58
58
  engine?: string;
59
- undropPureName?: string;
60
59
  }[];
61
60
  addJoinsFromExpandedColumns(select: Select, columns: DisplayColumn[], parentAlias: string, columnSources: any): void;
62
61
  addReferenceToSelect(select: Select, parentAlias: string, column: DisplayColumn): void;
@@ -99,7 +98,6 @@ export declare class TableGridDisplay extends GridDisplay {
99
98
  undropColumnName?: string;
100
99
  contentHash?: string;
101
100
  engine?: string;
102
- undropPureName?: string;
103
101
  };
104
102
  addAddedColumnsToSelect(select: Select, columns: DisplayColumn[], parentAlias: string, displayedColumnInfo: DisplayedColumnInfo): void;
105
103
  get hasReferences(): boolean;
@@ -33,7 +33,6 @@ export declare class ViewGridDisplay extends GridDisplay {
33
33
  undropColumnName?: string;
34
34
  contentHash?: string;
35
35
  engine?: string;
36
- undropPureName?: string;
37
36
  }[];
38
37
  getDisplayColumn(view: ViewInfo, col: ColumnInfo): {
39
38
  pureName: string;
@@ -63,7 +62,6 @@ export declare class ViewGridDisplay extends GridDisplay {
63
62
  undropColumnName?: string;
64
63
  contentHash?: string;
65
64
  engine?: string;
66
- undropPureName?: string;
67
65
  };
68
66
  createSelect(options?: {}): import("dbgate-sqltree").Select;
69
67
  }
package/lib/index.d.ts CHANGED
@@ -22,3 +22,4 @@ export * from './DataDuplicator';
22
22
  export * from './FreeTableGridDisplay';
23
23
  export * from './FreeTableModel';
24
24
  export * from './CustomGridDisplay';
25
+ export * from './ScriptDrivedDeployer';
package/lib/index.js CHANGED
@@ -38,3 +38,4 @@ __exportStar(require("./DataDuplicator"), exports);
38
38
  __exportStar(require("./FreeTableGridDisplay"), exports);
39
39
  __exportStar(require("./FreeTableModel"), exports);
40
40
  __exportStar(require("./CustomGridDisplay"), exports);
41
+ __exportStar(require("./ScriptDrivedDeployer"), exports);
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "5.5.7-alpha.16",
2
+ "version": "5.5.7-alpha.26",
3
3
  "name": "dbgate-datalib",
4
4
  "main": "lib/index.js",
5
5
  "typings": "lib/index.d.ts",
@@ -13,13 +13,13 @@
13
13
  "lib"
14
14
  ],
15
15
  "dependencies": {
16
- "dbgate-sqltree": "^5.5.7-alpha.16",
17
- "dbgate-tools": "^5.5.7-alpha.16",
18
- "dbgate-filterparser": "^5.5.7-alpha.16",
16
+ "dbgate-sqltree": "^5.5.7-alpha.26",
17
+ "dbgate-tools": "^5.5.7-alpha.26",
18
+ "dbgate-filterparser": "^5.5.7-alpha.26",
19
19
  "uuid": "^3.4.0"
20
20
  },
21
21
  "devDependencies": {
22
- "dbgate-types": "^5.5.7-alpha.16",
22
+ "dbgate-types": "^5.5.7-alpha.26",
23
23
  "@types/node": "^13.7.0",
24
24
  "jest": "^28.1.3",
25
25
  "ts-jest": "^28.0.7",