Skip to content

Commit a0e0a4f

Browse files
committed
fix(cli): Apply non destructive changes
1 parent d17c805 commit a0e0a4f

File tree

1 file changed

+154
-5
lines changed

1 file changed

+154
-5
lines changed

templates/cli/lib/commands/push.js.twig

Lines changed: 154 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,16 @@ const {
2525
databasesCreateUrlAttribute,
2626
databasesCreateIpAttribute,
2727
databasesCreateEnumAttribute,
28+
databasesUpdateBooleanAttribute,
29+
databasesUpdateStringAttribute,
30+
databasesUpdateIntegerAttribute,
31+
databasesUpdateFloatAttribute,
32+
databasesUpdateEmailAttribute,
33+
databasesUpdateDatetimeAttribute,
34+
databasesUpdateUrlAttribute,
35+
databasesUpdateIpAttribute,
36+
databasesUpdateEnumAttribute,
37+
databasesUpdateRelationshipAttribute,
2838
databasesCreateRelationshipAttribute,
2939
databasesDeleteAttribute,
3040
databasesListAttributes,
@@ -396,6 +406,123 @@ const createAttribute = async (databaseId, collectionId, attribute) => {
396406
})
397407
}
398408
}
409+
410+
const updateAttribute = async (databaseId, collectionId, attribute) => {
411+
switch (attribute.type) {
412+
case 'string':
413+
switch (attribute.format) {
414+
case 'email':
415+
return await databasesUpdateEmailAttribute({
416+
databaseId,
417+
collectionId,
418+
key: attribute.key,
419+
required: attribute.required,
420+
xdefault: attribute.default,
421+
array: attribute.array,
422+
parseOutput: false
423+
})
424+
case 'url':
425+
return await databasesUpdateUrlAttribute({
426+
databaseId,
427+
collectionId,
428+
key: attribute.key,
429+
required: attribute.required,
430+
xdefault: attribute.default,
431+
array: attribute.array,
432+
parseOutput: false
433+
})
434+
case 'ip':
435+
return await databasesUpdateIpAttribute({
436+
databaseId,
437+
collectionId,
438+
key: attribute.key,
439+
required: attribute.required,
440+
xdefault: attribute.default,
441+
array: attribute.array,
442+
parseOutput: false
443+
})
444+
case 'enum':
445+
return await databasesUpdateEnumAttribute({
446+
databaseId,
447+
collectionId,
448+
key: attribute.key,
449+
elements: attribute.elements,
450+
required: attribute.required,
451+
xdefault: attribute.default,
452+
array: attribute.array,
453+
parseOutput: false
454+
})
455+
default:
456+
return await databasesUpdateStringAttribute({
457+
databaseId,
458+
collectionId,
459+
key: attribute.key,
460+
size: attribute.size,
461+
required: attribute.required,
462+
xdefault: attribute.default,
463+
array: attribute.array,
464+
parseOutput: false
465+
})
466+
467+
}
468+
case 'integer':
469+
return await databasesUpdateIntegerAttribute({
470+
databaseId,
471+
collectionId,
472+
key: attribute.key,
473+
required: attribute.required,
474+
min: parseInt(attribute.min.toString()),
475+
max: parseInt(attribute.max.toString()),
476+
xdefault: attribute.default,
477+
array: attribute.array,
478+
parseOutput: false
479+
})
480+
case 'double':
481+
return databasesUpdateFloatAttribute({
482+
databaseId,
483+
collectionId,
484+
key: attribute.key,
485+
required: attribute.required,
486+
min: parseFloat(attribute.min.toString()),
487+
max: parseFloat(attribute.max.toString()),
488+
xdefault: attribute.default,
489+
array: attribute.array,
490+
parseOutput: false
491+
})
492+
case 'boolean':
493+
return databasesUpdateBooleanAttribute({
494+
databaseId,
495+
collectionId,
496+
key: attribute.key,
497+
required: attribute.required,
498+
xdefault: attribute.default,
499+
array: attribute.array,
500+
parseOutput: false
501+
})
502+
case 'datetime':
503+
return databasesUpdateDatetimeAttribute({
504+
databaseId,
505+
collectionId,
506+
key: attribute.key,
507+
required: attribute.required,
508+
xdefault: attribute.default,
509+
array: attribute.array,
510+
parseOutput: false
511+
})
512+
case 'relationship':
513+
return databasesUpdateRelationshipAttribute({
514+
databaseId,
515+
collectionId,
516+
relatedCollectionId: attribute.relatedCollection,
517+
type: attribute.relationType,
518+
twoWay: attribute.twoWay,
519+
key: attribute.key,
520+
twoWayKey: attribute.twoWayKey,
521+
onDelete: attribute.onDelete,
522+
parseOutput: false
523+
})
524+
}
525+
}
399526
const deleteAttribute = async (collection, attribute) => {
400527
log(`Deleting attribute ${attribute.key} of ${collection.name} ( ${collection['$id']} )`);
401528

@@ -407,25 +534,39 @@ const deleteAttribute = async (collection, attribute) => {
407534
});
408535
}
409536

537+
410538
/**
411539
* Check if attribute non-changeable fields has been changed
412540
* If so return the differences as an object.
413541
* @param remote
414542
* @param local
415543
* @param collection
544+
* @param recraeting when true will check only non-changeable keys
416545
* @returns {undefined|{reason: string, action: *, attribute, key: string}}
417546
*/
418-
const checkAttributeChanges = (remote, local, collection) => {
547+
const checkAttributeChanges = (remote, local, collection, recraeting = true) => {
419548
if (local === undefined) {
420549
return undefined;
421550
}
422551

423552
const keyName = `${chalk.yellow(local.key)} in ${collection.name} (${collection['$id']})`;
424-
const action = chalk.cyan('recreating');
553+
const action = chalk.cyan(recraeting ? 'recreating' : 'changing');
425554
let reason = '';
555+
let attribute = remote;
426556

427557
for (let key of Object.keys(remote)) {
428558
if (changeableKeys.includes(key)) {
559+
if (!recraeting) {
560+
if (remote[key] !== local[key]) {
561+
const bol = reason === '' ? '' : '\n';
562+
reason += `${bol}${key} changed from ${chalk.red(remote[key])} to ${chalk.green(local[key])}`;
563+
attribute = local;
564+
}
565+
}
566+
continue;
567+
}
568+
569+
if (!recraeting) {
429570
continue;
430571
}
431572

@@ -435,7 +576,7 @@ const checkAttributeChanges = (remote, local, collection) => {
435576
}
436577
}
437578

438-
return reason === '' ? undefined : { key: keyName, attribute: remote, reason, action };
579+
return reason === '' ? undefined : { key: keyName, attribute, reason, action };
439580
}
440581

441582
/**
@@ -468,9 +609,12 @@ const attributesToCreate = async (remoteAttributes, localAttributes, collection)
468609
const deleting = remoteAttributes.filter((attribute) => !attributesContains(attribute, localAttributes)).map((attr) => generateChangesObject(attr, collection, false));
469610
const adding = localAttributes.filter((attribute) => !attributesContains(attribute, remoteAttributes)).map((attr) => generateChangesObject(attr, collection, true));
470611
const conflicts = remoteAttributes.map((attribute) => checkAttributeChanges(attribute, attributesContains(attribute, localAttributes), collection)).filter(attribute => attribute !== undefined);
612+
const changes = remoteAttributes.map((attribute) => checkAttributeChanges(attribute, attributesContains(attribute, localAttributes), collection, false))
613+
.filter(attribute => attribute !== undefined)
614+
.filter(attribute => conflicts.filter(attr => attribute.key === attr.key).length !== 1);
471615

472616
let changedAttributes = [];
473-
const changing = [...deleting, ...adding, ...conflicts]
617+
const changing = [...deleting, ...adding, ...conflicts, ...changes]
474618
if (changing.length === 0) {
475619
return changedAttributes;
476620
}
@@ -502,6 +646,11 @@ const attributesToCreate = async (remoteAttributes, localAttributes, collection)
502646
remoteAttributes = remoteAttributes.filter((attribute) => !attributesContains(attribute, changedAttributes))
503647
}
504648

649+
if (changes.length > 0) {
650+
changedAttributes = changes.map((change) => change.attribute);
651+
await Promise.all(changedAttributes.map((changed) => updateAttribute(collection['databaseId'],collection['$id'], changed)));
652+
}
653+
505654
const deletingAttributes = deleting.map((change) => change.attribute);
506655
await Promise.all(deletingAttributes.map((attribute) => deleteAttribute(collection, attribute)));
507656
const attributeKeys = [...remoteAttributes.map(attribute => attribute.key), ...deletingAttributes.map(attribute => attribute.key)]
@@ -1063,7 +1212,7 @@ const pushCollection = async ({ returnOnZero } = { returnOnZero: false }) => {
10631212
attributes = await attributesToCreate(collection.remoteVersion.attributes, collection.attributes, collection);
10641213

10651214
if (Array.isArray(attributes) && attributes.length <= 0) {
1066-
log(`No changes has been detected. Skipping ${collection.name} ( ${collection['$id']} )`);
1215+
log(`No destructive changes has been detected. Skipping ${collection.name} ( ${collection['$id']} )`);
10671216
continue;
10681217
}
10691218
}

0 commit comments

Comments
 (0)