@prisma-psm/pg 1.0.44 → 1.0.47
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
|
@@ -7,11 +7,6 @@ export interface RestoreOptions {
|
|
|
7
7
|
parser: PostgresParserOptions;
|
|
8
8
|
}
|
|
9
9
|
export declare function lockTable(opts: RestoreOptions): string[];
|
|
10
|
-
export interface RestoreOptions {
|
|
11
|
-
source: string;
|
|
12
|
-
model: ModelOptions;
|
|
13
|
-
parser: PostgresParserOptions;
|
|
14
|
-
}
|
|
15
10
|
export declare function restoreBackupSQL(opts: RestoreOptions): {
|
|
16
11
|
data: string[];
|
|
17
12
|
registry: string[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["engine.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["engine.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAG7D,OAAO,EAAE,qBAAqB,EAAE,MAAM,QAAQ,CAAC;AAK/C,wBAAgB,2BAA2B,CAAC,IAAI,EAAE,qBAAqB,YAuCtE;AAED,MAAM,WAAW,cAAc;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,YAAY,CAAC;IACpB,MAAM,EAAE,qBAAqB,CAAC;CACjC;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,cAAc,YAyB7C;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,cAAc,GAAG;IACpD,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,QAAQ,EAAE,MAAM,EAAE,CAAC;CACtB,CAkLA;AAED,MAAM,WAAW,oBAAqB,SAAQ,cAAc;IACxD,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,CAAC,EAAE,MAAM,CAAC;CAChB;AACD,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,oBAAoB,YAqB1D"}
|
|
@@ -43,17 +43,32 @@ function createFunctionRestoreSerial(opts) {
|
|
|
43
43
|
end if;
|
|
44
44
|
return next;
|
|
45
45
|
end;
|
|
46
|
-
|
|
46
|
+
$$;`,
|
|
47
47
|
], tab);
|
|
48
48
|
}
|
|
49
49
|
function lockTable(opts) {
|
|
50
50
|
const schema = (0, escape_1.oid)(opts.model.schema);
|
|
51
51
|
const source = (0, escape_1.oid)(opts.source);
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
52
|
+
const modelName = opts.model.model;
|
|
53
|
+
const sSchema = (0, escape_1.lit)(opts.model.schema);
|
|
54
|
+
const sSource = (0, escape_1.lit)(opts.source);
|
|
55
|
+
const sql = `
|
|
56
|
+
DO $$
|
|
57
|
+
BEGIN
|
|
58
|
+
IF EXISTS (
|
|
59
|
+
SELECT 1
|
|
60
|
+
FROM pg_catalog.pg_class c
|
|
61
|
+
JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
|
|
62
|
+
WHERE n.nspname = ${sSchema}
|
|
63
|
+
AND c.relname = ${sSource}
|
|
64
|
+
) THEN
|
|
65
|
+
LOCK TABLE ${schema}.${source} IN SHARE MODE;
|
|
66
|
+
RAISE NOTICE 'LOCK TABLE FOR SHARE MODE TO MODEL ${modelName} [OK]';
|
|
67
|
+
ELSE
|
|
68
|
+
RAISE NOTICE 'TABLE ${schema}.${source} NOT FOUND, SKIPPING LOCK';
|
|
69
|
+
END IF;
|
|
70
|
+
END $$;`.trim();
|
|
71
|
+
return [(0, notice_1.notice)(`PREPARING LOCK FOR MODEL ${modelName}`), sql];
|
|
57
72
|
}
|
|
58
73
|
function restoreBackupSQL(opts) {
|
|
59
74
|
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6, _7;
|
|
@@ -64,25 +79,41 @@ function restoreBackupSQL(opts) {
|
|
|
64
79
|
const temp = (0, escape_1.oid)(opts.model.temp);
|
|
65
80
|
if ((_b = (_a = opts.model.psm) === null || _a === void 0 ? void 0 : _a.backup) === null || _b === void 0 ? void 0 : _b.skip)
|
|
66
81
|
return null;
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
const columns =
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
.
|
|
79
|
-
|
|
82
|
+
// Filtra campos escalares não gerados (serão restaurados)
|
|
83
|
+
const filter = (field) => !field.isGenerated && field.kind === "scalar";
|
|
84
|
+
const fields = opts.model.fields.filter(filter);
|
|
85
|
+
// Lista de colunas para o INSERT (na mesma ordem dos campos)
|
|
86
|
+
const columns = fields.map((f) => ` ${(0, escape_1.oid)(f.name)}`).join(", ");
|
|
87
|
+
// Constrói a lista de expressões SELECT com COALESCE para cada campo
|
|
88
|
+
const selectExpressions = fields
|
|
89
|
+
.map((field) => {
|
|
90
|
+
const colName = (0, escape_1.oid)(field.dbName || field.name);
|
|
91
|
+
// Obtém a expressão default da coluna, se houver; caso contrário, usa NULL
|
|
92
|
+
// Nota: assumindo que field.default contém a expressão SQL do default
|
|
93
|
+
const defaultValue = field.default !== undefined ? field.default : "NULL";
|
|
94
|
+
// Gera: COALESCE(s."colName", defaultExpression) AS "colName"
|
|
95
|
+
return `COALESCE(s.${colName}, ${defaultValue}) AS ${colName}`;
|
|
80
96
|
})
|
|
97
|
+
.join(",\n");
|
|
98
|
+
// Nova DEFAULT_QUERY com CTE e COALESCE para cada coluna
|
|
99
|
+
const DEFAULT_QUERY = `
|
|
100
|
+
WITH __source AS (
|
|
101
|
+
SELECT (jsonb_populate_record(null::${shadow}.${temp}, to_jsonb(_t))).*
|
|
102
|
+
FROM ${schema}.${source} _t
|
|
103
|
+
)
|
|
104
|
+
SELECT
|
|
105
|
+
${selectExpressions}
|
|
106
|
+
FROM __source s
|
|
107
|
+
`;
|
|
108
|
+
const DEFAULT_SOURCE_CHECKER = `select 1 from pg_catalog.pg_tables t where t.tablename = ${(0, escape_1.lit)(opts.model.name)} and t.schemaname = ${(0, escape_1.lit)(opts.model.schema)}`;
|
|
109
|
+
const DEFAULT_WHEN = `true`;
|
|
110
|
+
const DEFAULT_RESOLVER = fields
|
|
111
|
+
.map((f) => ` ${(0, escape_1.oid)(f.dbName || f.name)}`)
|
|
81
112
|
.join(", ");
|
|
82
113
|
let source_exists = DEFAULT_SOURCE_CHECKER;
|
|
83
114
|
let when = DEFAULT_WHEN;
|
|
84
|
-
const revision_resolver =
|
|
85
|
-
.map(field => {
|
|
115
|
+
const revision_resolver = fields
|
|
116
|
+
.map((field) => {
|
|
86
117
|
var _a, _b;
|
|
87
118
|
let expression = (_b = (_a = field.psm) === null || _a === void 0 ? void 0 : _a.restore) === null || _b === void 0 ? void 0 : _b.expression;
|
|
88
119
|
if (!expression)
|
|
@@ -93,29 +124,36 @@ function restoreBackupSQL(opts) {
|
|
|
93
124
|
let revision_query = DEFAULT_QUERY;
|
|
94
125
|
const expression = (_e = (_d = (_c = opts.model.psm) === null || _c === void 0 ? void 0 : _c.backup) === null || _d === void 0 ? void 0 : _d.rev) === null || _e === void 0 ? void 0 : _e.expression;
|
|
95
126
|
const exists = (_h = (_g = (_f = opts.model.psm) === null || _f === void 0 ? void 0 : _f.backup) === null || _g === void 0 ? void 0 : _g.rev) === null || _h === void 0 ? void 0 : _h.exists;
|
|
96
|
-
if (
|
|
127
|
+
if (exists === null || exists === void 0 ? void 0 : exists.length) {
|
|
97
128
|
source_exists = exists;
|
|
98
129
|
}
|
|
99
|
-
if (((_l = (_k = (_j = opts.model.psm) === null || _j === void 0 ? void 0 : _j.backup) === null || _k === void 0 ? void 0 : _k.rev) === null || _l === void 0 ? void 0 : _l.from) === "query"
|
|
100
|
-
|
|
130
|
+
if (((_l = (_k = (_j = opts.model.psm) === null || _j === void 0 ? void 0 : _j.backup) === null || _k === void 0 ? void 0 : _k.rev) === null || _l === void 0 ? void 0 : _l.from) === "query" &&
|
|
131
|
+
expression) {
|
|
101
132
|
revision_query = expression;
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
&&
|
|
133
|
+
}
|
|
134
|
+
else if (((_p = (_o = (_m = opts.model.psm) === null || _m === void 0 ? void 0 : _m.backup) === null || _o === void 0 ? void 0 : _o.rev) === null || _p === void 0 ? void 0 : _p.from) === "query:linked" &&
|
|
135
|
+
expression &&
|
|
136
|
+
((_r = (_q = opts.model.psm) === null || _q === void 0 ? void 0 : _q.query) === null || _r === void 0 ? void 0 : _r[expression])) {
|
|
105
137
|
revision_query = (_t = (_s = opts.model.psm) === null || _s === void 0 ? void 0 : _s.query) === null || _t === void 0 ? void 0 : _t[expression];
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
138
|
+
}
|
|
139
|
+
else if (((_w = (_v = (_u = opts.model.psm) === null || _u === void 0 ? void 0 : _u.backup) === null || _v === void 0 ? void 0 : _v.rev) === null || _w === void 0 ? void 0 : _w.from) === "model" &&
|
|
140
|
+
expression) {
|
|
141
|
+
const model = opts.parser.models.find((m) => m.model === expression);
|
|
142
|
+
if (model) {
|
|
109
143
|
revision_query = `select * from ${(0, escape_1.oid)(model.schema || "public")}.${(0, escape_1.oid)(model.dbName || model.name)}`;
|
|
144
|
+
}
|
|
110
145
|
}
|
|
111
146
|
const sys = (0, escape_1.oid)(opts.parser.sys);
|
|
112
147
|
let revision = "null";
|
|
113
148
|
const relation = `${schema}.${table}`;
|
|
114
|
-
if ((_z = (_y = (_x = opts.model.psm) === null || _x === void 0 ? void 0 : _x.backup) === null || _y === void 0 ? void 0 : _y.rev) === null || _z === void 0 ? void 0 : _z.version)
|
|
149
|
+
if ((_z = (_y = (_x = opts.model.psm) === null || _x === void 0 ? void 0 : _x.backup) === null || _y === void 0 ? void 0 : _y.rev) === null || _z === void 0 ? void 0 : _z.version) {
|
|
115
150
|
revision = (0, escape_1.lit)((_1 = (_0 = opts.model.psm) === null || _0 === void 0 ? void 0 : _0.backup) === null || _1 === void 0 ? void 0 : _1.rev.version);
|
|
151
|
+
}
|
|
116
152
|
let always_query = DEFAULT_QUERY;
|
|
117
153
|
let always_resolver = DEFAULT_RESOLVER;
|
|
118
|
-
if (((_4 = (_3 = (_2 = opts.model.psm) === null || _2 === void 0 ? void 0 : _2.backup) === null || _3 === void 0 ? void 0 : _3.rev) === null || _4 === void 0 ? void 0 : _4.apply) === "ALWAYS" &&
|
|
154
|
+
if (((_4 = (_3 = (_2 = opts.model.psm) === null || _2 === void 0 ? void 0 : _2.backup) === null || _3 === void 0 ? void 0 : _3.rev) === null || _4 === void 0 ? void 0 : _4.apply) === "ALWAYS" &&
|
|
155
|
+
revision_query &&
|
|
156
|
+
revision_resolver) {
|
|
119
157
|
always_query = revision_query;
|
|
120
158
|
always_resolver = revision_resolver;
|
|
121
159
|
revision = `always-${opts.parser.migration}`;
|
|
@@ -162,12 +200,8 @@ function restoreBackupSQL(opts) {
|
|
|
162
200
|
end;
|
|
163
201
|
$$;
|
|
164
202
|
`.split("\n")
|
|
165
|
-
.filter(
|
|
166
|
-
.map(
|
|
167
|
-
if (value.startsWith(" "))
|
|
168
|
-
return value.substring(" ".length);
|
|
169
|
-
return value;
|
|
170
|
-
})
|
|
203
|
+
.filter((line) => line.trim() !== "")
|
|
204
|
+
.map((line) => line.replace(/^ {6}/, "")) // Remove indentação de 6 espaços
|
|
171
205
|
.join("\n");
|
|
172
206
|
return {
|
|
173
207
|
data: [
|
|
@@ -181,7 +215,7 @@ function restoreBackupSQL(opts) {
|
|
|
181
215
|
revision: (_7 = (_6 = (_5 = opts.model.psm) === null || _5 === void 0 ? void 0 : _5.backup) === null || _6 === void 0 ? void 0 : _6.rev) === null || _7 === void 0 ? void 0 : _7.version,
|
|
182
216
|
relation: relation,
|
|
183
217
|
hash: (0, sha_1.migrationHash)(opts.parser.migration, `restore:data-${relation}`),
|
|
184
|
-
operation: `restore:data-${relation}
|
|
218
|
+
operation: `restore:data-${relation}`,
|
|
185
219
|
}).join("\n"),
|
|
186
220
|
(0, notice_1.notice)(`REGISTRY RESTORE OF BACKUP FOR MODEL ${opts.model.model} OK`),
|
|
187
221
|
],
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"engine.js","sourceRoot":"","sources":["engine.ts"],"names":[],"mappings":";;AAQA,
|
|
1
|
+
{"version":3,"file":"engine.js","sourceRoot":"","sources":["engine.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,16 +1,17 @@
|
|
|
1
|
-
import {FieldOption, ModelOptions} from "@prisma-psm/core";
|
|
2
|
-
import {oid, lit, VARCHAR} from "../../utils/escape";
|
|
1
|
+
import { FieldOption, ModelOptions } from "@prisma-psm/core";
|
|
2
|
+
import { oid, lit, VARCHAR } from "../../utils/escape";
|
|
3
3
|
import { noTab } from "../../utils/tabs";
|
|
4
4
|
import { PostgresParserOptions } from "../def";
|
|
5
|
-
import {notice} from "../notice";
|
|
6
|
-
import {createRevision} from "../sys";
|
|
7
|
-
import {migrationHash} from "../../utils/sha";
|
|
8
|
-
|
|
9
|
-
export function createFunctionRestoreSerial(
|
|
10
|
-
const sys = oid(
|
|
11
|
-
const tab = " "
|
|
12
|
-
return noTab(
|
|
13
|
-
|
|
5
|
+
import { notice } from "../notice";
|
|
6
|
+
import { createRevision } from "../sys";
|
|
7
|
+
import { migrationHash } from "../../utils/sha";
|
|
8
|
+
|
|
9
|
+
export function createFunctionRestoreSerial(opts: PostgresParserOptions) {
|
|
10
|
+
const sys = oid(opts.sys);
|
|
11
|
+
const tab = " ";
|
|
12
|
+
return noTab(
|
|
13
|
+
[
|
|
14
|
+
`create or replace function ${sys}.restore_serial(
|
|
14
15
|
schema character varying,
|
|
15
16
|
source character varying,
|
|
16
17
|
shadow character varying,
|
|
@@ -40,118 +41,159 @@ export function createFunctionRestoreSerial( opts: PostgresParserOptions) {
|
|
|
40
41
|
end if;
|
|
41
42
|
return next;
|
|
42
43
|
end;
|
|
43
|
-
|
|
44
|
-
|
|
44
|
+
$$;`,
|
|
45
|
+
],
|
|
46
|
+
tab
|
|
47
|
+
);
|
|
45
48
|
}
|
|
46
49
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
parser:PostgresParserOptions
|
|
50
|
+
export interface RestoreOptions {
|
|
51
|
+
source: string;
|
|
52
|
+
model: ModelOptions;
|
|
53
|
+
parser: PostgresParserOptions;
|
|
52
54
|
}
|
|
53
55
|
|
|
54
|
-
export function lockTable(opts:RestoreOptions
|
|
55
|
-
const schema =
|
|
56
|
-
const source =
|
|
56
|
+
export function lockTable(opts: RestoreOptions) {
|
|
57
|
+
const schema = oid(opts.model.schema);
|
|
58
|
+
const source = oid(opts.source);
|
|
59
|
+
const modelName = opts.model.model;
|
|
60
|
+
const sSchema = lit(opts.model.schema);
|
|
61
|
+
const sSource = lit(opts.source);
|
|
57
62
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
+
const sql = `
|
|
64
|
+
DO $$
|
|
65
|
+
BEGIN
|
|
66
|
+
IF EXISTS (
|
|
67
|
+
SELECT 1
|
|
68
|
+
FROM pg_catalog.pg_class c
|
|
69
|
+
JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
|
|
70
|
+
WHERE n.nspname = ${sSchema}
|
|
71
|
+
AND c.relname = ${sSource}
|
|
72
|
+
) THEN
|
|
73
|
+
LOCK TABLE ${schema}.${source} IN SHARE MODE;
|
|
74
|
+
RAISE NOTICE 'LOCK TABLE FOR SHARE MODE TO MODEL ${modelName} [OK]';
|
|
75
|
+
ELSE
|
|
76
|
+
RAISE NOTICE 'TABLE ${schema}.${source} NOT FOUND, SKIPPING LOCK';
|
|
77
|
+
END IF;
|
|
78
|
+
END $$;`.trim();
|
|
79
|
+
|
|
80
|
+
return [notice(`PREPARING LOCK FOR MODEL ${modelName}`), sql];
|
|
63
81
|
}
|
|
64
82
|
|
|
83
|
+
export function restoreBackupSQL(opts: RestoreOptions): {
|
|
84
|
+
data: string[];
|
|
85
|
+
registry: string[];
|
|
86
|
+
} {
|
|
87
|
+
const schema = oid(opts.model.schema);
|
|
88
|
+
const source = oid(opts.source);
|
|
89
|
+
const shadow = oid(opts.parser.shadow);
|
|
90
|
+
const table = oid(opts.model.name);
|
|
91
|
+
const temp = oid(opts.model.temp);
|
|
65
92
|
|
|
66
|
-
|
|
67
|
-
source:string
|
|
68
|
-
model:ModelOptions,
|
|
69
|
-
parser:PostgresParserOptions
|
|
70
|
-
}
|
|
93
|
+
if (opts.model.psm?.backup?.skip) return null as any;
|
|
71
94
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
const schema = oid(opts.model.schema);
|
|
77
|
-
const source = oid(opts.source);
|
|
78
|
-
const shadow = oid(opts.parser.shadow);
|
|
79
|
-
const table = oid(opts.model.name);
|
|
80
|
-
const temp = oid(opts.model.temp);
|
|
81
|
-
|
|
82
|
-
if( opts.model.psm?.backup?.skip ) return null as any;
|
|
83
|
-
|
|
84
|
-
let filter = ( field:FieldOption)=>{
|
|
85
|
-
return !field.isGenerated
|
|
86
|
-
&& field.kind === "scalar"
|
|
87
|
-
;
|
|
88
|
-
}
|
|
95
|
+
// Filtra campos escalares não gerados (serão restaurados)
|
|
96
|
+
const filter = (field: FieldOption) =>
|
|
97
|
+
!field.isGenerated && field.kind === "scalar";
|
|
98
|
+
const fields = opts.model.fields.filter(filter);
|
|
89
99
|
|
|
100
|
+
// Lista de colunas para o INSERT (na mesma ordem dos campos)
|
|
101
|
+
const columns = fields.map((f) => ` ${oid(f.name)}`).join(", ");
|
|
102
|
+
|
|
103
|
+
// Constrói a lista de expressões SELECT com COALESCE para cada campo
|
|
104
|
+
const selectExpressions = fields
|
|
105
|
+
.map((field) => {
|
|
106
|
+
const colName = oid(field.dbName || field.name);
|
|
107
|
+
// Obtém a expressão default da coluna, se houver; caso contrário, usa NULL
|
|
108
|
+
// Nota: assumindo que field.default contém a expressão SQL do default
|
|
109
|
+
const defaultValue =
|
|
110
|
+
field.default !== undefined ? field.default : "NULL";
|
|
111
|
+
// Gera: COALESCE(s."colName", defaultExpression) AS "colName"
|
|
112
|
+
return `COALESCE(s.${colName}, ${defaultValue}) AS ${colName}`;
|
|
113
|
+
})
|
|
114
|
+
.join(",\n");
|
|
90
115
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
116
|
+
// Nova DEFAULT_QUERY com CTE e COALESCE para cada coluna
|
|
117
|
+
const DEFAULT_QUERY = `
|
|
118
|
+
WITH __source AS (
|
|
119
|
+
SELECT (jsonb_populate_record(null::${shadow}.${temp}, to_jsonb(_t))).*
|
|
120
|
+
FROM ${schema}.${source} _t
|
|
121
|
+
)
|
|
122
|
+
SELECT
|
|
123
|
+
${selectExpressions}
|
|
124
|
+
FROM __source s
|
|
125
|
+
`;
|
|
95
126
|
|
|
127
|
+
const DEFAULT_SOURCE_CHECKER = `select 1 from pg_catalog.pg_tables t where t.tablename = ${lit(
|
|
128
|
+
opts.model.name
|
|
129
|
+
)} and t.schemaname = ${lit(opts.model.schema)}`;
|
|
96
130
|
const DEFAULT_WHEN = `true`;
|
|
97
|
-
const
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
.map( value => {
|
|
101
|
-
return ` ${oid(value.dbName||value.name)}`;
|
|
102
|
-
})
|
|
103
|
-
.join(", ")
|
|
104
|
-
;
|
|
131
|
+
const DEFAULT_RESOLVER = fields
|
|
132
|
+
.map((f) => ` ${oid(f.dbName || f.name)}`)
|
|
133
|
+
.join(", ");
|
|
105
134
|
|
|
106
135
|
let source_exists = DEFAULT_SOURCE_CHECKER;
|
|
107
136
|
let when = DEFAULT_WHEN;
|
|
108
137
|
|
|
109
|
-
const revision_resolver =
|
|
110
|
-
.map(
|
|
111
|
-
|
|
138
|
+
const revision_resolver = fields
|
|
139
|
+
.map((field) => {
|
|
112
140
|
let expression = field.psm?.restore?.expression;
|
|
113
|
-
if(
|
|
141
|
+
if (!expression) expression = ` ${oid(field.dbName || field.name)}`;
|
|
114
142
|
return expression;
|
|
115
143
|
})
|
|
116
|
-
.join(", ")
|
|
117
|
-
;
|
|
144
|
+
.join(", ");
|
|
118
145
|
|
|
119
146
|
let revision_query = DEFAULT_QUERY;
|
|
120
147
|
const expression = opts.model.psm?.backup?.rev?.expression;
|
|
121
148
|
const exists = opts.model.psm?.backup?.rev?.exists;
|
|
122
149
|
|
|
123
|
-
if(
|
|
150
|
+
if (exists?.length) {
|
|
124
151
|
source_exists = exists;
|
|
125
152
|
}
|
|
126
153
|
|
|
127
|
-
if(
|
|
128
|
-
&&
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
154
|
+
if (
|
|
155
|
+
opts.model.psm?.backup?.rev?.from === "query" &&
|
|
156
|
+
expression
|
|
157
|
+
) {
|
|
158
|
+
revision_query = expression;
|
|
159
|
+
} else if (
|
|
160
|
+
opts.model.psm?.backup?.rev?.from === "query:linked" &&
|
|
161
|
+
expression &&
|
|
162
|
+
opts.model.psm?.query?.[expression]
|
|
163
|
+
) {
|
|
164
|
+
revision_query = opts.model.psm?.query?.[expression];
|
|
165
|
+
} else if (
|
|
166
|
+
opts.model.psm?.backup?.rev?.from === "model" &&
|
|
167
|
+
expression
|
|
168
|
+
) {
|
|
169
|
+
const model = opts.parser.models.find((m) => m.model === expression);
|
|
170
|
+
if (model) {
|
|
171
|
+
revision_query = `select * from ${oid(
|
|
172
|
+
model.schema || "public"
|
|
173
|
+
)}.${oid(model.dbName || model.name)}`;
|
|
174
|
+
}
|
|
139
175
|
}
|
|
140
176
|
|
|
141
|
-
const sys = oid(
|
|
142
|
-
let revision= "null";
|
|
177
|
+
const sys = oid(opts.parser.sys);
|
|
178
|
+
let revision = "null";
|
|
143
179
|
const relation = `${schema}.${table}`;
|
|
144
|
-
if(
|
|
180
|
+
if (opts.model.psm?.backup?.rev?.version) {
|
|
181
|
+
revision = lit(opts.model.psm?.backup?.rev.version);
|
|
182
|
+
}
|
|
145
183
|
|
|
146
184
|
let always_query = DEFAULT_QUERY;
|
|
147
185
|
let always_resolver = DEFAULT_RESOLVER;
|
|
148
|
-
if(
|
|
186
|
+
if (
|
|
187
|
+
opts.model.psm?.backup?.rev?.apply === "ALWAYS" &&
|
|
188
|
+
revision_query &&
|
|
189
|
+
revision_resolver
|
|
190
|
+
) {
|
|
149
191
|
always_query = revision_query;
|
|
150
192
|
always_resolver = revision_resolver;
|
|
151
193
|
revision = `always-${opts.parser.migration}`;
|
|
152
194
|
}
|
|
153
195
|
|
|
154
|
-
const next
|
|
196
|
+
const next = `
|
|
155
197
|
do $$
|
|
156
198
|
declare
|
|
157
199
|
_revision character varying := ${revision}::character varying;
|
|
@@ -176,14 +218,14 @@ export function restoreBackupSQL(opts:RestoreOptions ): {
|
|
|
176
218
|
) then
|
|
177
219
|
with __restore as (
|
|
178
220
|
${revision_query}
|
|
179
|
-
) insert into ${shadow}.${temp} (${
|
|
221
|
+
) insert into ${shadow}.${temp} (${columns})
|
|
180
222
|
select
|
|
181
223
|
${revision_resolver}
|
|
182
224
|
from __restore r;
|
|
183
225
|
elsif _revision is null then
|
|
184
226
|
with __restore as (
|
|
185
227
|
${always_query}
|
|
186
|
-
) insert into ${shadow}.${temp} (${
|
|
228
|
+
) insert into ${shadow}.${temp} (${columns})
|
|
187
229
|
select
|
|
188
230
|
${always_resolver}
|
|
189
231
|
from __restore r;
|
|
@@ -193,38 +235,40 @@ export function restoreBackupSQL(opts:RestoreOptions ): {
|
|
|
193
235
|
end;
|
|
194
236
|
$$;
|
|
195
237
|
`.split("\n")
|
|
196
|
-
.filter(
|
|
197
|
-
.map(
|
|
198
|
-
if( value.startsWith(" ") ) return value.substring(" ".length)
|
|
199
|
-
return value;
|
|
200
|
-
})
|
|
238
|
+
.filter((line) => line.trim() !== "")
|
|
239
|
+
.map((line) => line.replace(/^ {6}/, "")) // Remove indentação de 6 espaços
|
|
201
240
|
.join("\n");
|
|
202
241
|
|
|
203
242
|
return {
|
|
204
243
|
data: [
|
|
205
|
-
notice(
|
|
244
|
+
notice(`RESTORE BACKUP FOR MODEL ${opts.model.model}`),
|
|
206
245
|
next,
|
|
207
|
-
notice(
|
|
246
|
+
notice(`RESTORE BACKUP FOR MODEL ${opts.model.model} OK`),
|
|
208
247
|
],
|
|
209
248
|
registry: [
|
|
210
|
-
notice(
|
|
211
|
-
createRevision(
|
|
249
|
+
notice(`REGISTRY RESTORE OF BACKUP FOR MODEL ${opts.model.model}`),
|
|
250
|
+
createRevision(opts.parser, {
|
|
212
251
|
revision: opts.model.psm?.backup?.rev?.version,
|
|
213
252
|
relation: relation,
|
|
214
|
-
hash: migrationHash(
|
|
215
|
-
|
|
253
|
+
hash: migrationHash(
|
|
254
|
+
opts.parser.migration,
|
|
255
|
+
`restore:data-${relation}`
|
|
256
|
+
),
|
|
257
|
+
operation: `restore:data-${relation}`,
|
|
216
258
|
}).join("\n"),
|
|
217
|
-
notice(
|
|
259
|
+
notice(
|
|
260
|
+
`REGISTRY RESTORE OF BACKUP FOR MODEL ${opts.model.model} OK`
|
|
261
|
+
),
|
|
218
262
|
],
|
|
219
|
-
}
|
|
263
|
+
};
|
|
220
264
|
}
|
|
221
265
|
|
|
222
266
|
export interface RestoreSerialOptions extends RestoreOptions {
|
|
223
|
-
from:string
|
|
224
|
-
to:string
|
|
225
|
-
seq?:string
|
|
267
|
+
from: string;
|
|
268
|
+
to: string;
|
|
269
|
+
seq?: string;
|
|
226
270
|
}
|
|
227
|
-
export function restoreSerialSQL(
|
|
271
|
+
export function restoreSerialSQL(opts: RestoreSerialOptions) {
|
|
228
272
|
const args = [
|
|
229
273
|
` schema := ${lit(opts.model.schema, VARCHAR)}`,
|
|
230
274
|
` source := ${lit(opts.source, VARCHAR)}`,
|
|
@@ -232,13 +276,17 @@ export function restoreSerialSQL( opts:RestoreSerialOptions) {
|
|
|
232
276
|
` temp := ${lit(opts.model.temp, VARCHAR)}`,
|
|
233
277
|
` "from" := ${lit(opts.from, VARCHAR)}`,
|
|
234
278
|
` "to" := ${lit(opts.to, VARCHAR)}`,
|
|
235
|
-
` "seq" := ${lit(
|
|
279
|
+
` "seq" := ${lit(opts.seq, VARCHAR)}`,
|
|
236
280
|
];
|
|
237
281
|
return [
|
|
238
|
-
notice(
|
|
239
|
-
|
|
240
|
-
|
|
282
|
+
notice(
|
|
283
|
+
`RESTORE SEQUENCE OF FIELD ${opts.to} FROM MODEL ${opts.model.model}`
|
|
284
|
+
),
|
|
285
|
+
`select * from ${oid(opts.parser.sys)}.restore_serial(\n ${args.join(
|
|
286
|
+
",\n "
|
|
287
|
+
)}\n);`,
|
|
288
|
+
notice(
|
|
289
|
+
`RESTORE SEQUENCE OF FIELD ${opts.to} FROM MODEL ${opts.model.model} OK`
|
|
290
|
+
),
|
|
241
291
|
];
|
|
242
|
-
|
|
243
|
-
}
|
|
244
|
-
|
|
292
|
+
}
|