@strapi/data-transfer 4.6.0-beta.2 → 4.6.1
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/lib/engine/diagnostic.d.ts +40 -0
- package/lib/engine/diagnostic.js +50 -0
- package/lib/engine/errors.d.ts +28 -0
- package/lib/engine/errors.js +29 -0
- package/lib/engine/index.d.ts +11 -3
- package/lib/engine/index.js +143 -30
- package/lib/engine/validation/index.d.ts +2 -1
- package/lib/engine/validation/index.js +4 -13
- package/lib/engine/validation/provider.d.ts +3 -0
- package/lib/engine/validation/provider.js +18 -0
- package/lib/errors/base.d.ts +8 -0
- package/lib/errors/base.js +13 -0
- package/lib/errors/constants.d.ts +3 -0
- package/lib/errors/constants.js +9 -0
- package/lib/errors/index.d.ts +2 -0
- package/lib/errors/index.js +19 -0
- package/lib/errors/providers.d.ts +21 -0
- package/lib/errors/providers.js +32 -0
- package/lib/file/providers/source/index.js +29 -14
- package/lib/strapi/providers/local-destination/index.d.ts +3 -1
- package/lib/strapi/providers/local-destination/index.js +53 -33
- package/lib/strapi/providers/local-destination/strategies/restore/configuration.d.ts +2 -2
- package/lib/strapi/providers/local-destination/strategies/restore/configuration.js +17 -10
- package/lib/strapi/providers/local-destination/strategies/restore/entities.d.ts +2 -0
- package/lib/strapi/providers/local-destination/strategies/restore/entities.js +57 -54
- package/lib/strapi/providers/local-destination/strategies/restore/index.js +2 -1
- package/lib/strapi/providers/local-destination/strategies/restore/links.d.ts +2 -1
- package/lib/strapi/providers/local-destination/strategies/restore/links.js +18 -15
- package/lib/strapi/providers/local-source/index.js +6 -21
- package/lib/strapi/providers/remote-destination/index.js +21 -6
- package/lib/strapi/queries/link.d.ts +1 -1
- package/lib/strapi/queries/link.js +17 -3
- package/lib/strapi/remote/constants.d.ts +1 -0
- package/lib/strapi/remote/constants.js +2 -1
- package/lib/strapi/remote/handlers.js +28 -12
- package/lib/utils/index.d.ts +1 -0
- package/lib/utils/index.js +2 -1
- package/lib/utils/json.js +6 -6
- package/lib/utils/providers.d.ts +2 -0
- package/lib/utils/providers.js +11 -0
- package/lib/utils/transaction.d.ts +3 -0
- package/lib/utils/transaction.js +70 -0
- package/package.json +7 -6
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ProviderTransferError = exports.ProviderValidationError = exports.ProviderInitializationError = exports.ProviderError = void 0;
|
|
4
|
+
const base_1 = require("./base");
|
|
5
|
+
const constants_1 = require("./constants");
|
|
6
|
+
class ProviderError extends base_1.DataTransferError {
|
|
7
|
+
constructor(severity, message, details) {
|
|
8
|
+
super('provider', severity, message, details);
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
exports.ProviderError = ProviderError;
|
|
12
|
+
class ProviderInitializationError extends ProviderError {
|
|
13
|
+
constructor(message) {
|
|
14
|
+
super(constants_1.SeverityKind.FATAL, message, { step: 'initialization' });
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
exports.ProviderInitializationError = ProviderInitializationError;
|
|
18
|
+
// TODO: these types are not working correctly, ProviderTransferError() is accepting any details object rather than requiring T
|
|
19
|
+
class ProviderValidationError extends ProviderError {
|
|
20
|
+
constructor(message, details) {
|
|
21
|
+
super(constants_1.SeverityKind.SILLY, message, { step: 'validation', details });
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
exports.ProviderValidationError = ProviderValidationError;
|
|
25
|
+
// TODO: these types are not working correctly, ProviderTransferError() is accepting any details object rather than requiring T
|
|
26
|
+
class ProviderTransferError extends ProviderError {
|
|
27
|
+
constructor(message, details) {
|
|
28
|
+
super(constants_1.SeverityKind.FATAL, message, { step: 'transfer', details });
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
exports.ProviderTransferError = ProviderTransferError;
|
|
32
|
+
//# sourceMappingURL=providers.js.map
|
|
@@ -26,6 +26,7 @@ const stream_1 = require("stream");
|
|
|
26
26
|
const Parser_1 = require("stream-json/jsonl/Parser");
|
|
27
27
|
const encryption_1 = require("../../../utils/encryption");
|
|
28
28
|
const stream_2 = require("../../../utils/stream");
|
|
29
|
+
const providers_1 = require("../../../errors/providers");
|
|
29
30
|
/**
|
|
30
31
|
* Constant for the metadata file path
|
|
31
32
|
*/
|
|
@@ -56,7 +57,10 @@ class LocalFileSourceProvider {
|
|
|
56
57
|
__classPrivateFieldSet(this, _LocalFileSourceProvider_metadata, await this.getMetadata(), "f");
|
|
57
58
|
}
|
|
58
59
|
catch (e) {
|
|
59
|
-
|
|
60
|
+
if (this.options?.encryption?.enabled) {
|
|
61
|
+
throw new providers_1.ProviderInitializationError(`Key is incorrect or the file '${filePath}' is not a valid Strapi data file.`);
|
|
62
|
+
}
|
|
63
|
+
throw new providers_1.ProviderInitializationError(`File '${filePath}' is not a valid Strapi data file.`);
|
|
60
64
|
}
|
|
61
65
|
}
|
|
62
66
|
getMetadata() {
|
|
@@ -137,35 +141,46 @@ _LocalFileSourceProvider_metadata = new WeakMap(), _LocalFileSourceProvider_inst
|
|
|
137
141
|
if (entry.type !== 'File') {
|
|
138
142
|
return false;
|
|
139
143
|
}
|
|
140
|
-
const parts = filePath.split('/');
|
|
144
|
+
const parts = path_1.default.relative('.', filePath).split('/');
|
|
145
|
+
// TODO: this method is limiting us from having additional subdirectories and is requiring us to remove any "./" prefixes (the path.relative line above)
|
|
141
146
|
if (parts.length !== 2) {
|
|
142
147
|
return false;
|
|
143
148
|
}
|
|
144
149
|
return parts[0] === directory;
|
|
145
150
|
},
|
|
146
|
-
onentry(entry) {
|
|
151
|
+
async onentry(entry) {
|
|
147
152
|
const transforms = [
|
|
148
153
|
// JSONL parser to read the data chunks one by one (line by line)
|
|
149
|
-
(0, Parser_1.parser)(
|
|
154
|
+
(0, Parser_1.parser)({
|
|
155
|
+
checkErrors: true,
|
|
156
|
+
}),
|
|
150
157
|
// The JSONL parser returns each line as key/value
|
|
151
158
|
(line) => line.value,
|
|
152
159
|
];
|
|
153
|
-
entry
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
+
const stream = entry.pipe((0, stream_chain_1.chain)(transforms));
|
|
161
|
+
try {
|
|
162
|
+
for await (const chunk of stream) {
|
|
163
|
+
outStream.write(chunk);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
catch (e) {
|
|
167
|
+
outStream.destroy(new providers_1.ProviderTransferError(`Error parsing backup files from backup file ${entry.path}: ${e.message}`, {
|
|
168
|
+
details: {
|
|
169
|
+
error: e,
|
|
170
|
+
},
|
|
171
|
+
}));
|
|
172
|
+
}
|
|
160
173
|
},
|
|
161
174
|
}),
|
|
162
|
-
], () => {
|
|
175
|
+
], async () => {
|
|
163
176
|
// Manually send the 'end' event to the out stream
|
|
164
177
|
// once every entry has finished streaming its content
|
|
165
178
|
outStream.end();
|
|
166
179
|
});
|
|
167
180
|
return outStream;
|
|
168
|
-
}, _LocalFileSourceProvider_parseJSONFile =
|
|
181
|
+
}, _LocalFileSourceProvider_parseJSONFile =
|
|
182
|
+
// For collecting an entire JSON file then parsing it, not for streaming JSONL
|
|
183
|
+
async function _LocalFileSourceProvider_parseJSONFile(fileStream, filePath) {
|
|
169
184
|
return new Promise((resolve, reject) => {
|
|
170
185
|
(0, stream_1.pipeline)([
|
|
171
186
|
fileStream,
|
|
@@ -175,7 +190,7 @@ _LocalFileSourceProvider_metadata = new WeakMap(), _LocalFileSourceProvider_inst
|
|
|
175
190
|
* Filter the parsed entries to only keep the one that matches the given filepath
|
|
176
191
|
*/
|
|
177
192
|
filter(entryPath, entry) {
|
|
178
|
-
return entryPath
|
|
193
|
+
return !path_1.default.relative(filePath, entryPath).length && entry.type === 'File';
|
|
179
194
|
},
|
|
180
195
|
async onentry(entry) {
|
|
181
196
|
// Collect all the content of the entry file
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/// <reference types="lodash" />
|
|
2
2
|
/// <reference types="node" />
|
|
3
3
|
import { Writable } from 'stream';
|
|
4
|
-
import type { IDestinationProvider, IMetadata, ProviderType } from '../../../../types';
|
|
4
|
+
import type { IDestinationProvider, IMetadata, ProviderType, Transaction } from '../../../../types';
|
|
5
5
|
import { restore } from './strategies';
|
|
6
6
|
export declare const VALID_CONFLICT_STRATEGIES: string[];
|
|
7
7
|
export declare const DEFAULT_CONFLICT_STRATEGY = "restore";
|
|
@@ -17,9 +17,11 @@ declare class LocalStrapiDestinationProvider implements IDestinationProvider {
|
|
|
17
17
|
type: ProviderType;
|
|
18
18
|
options: ILocalStrapiDestinationProviderOptions;
|
|
19
19
|
strapi?: Strapi.Strapi;
|
|
20
|
+
transaction?: Transaction;
|
|
20
21
|
constructor(options: ILocalStrapiDestinationProviderOptions);
|
|
21
22
|
bootstrap(): Promise<void>;
|
|
22
23
|
close(): Promise<void>;
|
|
24
|
+
rollback(): void;
|
|
23
25
|
beforeTransfer(): Promise<void>;
|
|
24
26
|
getMetadata(): IMetadata;
|
|
25
27
|
getSchemas(): import("lodash").Dictionary<Partial<import("@strapi/strapi").Schema>>;
|
|
@@ -44,6 +44,8 @@ const path_1 = __importDefault(require("path"));
|
|
|
44
44
|
const fse = __importStar(require("fs-extra"));
|
|
45
45
|
const strategies_1 = require("./strategies");
|
|
46
46
|
const utils = __importStar(require("../../../utils"));
|
|
47
|
+
const providers_1 = require("../../../errors/providers");
|
|
48
|
+
const providers_2 = require("../../../utils/providers");
|
|
47
49
|
exports.VALID_CONFLICT_STRATEGIES = ['restore', 'merge'];
|
|
48
50
|
exports.DEFAULT_CONFLICT_STRATEGY = 'restore';
|
|
49
51
|
class LocalStrapiDestinationProvider {
|
|
@@ -61,39 +63,46 @@ class LocalStrapiDestinationProvider {
|
|
|
61
63
|
async bootstrap() {
|
|
62
64
|
__classPrivateFieldGet(this, _LocalStrapiDestinationProvider_instances, "m", _LocalStrapiDestinationProvider_validateOptions).call(this);
|
|
63
65
|
this.strapi = await this.options.getStrapi();
|
|
66
|
+
this.transaction = utils.transaction.createTransaction(this.strapi);
|
|
64
67
|
}
|
|
65
68
|
async close() {
|
|
66
69
|
const { autoDestroy } = this.options;
|
|
70
|
+
this.transaction?.end();
|
|
67
71
|
// Basically `!== false` but more deterministic
|
|
68
72
|
if (autoDestroy === undefined || autoDestroy === true) {
|
|
69
73
|
await this.strapi?.destroy();
|
|
70
74
|
}
|
|
71
75
|
}
|
|
76
|
+
rollback() {
|
|
77
|
+
this.transaction?.rollback();
|
|
78
|
+
}
|
|
72
79
|
async beforeTransfer() {
|
|
73
|
-
if (this.
|
|
74
|
-
|
|
80
|
+
if (!this.strapi) {
|
|
81
|
+
throw new Error('Strapi instance not found');
|
|
75
82
|
}
|
|
83
|
+
await this.transaction?.attach(async () => {
|
|
84
|
+
try {
|
|
85
|
+
if (this.options.strategy === 'restore') {
|
|
86
|
+
await __classPrivateFieldGet(this, _LocalStrapiDestinationProvider_instances, "m", _LocalStrapiDestinationProvider_deleteAll).call(this);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
catch (error) {
|
|
90
|
+
throw new Error(`restore failed ${error}`);
|
|
91
|
+
}
|
|
92
|
+
});
|
|
76
93
|
}
|
|
77
94
|
getMetadata() {
|
|
78
95
|
const strapiVersion = strapi.config.get('info.strapi');
|
|
79
96
|
const createdAt = new Date().toISOString();
|
|
80
|
-
const plugins = Object.keys(strapi.plugins);
|
|
81
97
|
return {
|
|
82
98
|
createdAt,
|
|
83
99
|
strapi: {
|
|
84
100
|
version: strapiVersion,
|
|
85
|
-
plugins: plugins.map((name) => ({
|
|
86
|
-
name,
|
|
87
|
-
// TODO: Get the plugin actual version when it'll be available
|
|
88
|
-
version: strapiVersion,
|
|
89
|
-
})),
|
|
90
101
|
},
|
|
91
102
|
};
|
|
92
103
|
}
|
|
93
104
|
getSchemas() {
|
|
94
|
-
|
|
95
|
-
throw new Error('Not able to get Schemas. Strapi instance not found');
|
|
96
|
-
}
|
|
105
|
+
(0, providers_2.assertValidStrapi)(this.strapi, 'Not able to get Schemas');
|
|
97
106
|
const schemas = {
|
|
98
107
|
...this.strapi.contentTypes,
|
|
99
108
|
...this.strapi.components,
|
|
@@ -101,9 +110,7 @@ class LocalStrapiDestinationProvider {
|
|
|
101
110
|
return utils.schema.mapSchemasValues(schemas);
|
|
102
111
|
}
|
|
103
112
|
createEntitiesWriteStream() {
|
|
104
|
-
|
|
105
|
-
throw new Error('Not able to import entities. Strapi instance not found');
|
|
106
|
-
}
|
|
113
|
+
(0, providers_2.assertValidStrapi)(this.strapi, 'Not able to import entities');
|
|
107
114
|
const { strategy } = this.options;
|
|
108
115
|
const updateMappingTable = (type, oldID, newID) => {
|
|
109
116
|
if (!__classPrivateFieldGet(this, _LocalStrapiDestinationProvider_entitiesMapper, "f")[type]) {
|
|
@@ -115,19 +122,24 @@ class LocalStrapiDestinationProvider {
|
|
|
115
122
|
return strategies_1.restore.createEntitiesWriteStream({
|
|
116
123
|
strapi: this.strapi,
|
|
117
124
|
updateMappingTable,
|
|
125
|
+
transaction: this.transaction,
|
|
118
126
|
});
|
|
119
127
|
}
|
|
120
|
-
throw new
|
|
128
|
+
throw new providers_1.ProviderValidationError(`Invalid strategy ${this.options.strategy}`, {
|
|
129
|
+
check: 'strategy',
|
|
130
|
+
strategy: this.options.strategy,
|
|
131
|
+
validStrategies: exports.VALID_CONFLICT_STRATEGIES,
|
|
132
|
+
});
|
|
121
133
|
}
|
|
122
134
|
// TODO: Move this logic to the restore strategy
|
|
123
135
|
async createAssetsWriteStream() {
|
|
124
|
-
|
|
125
|
-
throw new Error('Not able to stream Assets. Strapi instance not found');
|
|
126
|
-
}
|
|
136
|
+
(0, providers_2.assertValidStrapi)(this.strapi, 'Not able to stream Assets');
|
|
127
137
|
const assetsDirectory = path_1.default.join(this.strapi.dirs.static.public, 'uploads');
|
|
128
138
|
const backupDirectory = path_1.default.join(this.strapi.dirs.static.public, `uploads_backup_${Date.now()}`);
|
|
129
|
-
await fse.
|
|
139
|
+
await fse.move(assetsDirectory, backupDirectory);
|
|
130
140
|
await fse.mkdir(assetsDirectory);
|
|
141
|
+
// Create a .gitkeep file to ensure the directory is not empty
|
|
142
|
+
await fse.outputFile(path_1.default.join(assetsDirectory, '.gitkeep'), '');
|
|
131
143
|
return new stream_1.Writable({
|
|
132
144
|
objectMode: true,
|
|
133
145
|
async final(next) {
|
|
@@ -143,11 +155,11 @@ class LocalStrapiDestinationProvider {
|
|
|
143
155
|
.on('error', async (error) => {
|
|
144
156
|
try {
|
|
145
157
|
await fse.rm(assetsDirectory, { recursive: true, force: true });
|
|
146
|
-
await fse.
|
|
147
|
-
this.destroy(new
|
|
158
|
+
await fse.move(backupDirectory, assetsDirectory);
|
|
159
|
+
this.destroy(new providers_1.ProviderTransferError(`There was an error during the transfer process. The original files have been restored to ${assetsDirectory}`));
|
|
148
160
|
}
|
|
149
161
|
catch (err) {
|
|
150
|
-
throw new
|
|
162
|
+
throw new providers_1.ProviderTransferError(`There was an error doing the rollback process. The original files are in ${backupDirectory}, but we failed to restore them to ${assetsDirectory}`);
|
|
151
163
|
}
|
|
152
164
|
finally {
|
|
153
165
|
callback(error);
|
|
@@ -157,14 +169,16 @@ class LocalStrapiDestinationProvider {
|
|
|
157
169
|
});
|
|
158
170
|
}
|
|
159
171
|
async createConfigurationWriteStream() {
|
|
160
|
-
|
|
161
|
-
throw new Error('Not able to stream Configurations. Strapi instance not found');
|
|
162
|
-
}
|
|
172
|
+
(0, providers_2.assertValidStrapi)(this.strapi, 'Not able to stream Configurations');
|
|
163
173
|
const { strategy } = this.options;
|
|
164
174
|
if (strategy === 'restore') {
|
|
165
|
-
return strategies_1.restore.createConfigurationWriteStream(this.strapi);
|
|
175
|
+
return strategies_1.restore.createConfigurationWriteStream(this.strapi, this.transaction);
|
|
166
176
|
}
|
|
167
|
-
throw new
|
|
177
|
+
throw new providers_1.ProviderValidationError(`Invalid strategy ${strategy}`, {
|
|
178
|
+
check: 'strategy',
|
|
179
|
+
strategy,
|
|
180
|
+
validStrategies: exports.VALID_CONFLICT_STRATEGIES,
|
|
181
|
+
});
|
|
168
182
|
}
|
|
169
183
|
async createLinksWriteStream() {
|
|
170
184
|
if (!this.strapi) {
|
|
@@ -173,19 +187,25 @@ class LocalStrapiDestinationProvider {
|
|
|
173
187
|
const { strategy } = this.options;
|
|
174
188
|
const mapID = (uid, id) => __classPrivateFieldGet(this, _LocalStrapiDestinationProvider_entitiesMapper, "f")[uid]?.[id];
|
|
175
189
|
if (strategy === 'restore') {
|
|
176
|
-
return strategies_1.restore.createLinksWriteStream(mapID, this.strapi);
|
|
190
|
+
return strategies_1.restore.createLinksWriteStream(mapID, this.strapi, this.transaction);
|
|
177
191
|
}
|
|
178
|
-
throw new
|
|
192
|
+
throw new providers_1.ProviderValidationError(`Invalid strategy ${strategy}`, {
|
|
193
|
+
check: 'strategy',
|
|
194
|
+
strategy,
|
|
195
|
+
validStrategies: exports.VALID_CONFLICT_STRATEGIES,
|
|
196
|
+
});
|
|
179
197
|
}
|
|
180
198
|
}
|
|
181
199
|
_LocalStrapiDestinationProvider_entitiesMapper = new WeakMap(), _LocalStrapiDestinationProvider_instances = new WeakSet(), _LocalStrapiDestinationProvider_validateOptions = function _LocalStrapiDestinationProvider_validateOptions() {
|
|
182
200
|
if (!exports.VALID_CONFLICT_STRATEGIES.includes(this.options.strategy)) {
|
|
183
|
-
throw new
|
|
201
|
+
throw new providers_1.ProviderValidationError(`Invalid strategy ${this.options.strategy}`, {
|
|
202
|
+
check: 'strategy',
|
|
203
|
+
strategy: this.options.strategy,
|
|
204
|
+
validStrategies: exports.VALID_CONFLICT_STRATEGIES,
|
|
205
|
+
});
|
|
184
206
|
}
|
|
185
207
|
}, _LocalStrapiDestinationProvider_deleteAll = async function _LocalStrapiDestinationProvider_deleteAll() {
|
|
186
|
-
|
|
187
|
-
throw new Error('Strapi instance not found');
|
|
188
|
-
}
|
|
208
|
+
(0, providers_2.assertValidStrapi)(this.strapi);
|
|
189
209
|
return strategies_1.restore.deleteRecords(this.strapi, this.options.restore);
|
|
190
210
|
};
|
|
191
211
|
const createLocalStrapiDestinationProvider = (options) => {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
2
|
import { Writable } from 'stream';
|
|
3
|
-
import { IConfiguration } from '../../../../../../types';
|
|
3
|
+
import { IConfiguration, Transaction } from '../../../../../../types';
|
|
4
4
|
export declare const restoreConfigs: (strapi: Strapi.Strapi, config: IConfiguration) => Promise<any>;
|
|
5
|
-
export declare const createConfigurationWriteStream: (strapi: Strapi.Strapi) => Promise<Writable>;
|
|
5
|
+
export declare const createConfigurationWriteStream: (strapi: Strapi.Strapi, transaction?: Transaction | undefined) => Promise<Writable>;
|
|
@@ -4,9 +4,13 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.createConfigurationWriteStream = exports.restoreConfigs = void 0;
|
|
7
|
+
const fp_1 = require("lodash/fp");
|
|
7
8
|
const stream_1 = require("stream");
|
|
8
9
|
const chalk_1 = __importDefault(require("chalk"));
|
|
9
|
-
const
|
|
10
|
+
const providers_1 = require("../../../../../errors/providers");
|
|
11
|
+
const omitInvalidCreationAttributes = (0, fp_1.omit)(['id']);
|
|
12
|
+
const restoreCoreStore = async (strapi, values) => {
|
|
13
|
+
const data = omitInvalidCreationAttributes(values);
|
|
10
14
|
return strapi.db.query('strapi::core-store').create({
|
|
11
15
|
data: {
|
|
12
16
|
...data,
|
|
@@ -14,7 +18,8 @@ const restoreCoreStore = async (strapi, data) => {
|
|
|
14
18
|
},
|
|
15
19
|
});
|
|
16
20
|
};
|
|
17
|
-
const restoreWebhooks = async (strapi,
|
|
21
|
+
const restoreWebhooks = async (strapi, values) => {
|
|
22
|
+
const data = omitInvalidCreationAttributes(values);
|
|
18
23
|
return strapi.db.query('webhook').create({ data });
|
|
19
24
|
};
|
|
20
25
|
const restoreConfigs = async (strapi, config) => {
|
|
@@ -26,17 +31,19 @@ const restoreConfigs = async (strapi, config) => {
|
|
|
26
31
|
}
|
|
27
32
|
};
|
|
28
33
|
exports.restoreConfigs = restoreConfigs;
|
|
29
|
-
const createConfigurationWriteStream = async (strapi) => {
|
|
34
|
+
const createConfigurationWriteStream = async (strapi, transaction) => {
|
|
30
35
|
return new stream_1.Writable({
|
|
31
36
|
objectMode: true,
|
|
32
37
|
async write(config, _encoding, callback) {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
38
|
+
await transaction?.attach(async () => {
|
|
39
|
+
try {
|
|
40
|
+
await (0, exports.restoreConfigs)(strapi, config);
|
|
41
|
+
}
|
|
42
|
+
catch (error) {
|
|
43
|
+
return callback(new providers_1.ProviderTransferError(`Failed to import ${chalk_1.default.yellowBright(config.type)} (${chalk_1.default.greenBright(config.value.id)}`));
|
|
44
|
+
}
|
|
45
|
+
callback();
|
|
46
|
+
});
|
|
40
47
|
},
|
|
41
48
|
});
|
|
42
49
|
};
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
2
|
import type { SchemaUID } from '@strapi/strapi/lib/types/utils';
|
|
3
3
|
import { Writable } from 'stream';
|
|
4
|
+
import type { Transaction } from '../../../../../../types';
|
|
4
5
|
interface IEntitiesRestoreStreamOptions {
|
|
5
6
|
strapi: Strapi.Strapi;
|
|
6
7
|
updateMappingTable<T extends SchemaUID | string>(type: T, oldID: number, newID: number): void;
|
|
8
|
+
transaction?: Transaction;
|
|
7
9
|
}
|
|
8
10
|
declare const createEntitiesWriteStream: (options: IEntitiesRestoreStreamOptions) => Writable;
|
|
9
11
|
export { createEntitiesWriteStream };
|
|
@@ -26,73 +26,76 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
26
26
|
exports.createEntitiesWriteStream = void 0;
|
|
27
27
|
const fp_1 = require("lodash/fp");
|
|
28
28
|
const stream_1 = require("stream");
|
|
29
|
+
const providers_1 = require("../../../../../errors/providers");
|
|
29
30
|
const utils_1 = require("../../../../../utils");
|
|
30
31
|
const queries = __importStar(require("../../../../queries"));
|
|
31
32
|
const createEntitiesWriteStream = (options) => {
|
|
32
|
-
const { strapi, updateMappingTable } = options;
|
|
33
|
+
const { strapi, updateMappingTable, transaction } = options;
|
|
33
34
|
const query = queries.entity.createEntityQuery(strapi);
|
|
34
35
|
return new stream_1.Writable({
|
|
35
36
|
objectMode: true,
|
|
36
37
|
async write(entity, _encoding, callback) {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
cType
|
|
53
|
-
|
|
54
|
-
if (path in cType.attributes) {
|
|
55
|
-
const attribute = cType.attributes[path];
|
|
56
|
-
if (attribute.type === 'component') {
|
|
57
|
-
cType = strapi.getModel(attribute.component);
|
|
38
|
+
await transaction?.attach(async () => {
|
|
39
|
+
const { type, id, data } = entity;
|
|
40
|
+
const { create, getDeepPopulateComponentLikeQuery } = query(type);
|
|
41
|
+
const contentType = strapi.getModel(type);
|
|
42
|
+
/**
|
|
43
|
+
* Resolve the component UID of an entity's attribute based
|
|
44
|
+
* on a given path (components & dynamic zones only)
|
|
45
|
+
*/
|
|
46
|
+
const resolveType = (paths) => {
|
|
47
|
+
let cType = contentType;
|
|
48
|
+
let value = data;
|
|
49
|
+
for (const path of paths) {
|
|
50
|
+
value = (0, fp_1.get)(path, value);
|
|
51
|
+
// Needed when the value of cType should be computed
|
|
52
|
+
// based on the next value (eg: dynamic zones)
|
|
53
|
+
if (typeof cType === 'function') {
|
|
54
|
+
cType = cType(value);
|
|
58
55
|
}
|
|
59
|
-
if (
|
|
60
|
-
|
|
56
|
+
if (path in cType.attributes) {
|
|
57
|
+
const attribute = cType.attributes[path];
|
|
58
|
+
if (attribute.type === 'component') {
|
|
59
|
+
cType = strapi.getModel(attribute.component);
|
|
60
|
+
}
|
|
61
|
+
if (attribute.type === 'dynamiczone') {
|
|
62
|
+
cType = ({ __component }) => strapi.getModel(__component);
|
|
63
|
+
}
|
|
61
64
|
}
|
|
62
65
|
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
66
|
+
return cType?.uid;
|
|
67
|
+
};
|
|
68
|
+
try {
|
|
69
|
+
const created = await create({
|
|
70
|
+
data,
|
|
71
|
+
populate: getDeepPopulateComponentLikeQuery(contentType, { select: 'id' }),
|
|
72
|
+
select: 'id',
|
|
73
|
+
});
|
|
74
|
+
// Compute differences between original & new entities
|
|
75
|
+
const diffs = utils_1.json.diff(data, created);
|
|
76
|
+
updateMappingTable(type, id, created.id);
|
|
77
|
+
// For each difference found on an ID attribute,
|
|
78
|
+
// update the mapping the table accordingly
|
|
79
|
+
diffs.forEach((diff) => {
|
|
80
|
+
if (diff.kind === 'modified' && (0, fp_1.last)(diff.path) === 'id') {
|
|
81
|
+
const target = resolveType(diff.path);
|
|
82
|
+
// If no type is found for the given path, then ignore the diff
|
|
83
|
+
if (!target) {
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
const [oldID, newID] = diff.values;
|
|
87
|
+
updateMappingTable(target, oldID, newID);
|
|
83
88
|
}
|
|
84
|
-
|
|
85
|
-
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
catch (e) {
|
|
92
|
+
if (e instanceof Error) {
|
|
93
|
+
return callback(e);
|
|
86
94
|
}
|
|
87
|
-
|
|
88
|
-
}
|
|
89
|
-
catch (e) {
|
|
90
|
-
if (e instanceof Error) {
|
|
91
|
-
return callback(e);
|
|
95
|
+
return callback(new providers_1.ProviderTransferError(`Failed to create "${type}" (${id})`));
|
|
92
96
|
}
|
|
93
|
-
return callback(
|
|
94
|
-
}
|
|
95
|
-
return callback(null);
|
|
97
|
+
return callback(null);
|
|
98
|
+
});
|
|
96
99
|
},
|
|
97
100
|
});
|
|
98
101
|
};
|
|
@@ -27,6 +27,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
27
27
|
};
|
|
28
28
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
29
|
exports.deleteRecords = void 0;
|
|
30
|
+
const providers_1 = require("../../../../../errors/providers");
|
|
30
31
|
const queries = __importStar(require("../../../../queries"));
|
|
31
32
|
const deleteRecords = async (strapi, options) => {
|
|
32
33
|
const entities = await deleteEntitiesRecord(strapi, options);
|
|
@@ -92,7 +93,7 @@ const useResults = (keys) => {
|
|
|
92
93
|
const update = (count, key) => {
|
|
93
94
|
if (key) {
|
|
94
95
|
if (!(key in results.aggregate)) {
|
|
95
|
-
throw new
|
|
96
|
+
throw new providers_1.ProviderTransferError(`Unknown key "${key}" provided in results update`);
|
|
96
97
|
}
|
|
97
98
|
results.aggregate[key].count += count;
|
|
98
99
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
2
|
import { Writable } from 'stream';
|
|
3
|
-
|
|
3
|
+
import { Transaction } from '../../../../../../types';
|
|
4
|
+
export declare const createLinksWriteStream: (mapID: (uid: string, id: number) => number | undefined, strapi: Strapi.Strapi, transaction?: Transaction | undefined) => Writable;
|
|
@@ -2,26 +2,29 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.createLinksWriteStream = void 0;
|
|
4
4
|
const stream_1 = require("stream");
|
|
5
|
+
const providers_1 = require("../../../../../errors/providers");
|
|
5
6
|
const link_1 = require("../../../../queries/link");
|
|
6
|
-
const createLinksWriteStream = (mapID, strapi) => {
|
|
7
|
+
const createLinksWriteStream = (mapID, strapi, transaction) => {
|
|
7
8
|
return new stream_1.Writable({
|
|
8
9
|
objectMode: true,
|
|
9
10
|
async write(link, _encoding, callback) {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
catch (e) {
|
|
19
|
-
if (e instanceof Error) {
|
|
20
|
-
return callback(e);
|
|
11
|
+
await transaction?.attach(async (trx) => {
|
|
12
|
+
const { left, right } = link;
|
|
13
|
+
const query = (0, link_1.createLinkQuery)(strapi, trx);
|
|
14
|
+
// Map IDs if needed
|
|
15
|
+
left.ref = mapID(left.type, left.ref) ?? left.ref;
|
|
16
|
+
right.ref = mapID(right.type, right.ref) ?? right.ref;
|
|
17
|
+
try {
|
|
18
|
+
await query().insert(link);
|
|
21
19
|
}
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
20
|
+
catch (e) {
|
|
21
|
+
if (e instanceof Error) {
|
|
22
|
+
return callback(e);
|
|
23
|
+
}
|
|
24
|
+
return callback(new providers_1.ProviderTransferError(`An error happened while trying to import a ${left.type} link.`));
|
|
25
|
+
}
|
|
26
|
+
callback(null);
|
|
27
|
+
});
|
|
25
28
|
},
|
|
26
29
|
});
|
|
27
30
|
};
|