@strapi/data-transfer 4.6.0-beta.2 → 4.6.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.
- 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 +140 -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 +9 -11
- package/lib/strapi/providers/local-destination/index.d.ts +3 -1
- package/lib/strapi/providers/local-destination/index.js +51 -31
- 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/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 +6 -5
|
@@ -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
|
|
@@ -137,29 +137,27 @@ _LocalFileSourceProvider_metadata = new WeakMap(), _LocalFileSourceProvider_inst
|
|
|
137
137
|
if (entry.type !== 'File') {
|
|
138
138
|
return false;
|
|
139
139
|
}
|
|
140
|
-
const parts = filePath.split('/');
|
|
140
|
+
const parts = path_1.default.relative('.', filePath).split('/');
|
|
141
|
+
// TODO: this method is limiting us from having additional subdirectories and is requiring us to remove any "./" prefixes (the path.relative line above)
|
|
141
142
|
if (parts.length !== 2) {
|
|
142
143
|
return false;
|
|
143
144
|
}
|
|
144
145
|
return parts[0] === directory;
|
|
145
146
|
},
|
|
146
|
-
onentry(entry) {
|
|
147
|
+
async onentry(entry) {
|
|
147
148
|
const transforms = [
|
|
148
149
|
// JSONL parser to read the data chunks one by one (line by line)
|
|
149
150
|
(0, Parser_1.parser)(),
|
|
150
151
|
// The JSONL parser returns each line as key/value
|
|
151
152
|
(line) => line.value,
|
|
152
153
|
];
|
|
153
|
-
entry
|
|
154
|
-
|
|
155
|
-
.
|
|
156
|
-
|
|
157
|
-
// DO NOT send the 'end' event when this entry has finished
|
|
158
|
-
// emitting data, so that it doesn't close the out stream
|
|
159
|
-
.pipe(outStream, { end: false });
|
|
154
|
+
const stream = entry.pipe((0, stream_chain_1.chain)(transforms));
|
|
155
|
+
for await (const chunk of stream) {
|
|
156
|
+
outStream.write(chunk);
|
|
157
|
+
}
|
|
160
158
|
},
|
|
161
159
|
}),
|
|
162
|
-
], () => {
|
|
160
|
+
], async () => {
|
|
163
161
|
// Manually send the 'end' event to the out stream
|
|
164
162
|
// once every entry has finished streaming its content
|
|
165
163
|
outStream.end();
|
|
@@ -175,7 +173,7 @@ _LocalFileSourceProvider_metadata = new WeakMap(), _LocalFileSourceProvider_inst
|
|
|
175
173
|
* Filter the parsed entries to only keep the one that matches the given filepath
|
|
176
174
|
*/
|
|
177
175
|
filter(entryPath, entry) {
|
|
178
|
-
return entryPath
|
|
176
|
+
return !path_1.default.relative(filePath, entryPath).length && entry.type === 'File';
|
|
179
177
|
},
|
|
180
178
|
async onentry(entry) {
|
|
181
179
|
// 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
139
|
await fse.rename(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) {
|
|
@@ -144,10 +156,10 @@ class LocalStrapiDestinationProvider {
|
|
|
144
156
|
try {
|
|
145
157
|
await fse.rm(assetsDirectory, { recursive: true, force: true });
|
|
146
158
|
await fse.rename(backupDirectory, assetsDirectory);
|
|
147
|
-
this.destroy(new
|
|
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
|
};
|
|
@@ -31,6 +31,7 @@ const links_1 = require("./links");
|
|
|
31
31
|
const configuration_1 = require("./configuration");
|
|
32
32
|
const assets_1 = require("./assets");
|
|
33
33
|
const utils = __importStar(require("../../../utils"));
|
|
34
|
+
const providers_1 = require("../../../utils/providers");
|
|
34
35
|
const createLocalStrapiSourceProvider = (options) => {
|
|
35
36
|
return new LocalStrapiSourceProvider(options);
|
|
36
37
|
};
|
|
@@ -54,23 +55,15 @@ class LocalStrapiSourceProvider {
|
|
|
54
55
|
getMetadata() {
|
|
55
56
|
const strapiVersion = strapi.config.get('info.strapi');
|
|
56
57
|
const createdAt = new Date().toISOString();
|
|
57
|
-
const plugins = Object.keys(strapi.plugins);
|
|
58
58
|
return {
|
|
59
59
|
createdAt,
|
|
60
60
|
strapi: {
|
|
61
61
|
version: strapiVersion,
|
|
62
|
-
plugins: plugins.map((name) => ({
|
|
63
|
-
name,
|
|
64
|
-
// TODO: Get the plugin actual version when it'll be available
|
|
65
|
-
version: strapiVersion,
|
|
66
|
-
})),
|
|
67
62
|
},
|
|
68
63
|
};
|
|
69
64
|
}
|
|
70
65
|
async createEntitiesReadStream() {
|
|
71
|
-
|
|
72
|
-
throw new Error('Not able to stream entities. Strapi instance not found');
|
|
73
|
-
}
|
|
66
|
+
(0, providers_1.assertValidStrapi)(this.strapi, 'Not able to stream entities');
|
|
74
67
|
return (0, stream_chain_1.chain)([
|
|
75
68
|
// Entities stream
|
|
76
69
|
(0, entities_1.createEntitiesStream)(this.strapi),
|
|
@@ -79,21 +72,15 @@ class LocalStrapiSourceProvider {
|
|
|
79
72
|
]);
|
|
80
73
|
}
|
|
81
74
|
createLinksReadStream() {
|
|
82
|
-
|
|
83
|
-
throw new Error('Not able to stream links. Strapi instance not found');
|
|
84
|
-
}
|
|
75
|
+
(0, providers_1.assertValidStrapi)(this.strapi, 'Not able to stream links');
|
|
85
76
|
return (0, links_1.createLinksStream)(this.strapi);
|
|
86
77
|
}
|
|
87
78
|
createConfigurationReadStream() {
|
|
88
|
-
|
|
89
|
-
throw new Error('Not able to stream configuration. Strapi instance not found');
|
|
90
|
-
}
|
|
79
|
+
(0, providers_1.assertValidStrapi)(this.strapi, 'Not able to stream configuration');
|
|
91
80
|
return (0, configuration_1.createConfigurationStream)(strapi);
|
|
92
81
|
}
|
|
93
82
|
getSchemas() {
|
|
94
|
-
|
|
95
|
-
throw new Error('Not able to get Schemas. Strapi instance not found');
|
|
96
|
-
}
|
|
83
|
+
(0, providers_1.assertValidStrapi)(this.strapi, 'Not able to get Schemas');
|
|
97
84
|
const schemas = {
|
|
98
85
|
...this.strapi.contentTypes,
|
|
99
86
|
...this.strapi.components,
|
|
@@ -104,9 +91,7 @@ class LocalStrapiSourceProvider {
|
|
|
104
91
|
return stream_1.Readable.from(Object.values(this.getSchemas()));
|
|
105
92
|
}
|
|
106
93
|
createAssetsReadStream() {
|
|
107
|
-
|
|
108
|
-
throw new Error('Not able to stream assets. Strapi instance not found');
|
|
109
|
-
}
|
|
94
|
+
(0, providers_1.assertValidStrapi)(this.strapi, 'Not able to stream assets');
|
|
110
95
|
return (0, assets_1.createAssetsStream)(this.strapi);
|
|
111
96
|
}
|
|
112
97
|
}
|