@@ -25,6 +25,16 @@ const {
25
25
databasesCreateUrlAttribute,
26
26
databasesCreateIpAttribute,
27
27
databasesCreateEnumAttribute,
28
+ databasesUpdateBooleanAttribute,
29
+ databasesUpdateStringAttribute,
30
+ databasesUpdateIntegerAttribute,
31
+ databasesUpdateFloatAttribute,
32
+ databasesUpdateEmailAttribute,
33
+ databasesUpdateDatetimeAttribute,
34
+ databasesUpdateUrlAttribute,
35
+ databasesUpdateIpAttribute,
36
+ databasesUpdateEnumAttribute,
37
+ databasesUpdateRelationshipAttribute,
28
38
databasesCreateRelationshipAttribute,
29
39
databasesDeleteAttribute,
30
40
databasesListAttributes,
@@ -396,6 +406,123 @@ const createAttribute = async (databaseId, collectionId, attribute) => {
396
406
})
397
407
}
398
408
}
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
+ }
399
526
const deleteAttribute = async (collection, attribute) => {
400
527
log(`Deleting attribute ${attribute.key} of ${collection.name} ( ${collection['$id']} )`);
401
528
@@ -407,25 +534,39 @@ const deleteAttribute = async (collection, attribute) => {
407
534
});
408
535
}
409
536
537
+
410
538
/**
411
539
* Check if attribute non-changeable fields has been changed
412
540
* If so return the differences as an object.
413
541
* @param remote
414
542
* @param local
415
543
* @param collection
544
+ * @param recraeting when true will check only non-changeable keys
416
545
* @returns {undefined|{reason: string, action: *, attribute, key: string}}
417
546
*/
418
- const checkAttributeChanges = (remote, local, collection) => {
547
+ const checkAttributeChanges = (remote, local, collection, recraeting = true ) => {
419
548
if (local === undefined) {
420
549
return undefined;
421
550
}
422
551
423
552
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 ');
425
554
let reason = '';
555
+ let attribute = remote;
426
556
427
557
for (let key of Object.keys(remote)) {
428
558
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) {
429
570
continue;
430
571
}
431
572
@@ -435,7 +576,7 @@ const checkAttributeChanges = (remote, local, collection) => {
435
576
}
436
577
}
437
578
438
- return reason === '' ? undefined : { key: keyName, attribute: remote , reason, action };
579
+ return reason === '' ? undefined : { key: keyName, attribute, reason, action };
439
580
}
440
581
441
582
/**
@@ -468,9 +609,12 @@ const attributesToCreate = async (remoteAttributes, localAttributes, collection)
468
609
const deleting = remoteAttributes.filter((attribute) => !attributesContains(attribute, localAttributes)).map((attr) => generateChangesObject(attr, collection, false));
469
610
const adding = localAttributes.filter((attribute) => !attributesContains(attribute, remoteAttributes)).map((attr) => generateChangesObject(attr, collection, true));
470
611
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);
471
615
472
616
let changedAttributes = [];
473
- const changing = [...deleting, ...adding, ...conflicts]
617
+ const changing = [...deleting, ...adding, ...conflicts, ...changes ]
474
618
if (changing.length === 0) {
475
619
return changedAttributes;
476
620
}
@@ -481,7 +625,7 @@ const attributesToCreate = async (remoteAttributes, localAttributes, collection)
481
625
return { Key: change.key, Action: change.action, Reason: change.reason, };
482
626
}));
483
627
484
- if (!cliConfig.force && (deleting.length > 0 || conflicts.length > 0) ) {
628
+ if (!cliConfig.force) {
485
629
if (deleting.length > 0) {
486
630
log(`Attribute deletion will cause ${chalk.red('loss of data')}`);
487
631
}
@@ -502,6 +646,11 @@ const attributesToCreate = async (remoteAttributes, localAttributes, collection)
502
646
remoteAttributes = remoteAttributes.filter((attribute) => !attributesContains(attribute, changedAttributes))
503
647
}
504
648
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
+
505
654
const deletingAttributes = deleting.map((change) => change.attribute);
506
655
await Promise.all(deletingAttributes.map((attribute) => deleteAttribute(collection, attribute)));
507
656
const attributeKeys = [...remoteAttributes.map(attribute => attribute.key), ...deletingAttributes.map(attribute => attribute.key)]
@@ -1063,7 +1212,6 @@ const pushCollection = async ({ returnOnZero } = { returnOnZero: false }) => {
1063
1212
attributes = await attributesToCreate(collection.remoteVersion.attributes, collection.attributes, collection);
1064
1213
1065
1214
if (Array.isArray(attributes) && attributes.length < = 0) {
1066
- log(`No changes has been detected. Skipping ${collection.name} ( ${collection['$id']} )`);
1067
1215
continue;
1068
1216
}
1069
1217
}
0 commit comments