mysqlsyncr 1.1.2 → 1.1.6

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/dist/index.cjs CHANGED
@@ -137,7 +137,10 @@ function _iterableToArrayLimit(r, l) {
137
137
  f = true,
138
138
  o = false;
139
139
  try {
140
- if (i = (t = t.call(r)).next, 0 === l) ; else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0);
140
+ if (i = (t = t.call(r)).next, 0 === l) {
141
+ if (Object(t) !== t) return;
142
+ f = !1;
143
+ } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0);
141
144
  } catch (r) {
142
145
  o = true, n = r;
143
146
  } finally {
@@ -3599,7 +3602,7 @@ var applyDifferences = /*#__PURE__*/function () {
3599
3602
  _iterator = _createForOfIteratorHelper(differences);
3600
3603
  _context2.prev = 2;
3601
3604
  _loop = /*#__PURE__*/_regeneratorRuntime().mark(function _loop() {
3602
- var diff, createDatabaseSQL, tableName, createSQL, _tableName, dropTableSQL, addFieldSQL, modifyFieldSQL, defaultClause, _modifyFieldSQL, dropFieldSQL, _tableName2, field, _defaultClause, _dropFieldSQL, existingColumns, columnNames, missingColumns, indexColumns, primaryKeySQL, uniqueSQL, addIndexSQL, dropPrimaryKeySQL, dropIndexSQL, _tableName3, index, _dropPrimaryKeySQL, _dropIndexSQL, _uniqueSQL, addPrimaryKeySQL, _addIndexSQL, dropCurrentProcSQL, createProcSQL, dropViewSQL, createViewSQL, _dropViewSQL, _createViewSQL, _dropViewSQL2, createTriggerSQL, dropTriggerSQL, _createTriggerSQL, _dropTriggerSQL, _createDatabaseSQL;
3605
+ var diff, createDatabaseSQL, tableName, createSQL, _tableName, dropTableSQL, addFieldSQL, modifyFieldSQL, defaultClause, _modifyFieldSQL, dropFieldSQL, _tableName2, field, currentField, needsBatchProcessing, addColumnSQL, totalUpdated, batchSize, batchCount, updateSQL, result, rowsAffected, verifySQL, _yield$connection$que, _yield$connection$que2, verifyResult, swapColumnsSQL, isTimestamp, _defaultClause, _currentField, hasOnUpdate, _modifyFieldSQL2, existingColumns, columnNames, missingColumns, indexColumns, primaryKeySQL, uniqueSQL, addIndexSQL, dropPrimaryKeySQL, dropIndexSQL, _tableName3, index, _dropPrimaryKeySQL, _dropIndexSQL, _uniqueSQL, addPrimaryKeySQL, _addIndexSQL, dropCurrentProcSQL, createProcSQL, dropViewSQL, createViewSQL, _dropViewSQL, _createViewSQL, _dropViewSQL2, createTriggerSQL, dropTriggerSQL, _createTriggerSQL, _dropTriggerSQL, _createDatabaseSQL;
3603
3606
  return _regeneratorRuntime().wrap(function _loop$(_context) {
3604
3607
  while (1) switch (_context.prev = _context.next) {
3605
3608
  case 0:
@@ -3629,7 +3632,7 @@ var applyDifferences = /*#__PURE__*/function () {
3629
3632
  _context.next = 16;
3630
3633
  return connection.query(createSQL);
3631
3634
  case 16:
3632
- _context.next = 210;
3635
+ _context.next = 249;
3633
3636
  break;
3634
3637
  case 18:
3635
3638
  if (!(diff.type === 'extra_table')) {
@@ -3643,7 +3646,7 @@ var applyDifferences = /*#__PURE__*/function () {
3643
3646
  _context.next = 25;
3644
3647
  return connection.query(dropTableSQL);
3645
3648
  case 25:
3646
- _context.next = 210;
3649
+ _context.next = 249;
3647
3650
  break;
3648
3651
  case 27:
3649
3652
  if (!(diff.type === 'missing_field')) {
@@ -3675,7 +3678,7 @@ var applyDifferences = /*#__PURE__*/function () {
3675
3678
  _context.next = 43;
3676
3679
  return connection.query(_modifyFieldSQL);
3677
3680
  case 43:
3678
- _context.next = 210;
3681
+ _context.next = 249;
3679
3682
  break;
3680
3683
  case 45:
3681
3684
  if (!(diff.type === 'extra_field')) {
@@ -3687,30 +3690,132 @@ var applyDifferences = /*#__PURE__*/function () {
3687
3690
  _context.next = 50;
3688
3691
  return connection.query(dropFieldSQL);
3689
3692
  case 50:
3690
- _context.next = 210;
3693
+ _context.next = 249;
3691
3694
  break;
3692
3695
  case 52:
3693
3696
  if (!(diff.type === 'mismatched_field')) {
3694
- _context.next = 61;
3697
+ _context.next = 100;
3695
3698
  break;
3696
3699
  }
3697
- _tableName2 = diff.tableName, field = diff.field;
3698
- _defaultClause = field.Default === 'CURRENT_TIMESTAMP' ? 'DEFAULT CURRENT_TIMESTAMP' : field.Default === 'NULL' ? 'DEFAULT NULL' : field.Default !== undefined && field.Default !== null ? "DEFAULT '".concat(field.Default, "'") : 'DEFAULT NULL';
3699
- _dropFieldSQL = "ALTER TABLE `".concat(_tableName2, "` CHANGE `").concat(field.Field, "` `").concat(field.Field, "` ").concat(field.Type, " ").concat(field.NotNull ? 'NOT NULL' : '', " ").concat(_defaultClause, ";");
3700
- console.log("Executing: ".concat(_dropFieldSQL));
3701
- _context.next = 59;
3702
- return connection.query(_dropFieldSQL);
3703
- case 59:
3704
- _context.next = 210;
3700
+ _tableName2 = diff.tableName, field = diff.field, currentField = diff.currentField; // Helper function to determine if we need batch processing
3701
+ needsBatchProcessing = function needsBatchProcessing() {
3702
+ var currentType = currentField.Type.toLowerCase();
3703
+ var newType = field.Type.toLowerCase();
3704
+
3705
+ // Decimal changes
3706
+ if (currentType.includes('decimal') && newType.includes('decimal')) {
3707
+ return true;
3708
+ }
3709
+
3710
+ // VARCHAR/CHAR length reductions
3711
+ if ((currentType.includes('varchar') || currentType.includes('char')) && (newType.includes('varchar') || newType.includes('char'))) {
3712
+ var _currentType$match, _newType$match;
3713
+ var currentLength = parseInt(((_currentType$match = currentType.match(/\((\d+)\)/)) === null || _currentType$match === undefined ? undefined : _currentType$match[1]) || '0');
3714
+ var newLength = parseInt(((_newType$match = newType.match(/\((\d+)\)/)) === null || _newType$match === undefined ? undefined : _newType$match[1]) || '0');
3715
+ return newLength < currentLength;
3716
+ }
3717
+
3718
+ // TEXT to VARCHAR conversions
3719
+ if (currentType.includes('text') && newType.includes('varchar')) {
3720
+ return true;
3721
+ }
3722
+
3723
+ // Numeric type downgrades
3724
+ var numericDowngrades = {
3725
+ 'bigint': ['int', 'mediumint', 'smallint', 'tinyint'],
3726
+ 'int': ['mediumint', 'smallint', 'tinyint'],
3727
+ 'mediumint': ['smallint', 'tinyint'],
3728
+ 'smallint': ['tinyint'],
3729
+ 'double': ['float', 'decimal'],
3730
+ 'float': ['decimal']
3731
+ };
3732
+ for (var _i = 0, _Object$entries = Object.entries(numericDowngrades); _i < _Object$entries.length; _i++) {
3733
+ var _Object$entries$_i = _slicedToArray(_Object$entries[_i], 2),
3734
+ larger = _Object$entries$_i[0],
3735
+ smaller = _Object$entries$_i[1];
3736
+ if (currentType.includes(larger) && smaller.some(function (t) {
3737
+ return newType.includes(t);
3738
+ })) {
3739
+ return true;
3740
+ }
3741
+ }
3742
+ return false;
3743
+ };
3744
+ if (!needsBatchProcessing()) {
3745
+ _context.next = 90;
3746
+ break;
3747
+ }
3748
+ // Step 1: Add new column
3749
+ addColumnSQL = "ALTER TABLE `".concat(_tableName2, "` ADD COLUMN `").concat(field.Field, "_new` ").concat(field.Type, " DEFAULT NULL;");
3750
+ logger("Adding new column for type conversion: ".concat(addColumnSQL));
3751
+ _context.next = 60;
3752
+ return connection.query(addColumnSQL);
3753
+ case 60:
3754
+ // Step 2: Copy data in batches
3755
+ totalUpdated = 0;
3756
+ batchSize = 10000;
3757
+ batchCount = 0;
3758
+ case 63:
3759
+ updateSQL = "\n UPDATE `".concat(_tableName2, "` \n SET `").concat(field.Field, "_new` = `").concat(field.Field, "`\n WHERE `").concat(field.Field, "_new` IS NULL \n AND `").concat(field.Field, "` IS NOT NULL\n LIMIT ").concat(batchSize, ";\n ");
3760
+ _context.next = 67;
3761
+ return connection.query(updateSQL);
3762
+ case 67:
3763
+ result = _context.sent;
3764
+ rowsAffected = result.affectedRows;
3765
+ if (!(rowsAffected === 0)) {
3766
+ _context.next = 71;
3767
+ break;
3768
+ }
3769
+ return _context.abrupt("break", 76);
3770
+ case 71:
3771
+ totalUpdated += rowsAffected;
3772
+ batchCount++;
3773
+ logger("Batch ".concat(batchCount, ": Converted ").concat(rowsAffected, " rows. Total converted: ").concat(totalUpdated));
3774
+ _context.next = 63;
3775
+ break;
3776
+ case 76:
3777
+ // Step 3: Verify data (optional)
3778
+ verifySQL = "\n SELECT COUNT(*) as mismatch FROM `".concat(_tableName2, "`\n WHERE `").concat(field.Field, "` IS NOT NULL \n AND `").concat(field.Field, "_new` IS NULL;\n ");
3779
+ _context.next = 79;
3780
+ return connection.query(verifySQL);
3781
+ case 79:
3782
+ _yield$connection$que = _context.sent;
3783
+ _yield$connection$que2 = _slicedToArray(_yield$connection$que, 1);
3784
+ verifyResult = _yield$connection$que2[0];
3785
+ if (verifyResult.mismatch > 0) {
3786
+ logger("Warning: ".concat(verifyResult.mismatch, " rows may have failed conversion"));
3787
+ }
3788
+
3789
+ // Step 4: Swap columns
3790
+ swapColumnsSQL = "\n ALTER TABLE `".concat(_tableName2, "`\n DROP COLUMN `").concat(field.Field, "`,\n RENAME COLUMN `").concat(field.Field, "_new` TO `").concat(field.Field, "`\n ");
3791
+ logger("Swapping columns: ".concat(swapColumnsSQL));
3792
+ _context.next = 87;
3793
+ return connection.query(swapColumnsSQL);
3794
+ case 87:
3795
+ logger("Completed type conversion for ".concat(field.Field, ". Total rows converted: ").concat(totalUpdated));
3796
+ _context.next = 98;
3705
3797
  break;
3706
- case 61:
3798
+ case 90:
3799
+ // Original mismatched field handling for simple changes
3800
+ isTimestamp = field.Type.toLowerCase().includes('timestamp'); // Handle timestamp specific attributes
3801
+ _defaultClause = field.Default === 'CURRENT_TIMESTAMP' ? 'DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP' : field.Default === 'NULL' ? isTimestamp ? 'NULL DEFAULT NULL' : 'DEFAULT NULL' : field.Default !== undefined && field.Default !== null ? "DEFAULT '".concat(field.Default, "'") : isTimestamp ? 'NULL DEFAULT NULL' : 'DEFAULT NULL'; // Remove ON UPDATE CURRENT_TIMESTAMP if we're changing away from CURRENT_TIMESTAMP
3802
+ _currentField = diff.currentField;
3803
+ hasOnUpdate = (_currentField === null || _currentField === undefined ? undefined : _currentField.Default) === 'CURRENT_TIMESTAMP' && field.Default !== 'CURRENT_TIMESTAMP';
3804
+ _modifyFieldSQL2 = "ALTER TABLE `".concat(_tableName2, "` CHANGE `").concat(field.Field, "` `").concat(field.Field, "` ").concat(field.Type, " ").concat(field.NotNull ? 'NOT NULL' : '', " ").concat(_defaultClause).concat(hasOnUpdate ? ' ON UPDATE CURRENT_TIMESTAMP' : '', ";");
3805
+ console.log("Executing: ".concat(_modifyFieldSQL2));
3806
+ _context.next = 98;
3807
+ return connection.query(_modifyFieldSQL2);
3808
+ case 98:
3809
+ _context.next = 249;
3810
+ break;
3811
+ case 100:
3707
3812
  if (!(diff.type === 'missing_index')) {
3708
- _context.next = 93;
3813
+ _context.next = 132;
3709
3814
  break;
3710
3815
  }
3711
- _context.next = 64;
3816
+ _context.next = 103;
3712
3817
  return connection.query("SHOW COLUMNS FROM `".concat(diff.tableName, "`"));
3713
- case 64:
3818
+ case 103:
3714
3819
  existingColumns = _context.sent;
3715
3820
  columnNames = existingColumns.map(function (col) {
3716
3821
  return col.Field;
@@ -3719,260 +3824,260 @@ var applyDifferences = /*#__PURE__*/function () {
3719
3824
  return !columnNames.includes(col);
3720
3825
  }) : [];
3721
3826
  if (!(missingColumns.length > 0)) {
3722
- _context.next = 70;
3827
+ _context.next = 109;
3723
3828
  break;
3724
3829
  }
3725
3830
  logger("Cannot create index ".concat(diff.index.Name, " on ").concat(diff.tableName, ". Missing columns: ").concat(missingColumns.join(', ')));
3726
3831
  return _context.abrupt("return", 0);
3727
- case 70:
3832
+ case 109:
3728
3833
  // Prepare the index columns with proper formatting
3729
3834
  indexColumns = diff.index.ColumnName.map(function (col) {
3730
3835
  return "`".concat(col, "`");
3731
3836
  }); // Format column names
3732
3837
  // Handle PRIMARY index creation
3733
3838
  if (!(diff.index.Name === 'PRIMARY')) {
3734
- _context.next = 82;
3839
+ _context.next = 121;
3735
3840
  break;
3736
3841
  }
3737
3842
  if (!(indexColumns.length > 0)) {
3738
- _context.next = 79;
3843
+ _context.next = 118;
3739
3844
  break;
3740
3845
  }
3741
3846
  primaryKeySQL = "ALTER TABLE `".concat(diff.tableName, "` ADD PRIMARY KEY (").concat(indexColumns.join(', '), ");");
3742
3847
  console.log("Executing: ".concat(primaryKeySQL));
3743
- _context.next = 77;
3848
+ _context.next = 116;
3744
3849
  return connection.query(primaryKeySQL);
3745
- case 77:
3746
- _context.next = 80;
3850
+ case 116:
3851
+ _context.next = 119;
3747
3852
  break;
3748
- case 79:
3853
+ case 118:
3749
3854
  logger("Cannot create PRIMARY index on ".concat(diff.tableName, ". ColumnName is undefined or empty."), diff.index);
3750
- case 80:
3751
- _context.next = 91;
3855
+ case 119:
3856
+ _context.next = 130;
3752
3857
  break;
3753
- case 82:
3858
+ case 121:
3754
3859
  // Create the new index with UNIQUE if applicable
3755
3860
  uniqueSQL = diff.index.Unique ? 'UNIQUE ' : ''; // Check if the index is unique
3756
3861
  if (!(indexColumns.length > 0)) {
3757
- _context.next = 90;
3862
+ _context.next = 129;
3758
3863
  break;
3759
3864
  }
3760
3865
  addIndexSQL = "ALTER TABLE `".concat(diff.tableName, "` ADD ").concat(uniqueSQL, "INDEX `").concat(diff.index.Name, "` (").concat(indexColumns.join(', '), ");");
3761
3866
  console.log("Executing: ".concat(addIndexSQL));
3762
- _context.next = 88;
3867
+ _context.next = 127;
3763
3868
  return connection.query(addIndexSQL);
3764
- case 88:
3765
- _context.next = 91;
3869
+ case 127:
3870
+ _context.next = 130;
3766
3871
  break;
3767
- case 90:
3872
+ case 129:
3768
3873
  logger("Cannot create index ".concat(diff.index.Name, " on ").concat(diff.tableName, ". ColumnName is undefined or empty."), diff.index);
3769
- case 91:
3770
- _context.next = 210;
3874
+ case 130:
3875
+ _context.next = 249;
3771
3876
  break;
3772
- case 93:
3877
+ case 132:
3773
3878
  if (!(diff.type === 'extra_index')) {
3774
- _context.next = 107;
3879
+ _context.next = 146;
3775
3880
  break;
3776
3881
  }
3777
3882
  if (!(diff.index.Name === 'PRIMARY')) {
3778
- _context.next = 101;
3883
+ _context.next = 140;
3779
3884
  break;
3780
3885
  }
3781
3886
  dropPrimaryKeySQL = "ALTER TABLE `".concat(diff.tableName, "` DROP PRIMARY KEY;");
3782
3887
  console.log("Executing: ".concat(dropPrimaryKeySQL));
3783
- _context.next = 99;
3888
+ _context.next = 138;
3784
3889
  return connection.query(dropPrimaryKeySQL);
3785
- case 99:
3786
- _context.next = 105;
3890
+ case 138:
3891
+ _context.next = 144;
3787
3892
  break;
3788
- case 101:
3893
+ case 140:
3789
3894
  dropIndexSQL = "DROP INDEX `".concat(diff.index.Name, "` ON `").concat(diff.tableName, "`;");
3790
3895
  console.log("Executing: ".concat(dropIndexSQL));
3791
- _context.next = 105;
3896
+ _context.next = 144;
3792
3897
  return connection.query(dropIndexSQL);
3793
- case 105:
3794
- _context.next = 210;
3898
+ case 144:
3899
+ _context.next = 249;
3795
3900
  break;
3796
- case 107:
3901
+ case 146:
3797
3902
  if (!(diff.type === 'mismatched_index')) {
3798
- _context.next = 135;
3903
+ _context.next = 174;
3799
3904
  break;
3800
3905
  }
3801
3906
  _tableName3 = diff.tableName, index = diff.index; // Drop the existing index
3802
3907
  if (!(index.Name === 'PRIMARY')) {
3803
- _context.next = 116;
3908
+ _context.next = 155;
3804
3909
  break;
3805
3910
  }
3806
3911
  _dropPrimaryKeySQL = "ALTER TABLE `".concat(_tableName3, "` DROP PRIMARY KEY;");
3807
3912
  console.log("Executing: ".concat(_dropPrimaryKeySQL));
3808
- _context.next = 114;
3913
+ _context.next = 153;
3809
3914
  return connection.query(_dropPrimaryKeySQL);
3810
- case 114:
3811
- _context.next = 120;
3915
+ case 153:
3916
+ _context.next = 159;
3812
3917
  break;
3813
- case 116:
3918
+ case 155:
3814
3919
  _dropIndexSQL = "DROP INDEX `".concat(index.Name, "` ON `").concat(_tableName3, "`;");
3815
3920
  console.log("Executing: ".concat(_dropIndexSQL));
3816
- _context.next = 120;
3921
+ _context.next = 159;
3817
3922
  return connection.query(_dropIndexSQL);
3818
- case 120:
3923
+ case 159:
3819
3924
  console.log('index', index);
3820
3925
 
3821
3926
  // Create the new index
3822
3927
  _uniqueSQL = index.Unique ? 'UNIQUE ' : ''; // Check if the index is unique
3823
3928
  if (!(index.Name === 'PRIMARY')) {
3824
- _context.next = 129;
3929
+ _context.next = 168;
3825
3930
  break;
3826
3931
  }
3827
3932
  addPrimaryKeySQL = "ALTER TABLE `".concat(_tableName3, "` ADD PRIMARY KEY (").concat(index.ColumnName.join(', '), ");");
3828
3933
  console.log("Executing: ".concat(addPrimaryKeySQL));
3829
- _context.next = 127;
3934
+ _context.next = 166;
3830
3935
  return connection.query(addPrimaryKeySQL);
3831
- case 127:
3832
- _context.next = 133;
3936
+ case 166:
3937
+ _context.next = 172;
3833
3938
  break;
3834
- case 129:
3939
+ case 168:
3835
3940
  _addIndexSQL = "ALTER TABLE `".concat(_tableName3, "` ADD ").concat(_uniqueSQL, "INDEX `").concat(index.Name, "` (").concat(index.ColumnName.join(', '), ");"); // Include UNIQUE if applicable
3836
3941
  console.log("Executing: ".concat(_addIndexSQL));
3837
- _context.next = 133;
3942
+ _context.next = 172;
3838
3943
  return connection.query(_addIndexSQL);
3839
- case 133:
3840
- _context.next = 210;
3944
+ case 172:
3945
+ _context.next = 249;
3841
3946
  break;
3842
- case 135:
3947
+ case 174:
3843
3948
  if (!(diff.type === 'missing_procedure' || diff.type === 'mismatched_procedure')) {
3844
- _context.next = 146;
3949
+ _context.next = 185;
3845
3950
  break;
3846
3951
  }
3847
3952
  // Drop the procedure if it exists
3848
3953
  dropCurrentProcSQL = "DROP PROCEDURE IF EXISTS `".concat(diff.Name, "`;");
3849
3954
  console.log("Executing: ".concat(dropCurrentProcSQL));
3850
- _context.next = 140;
3955
+ _context.next = 179;
3851
3956
  return connection.query(dropCurrentProcSQL);
3852
- case 140:
3957
+ case 179:
3853
3958
  // Create the procedure
3854
3959
  createProcSQL = diff.Definition;
3855
3960
  console.log("Executing: ".concat(createProcSQL)); // Log the SQL statement
3856
- _context.next = 144;
3961
+ _context.next = 183;
3857
3962
  return connection.query(createProcSQL);
3858
- case 144:
3859
- _context.next = 210;
3963
+ case 183:
3964
+ _context.next = 249;
3860
3965
  break;
3861
- case 146:
3966
+ case 185:
3862
3967
  if (!(diff.type === 'missing_view')) {
3863
- _context.next = 157;
3968
+ _context.next = 196;
3864
3969
  break;
3865
3970
  }
3866
3971
  dropViewSQL = "DROP VIEW IF EXISTS `".concat(diff.viewName, "`;");
3867
3972
  console.log("Executing: ".concat(dropViewSQL));
3868
- _context.next = 151;
3973
+ _context.next = 190;
3869
3974
  return connection.query(dropViewSQL);
3870
- case 151:
3975
+ case 190:
3871
3976
  createViewSQL = diff.definition; // Use the expected definition to create the view
3872
3977
  console.log("Executing: ".concat(createViewSQL));
3873
- _context.next = 155;
3978
+ _context.next = 194;
3874
3979
  return connection.query(createViewSQL);
3875
- case 155:
3876
- _context.next = 210;
3980
+ case 194:
3981
+ _context.next = 249;
3877
3982
  break;
3878
- case 157:
3983
+ case 196:
3879
3984
  if (!(diff.type === 'mismatched_view')) {
3880
- _context.next = 168;
3985
+ _context.next = 207;
3881
3986
  break;
3882
3987
  }
3883
3988
  _dropViewSQL = "DROP VIEW IF EXISTS `".concat(diff.viewName, "`;");
3884
3989
  console.log("Executing: ".concat(_dropViewSQL));
3885
- _context.next = 162;
3990
+ _context.next = 201;
3886
3991
  return connection.query(_dropViewSQL);
3887
- case 162:
3992
+ case 201:
3888
3993
  _createViewSQL = diff.definition; // Use the expected definition to create the view
3889
3994
  console.log("Executing: ".concat(_createViewSQL));
3890
- _context.next = 166;
3995
+ _context.next = 205;
3891
3996
  return connection.query(_createViewSQL);
3892
- case 166:
3893
- _context.next = 210;
3997
+ case 205:
3998
+ _context.next = 249;
3894
3999
  break;
3895
- case 168:
4000
+ case 207:
3896
4001
  if (!(diff.type === 'extra_view')) {
3897
- _context.next = 175;
4002
+ _context.next = 214;
3898
4003
  break;
3899
4004
  }
3900
4005
  _dropViewSQL2 = "DROP VIEW IF EXISTS `".concat(diff.viewName, "`;");
3901
4006
  console.log("Executing: ".concat(_dropViewSQL2));
3902
- _context.next = 173;
4007
+ _context.next = 212;
3903
4008
  return connection.query(_dropViewSQL2);
3904
- case 173:
3905
- _context.next = 210;
4009
+ case 212:
4010
+ _context.next = 249;
3906
4011
  break;
3907
- case 175:
4012
+ case 214:
3908
4013
  if (!(diff.type === 'missing_trigger')) {
3909
- _context.next = 183;
4014
+ _context.next = 222;
3910
4015
  break;
3911
4016
  }
3912
4017
  createTriggerSQL = diff.trigger.Definition;
3913
4018
  logger('fixing trigger', diff.trigger.Name);
3914
4019
  console.log("Executing: ".concat(createTriggerSQL));
3915
- _context.next = 181;
4020
+ _context.next = 220;
3916
4021
  return connection.query(createTriggerSQL);
3917
- case 181:
3918
- _context.next = 210;
4022
+ case 220:
4023
+ _context.next = 249;
3919
4024
  break;
3920
- case 183:
4025
+ case 222:
3921
4026
  if (!(diff.type === 'mismatched_trigger')) {
3922
- _context.next = 194;
4027
+ _context.next = 233;
3923
4028
  break;
3924
4029
  }
3925
4030
  dropTriggerSQL = "DROP TRIGGER IF EXISTS `".concat(diff.trigger.Name, "`;");
3926
4031
  console.log("Executing: ".concat(dropTriggerSQL));
3927
- _context.next = 188;
4032
+ _context.next = 227;
3928
4033
  return connection.query(dropTriggerSQL);
3929
- case 188:
4034
+ case 227:
3930
4035
  _createTriggerSQL = diff.trigger.Definition;
3931
4036
  console.log("Executing: ".concat(_createTriggerSQL));
3932
- _context.next = 192;
4037
+ _context.next = 231;
3933
4038
  return connection.query(_createTriggerSQL);
3934
- case 192:
3935
- _context.next = 210;
4039
+ case 231:
4040
+ _context.next = 249;
3936
4041
  break;
3937
- case 194:
4042
+ case 233:
3938
4043
  if (!(diff.type === 'extra_trigger')) {
3939
- _context.next = 201;
4044
+ _context.next = 240;
3940
4045
  break;
3941
4046
  }
3942
4047
  _dropTriggerSQL = "DROP TRIGGER IF EXISTS `".concat(diff.trigger.Name, "`;");
3943
4048
  console.log("Executing: ".concat(_dropTriggerSQL));
3944
- _context.next = 199;
4049
+ _context.next = 238;
3945
4050
  return connection.query(_dropTriggerSQL);
3946
- case 199:
3947
- _context.next = 210;
4051
+ case 238:
4052
+ _context.next = 249;
3948
4053
  break;
3949
- case 201:
4054
+ case 240:
3950
4055
  if (!(diff.type === 'missing_database')) {
3951
- _context.next = 209;
4056
+ _context.next = 248;
3952
4057
  break;
3953
4058
  }
3954
4059
  logger('fixing missing database', diff.database);
3955
4060
  _createDatabaseSQL = "CREATE DATABASE `".concat(diff.database, "`;");
3956
4061
  console.log("Executing: ".concat(_createDatabaseSQL));
3957
- _context.next = 207;
4062
+ _context.next = 246;
3958
4063
  return connection.query(_createDatabaseSQL);
3959
- case 207:
3960
- _context.next = 210;
4064
+ case 246:
4065
+ _context.next = 249;
3961
4066
  break;
3962
- case 209:
4067
+ case 248:
3963
4068
  logger("Error applying difference of type:".concat(diff.type), diff);
3964
- case 210:
3965
- _context.next = 215;
4069
+ case 249:
4070
+ _context.next = 254;
3966
4071
  break;
3967
- case 212:
3968
- _context.prev = 212;
4072
+ case 251:
4073
+ _context.prev = 251;
3969
4074
  _context.t0 = _context["catch"](1);
3970
4075
  logger("Error applying difference of type:".concat(diff.type, ". Error: ").concat(_context.t0.message), diff);
3971
- case 215:
4076
+ case 254:
3972
4077
  case "end":
3973
4078
  return _context.stop();
3974
4079
  }
3975
- }, _loop, null, [[1, 212]]);
4080
+ }, _loop, null, [[1, 251]]);
3976
4081
  });
3977
4082
  _iterator.s();
3978
4083
  case 5:
package/dist/index.js CHANGED
@@ -134,7 +134,10 @@ function _iterableToArrayLimit(r, l) {
134
134
  f = true,
135
135
  o = false;
136
136
  try {
137
- if (i = (t = t.call(r)).next, 0 === l) ; else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0);
137
+ if (i = (t = t.call(r)).next, 0 === l) {
138
+ if (Object(t) !== t) return;
139
+ f = !1;
140
+ } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0);
138
141
  } catch (r) {
139
142
  o = true, n = r;
140
143
  } finally {
@@ -3596,7 +3599,7 @@ var applyDifferences = /*#__PURE__*/function () {
3596
3599
  _iterator = _createForOfIteratorHelper(differences);
3597
3600
  _context2.prev = 2;
3598
3601
  _loop = /*#__PURE__*/_regeneratorRuntime().mark(function _loop() {
3599
- var diff, createDatabaseSQL, tableName, createSQL, _tableName, dropTableSQL, addFieldSQL, modifyFieldSQL, defaultClause, _modifyFieldSQL, dropFieldSQL, _tableName2, field, _defaultClause, _dropFieldSQL, existingColumns, columnNames, missingColumns, indexColumns, primaryKeySQL, uniqueSQL, addIndexSQL, dropPrimaryKeySQL, dropIndexSQL, _tableName3, index, _dropPrimaryKeySQL, _dropIndexSQL, _uniqueSQL, addPrimaryKeySQL, _addIndexSQL, dropCurrentProcSQL, createProcSQL, dropViewSQL, createViewSQL, _dropViewSQL, _createViewSQL, _dropViewSQL2, createTriggerSQL, dropTriggerSQL, _createTriggerSQL, _dropTriggerSQL, _createDatabaseSQL;
3602
+ var diff, createDatabaseSQL, tableName, createSQL, _tableName, dropTableSQL, addFieldSQL, modifyFieldSQL, defaultClause, _modifyFieldSQL, dropFieldSQL, _tableName2, field, currentField, needsBatchProcessing, addColumnSQL, totalUpdated, batchSize, batchCount, updateSQL, result, rowsAffected, verifySQL, _yield$connection$que, _yield$connection$que2, verifyResult, swapColumnsSQL, isTimestamp, _defaultClause, _currentField, hasOnUpdate, _modifyFieldSQL2, existingColumns, columnNames, missingColumns, indexColumns, primaryKeySQL, uniqueSQL, addIndexSQL, dropPrimaryKeySQL, dropIndexSQL, _tableName3, index, _dropPrimaryKeySQL, _dropIndexSQL, _uniqueSQL, addPrimaryKeySQL, _addIndexSQL, dropCurrentProcSQL, createProcSQL, dropViewSQL, createViewSQL, _dropViewSQL, _createViewSQL, _dropViewSQL2, createTriggerSQL, dropTriggerSQL, _createTriggerSQL, _dropTriggerSQL, _createDatabaseSQL;
3600
3603
  return _regeneratorRuntime().wrap(function _loop$(_context) {
3601
3604
  while (1) switch (_context.prev = _context.next) {
3602
3605
  case 0:
@@ -3626,7 +3629,7 @@ var applyDifferences = /*#__PURE__*/function () {
3626
3629
  _context.next = 16;
3627
3630
  return connection.query(createSQL);
3628
3631
  case 16:
3629
- _context.next = 210;
3632
+ _context.next = 249;
3630
3633
  break;
3631
3634
  case 18:
3632
3635
  if (!(diff.type === 'extra_table')) {
@@ -3640,7 +3643,7 @@ var applyDifferences = /*#__PURE__*/function () {
3640
3643
  _context.next = 25;
3641
3644
  return connection.query(dropTableSQL);
3642
3645
  case 25:
3643
- _context.next = 210;
3646
+ _context.next = 249;
3644
3647
  break;
3645
3648
  case 27:
3646
3649
  if (!(diff.type === 'missing_field')) {
@@ -3672,7 +3675,7 @@ var applyDifferences = /*#__PURE__*/function () {
3672
3675
  _context.next = 43;
3673
3676
  return connection.query(_modifyFieldSQL);
3674
3677
  case 43:
3675
- _context.next = 210;
3678
+ _context.next = 249;
3676
3679
  break;
3677
3680
  case 45:
3678
3681
  if (!(diff.type === 'extra_field')) {
@@ -3684,30 +3687,132 @@ var applyDifferences = /*#__PURE__*/function () {
3684
3687
  _context.next = 50;
3685
3688
  return connection.query(dropFieldSQL);
3686
3689
  case 50:
3687
- _context.next = 210;
3690
+ _context.next = 249;
3688
3691
  break;
3689
3692
  case 52:
3690
3693
  if (!(diff.type === 'mismatched_field')) {
3691
- _context.next = 61;
3694
+ _context.next = 100;
3692
3695
  break;
3693
3696
  }
3694
- _tableName2 = diff.tableName, field = diff.field;
3695
- _defaultClause = field.Default === 'CURRENT_TIMESTAMP' ? 'DEFAULT CURRENT_TIMESTAMP' : field.Default === 'NULL' ? 'DEFAULT NULL' : field.Default !== undefined && field.Default !== null ? "DEFAULT '".concat(field.Default, "'") : 'DEFAULT NULL';
3696
- _dropFieldSQL = "ALTER TABLE `".concat(_tableName2, "` CHANGE `").concat(field.Field, "` `").concat(field.Field, "` ").concat(field.Type, " ").concat(field.NotNull ? 'NOT NULL' : '', " ").concat(_defaultClause, ";");
3697
- console.log("Executing: ".concat(_dropFieldSQL));
3698
- _context.next = 59;
3699
- return connection.query(_dropFieldSQL);
3700
- case 59:
3701
- _context.next = 210;
3697
+ _tableName2 = diff.tableName, field = diff.field, currentField = diff.currentField; // Helper function to determine if we need batch processing
3698
+ needsBatchProcessing = function needsBatchProcessing() {
3699
+ var currentType = currentField.Type.toLowerCase();
3700
+ var newType = field.Type.toLowerCase();
3701
+
3702
+ // Decimal changes
3703
+ if (currentType.includes('decimal') && newType.includes('decimal')) {
3704
+ return true;
3705
+ }
3706
+
3707
+ // VARCHAR/CHAR length reductions
3708
+ if ((currentType.includes('varchar') || currentType.includes('char')) && (newType.includes('varchar') || newType.includes('char'))) {
3709
+ var _currentType$match, _newType$match;
3710
+ var currentLength = parseInt(((_currentType$match = currentType.match(/\((\d+)\)/)) === null || _currentType$match === undefined ? undefined : _currentType$match[1]) || '0');
3711
+ var newLength = parseInt(((_newType$match = newType.match(/\((\d+)\)/)) === null || _newType$match === undefined ? undefined : _newType$match[1]) || '0');
3712
+ return newLength < currentLength;
3713
+ }
3714
+
3715
+ // TEXT to VARCHAR conversions
3716
+ if (currentType.includes('text') && newType.includes('varchar')) {
3717
+ return true;
3718
+ }
3719
+
3720
+ // Numeric type downgrades
3721
+ var numericDowngrades = {
3722
+ 'bigint': ['int', 'mediumint', 'smallint', 'tinyint'],
3723
+ 'int': ['mediumint', 'smallint', 'tinyint'],
3724
+ 'mediumint': ['smallint', 'tinyint'],
3725
+ 'smallint': ['tinyint'],
3726
+ 'double': ['float', 'decimal'],
3727
+ 'float': ['decimal']
3728
+ };
3729
+ for (var _i = 0, _Object$entries = Object.entries(numericDowngrades); _i < _Object$entries.length; _i++) {
3730
+ var _Object$entries$_i = _slicedToArray(_Object$entries[_i], 2),
3731
+ larger = _Object$entries$_i[0],
3732
+ smaller = _Object$entries$_i[1];
3733
+ if (currentType.includes(larger) && smaller.some(function (t) {
3734
+ return newType.includes(t);
3735
+ })) {
3736
+ return true;
3737
+ }
3738
+ }
3739
+ return false;
3740
+ };
3741
+ if (!needsBatchProcessing()) {
3742
+ _context.next = 90;
3743
+ break;
3744
+ }
3745
+ // Step 1: Add new column
3746
+ addColumnSQL = "ALTER TABLE `".concat(_tableName2, "` ADD COLUMN `").concat(field.Field, "_new` ").concat(field.Type, " DEFAULT NULL;");
3747
+ logger("Adding new column for type conversion: ".concat(addColumnSQL));
3748
+ _context.next = 60;
3749
+ return connection.query(addColumnSQL);
3750
+ case 60:
3751
+ // Step 2: Copy data in batches
3752
+ totalUpdated = 0;
3753
+ batchSize = 10000;
3754
+ batchCount = 0;
3755
+ case 63:
3756
+ updateSQL = "\n UPDATE `".concat(_tableName2, "` \n SET `").concat(field.Field, "_new` = `").concat(field.Field, "`\n WHERE `").concat(field.Field, "_new` IS NULL \n AND `").concat(field.Field, "` IS NOT NULL\n LIMIT ").concat(batchSize, ";\n ");
3757
+ _context.next = 67;
3758
+ return connection.query(updateSQL);
3759
+ case 67:
3760
+ result = _context.sent;
3761
+ rowsAffected = result.affectedRows;
3762
+ if (!(rowsAffected === 0)) {
3763
+ _context.next = 71;
3764
+ break;
3765
+ }
3766
+ return _context.abrupt("break", 76);
3767
+ case 71:
3768
+ totalUpdated += rowsAffected;
3769
+ batchCount++;
3770
+ logger("Batch ".concat(batchCount, ": Converted ").concat(rowsAffected, " rows. Total converted: ").concat(totalUpdated));
3771
+ _context.next = 63;
3772
+ break;
3773
+ case 76:
3774
+ // Step 3: Verify data (optional)
3775
+ verifySQL = "\n SELECT COUNT(*) as mismatch FROM `".concat(_tableName2, "`\n WHERE `").concat(field.Field, "` IS NOT NULL \n AND `").concat(field.Field, "_new` IS NULL;\n ");
3776
+ _context.next = 79;
3777
+ return connection.query(verifySQL);
3778
+ case 79:
3779
+ _yield$connection$que = _context.sent;
3780
+ _yield$connection$que2 = _slicedToArray(_yield$connection$que, 1);
3781
+ verifyResult = _yield$connection$que2[0];
3782
+ if (verifyResult.mismatch > 0) {
3783
+ logger("Warning: ".concat(verifyResult.mismatch, " rows may have failed conversion"));
3784
+ }
3785
+
3786
+ // Step 4: Swap columns
3787
+ swapColumnsSQL = "\n ALTER TABLE `".concat(_tableName2, "`\n DROP COLUMN `").concat(field.Field, "`,\n RENAME COLUMN `").concat(field.Field, "_new` TO `").concat(field.Field, "`\n ");
3788
+ logger("Swapping columns: ".concat(swapColumnsSQL));
3789
+ _context.next = 87;
3790
+ return connection.query(swapColumnsSQL);
3791
+ case 87:
3792
+ logger("Completed type conversion for ".concat(field.Field, ". Total rows converted: ").concat(totalUpdated));
3793
+ _context.next = 98;
3702
3794
  break;
3703
- case 61:
3795
+ case 90:
3796
+ // Original mismatched field handling for simple changes
3797
+ isTimestamp = field.Type.toLowerCase().includes('timestamp'); // Handle timestamp specific attributes
3798
+ _defaultClause = field.Default === 'CURRENT_TIMESTAMP' ? 'DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP' : field.Default === 'NULL' ? isTimestamp ? 'NULL DEFAULT NULL' : 'DEFAULT NULL' : field.Default !== undefined && field.Default !== null ? "DEFAULT '".concat(field.Default, "'") : isTimestamp ? 'NULL DEFAULT NULL' : 'DEFAULT NULL'; // Remove ON UPDATE CURRENT_TIMESTAMP if we're changing away from CURRENT_TIMESTAMP
3799
+ _currentField = diff.currentField;
3800
+ hasOnUpdate = (_currentField === null || _currentField === undefined ? undefined : _currentField.Default) === 'CURRENT_TIMESTAMP' && field.Default !== 'CURRENT_TIMESTAMP';
3801
+ _modifyFieldSQL2 = "ALTER TABLE `".concat(_tableName2, "` CHANGE `").concat(field.Field, "` `").concat(field.Field, "` ").concat(field.Type, " ").concat(field.NotNull ? 'NOT NULL' : '', " ").concat(_defaultClause).concat(hasOnUpdate ? ' ON UPDATE CURRENT_TIMESTAMP' : '', ";");
3802
+ console.log("Executing: ".concat(_modifyFieldSQL2));
3803
+ _context.next = 98;
3804
+ return connection.query(_modifyFieldSQL2);
3805
+ case 98:
3806
+ _context.next = 249;
3807
+ break;
3808
+ case 100:
3704
3809
  if (!(diff.type === 'missing_index')) {
3705
- _context.next = 93;
3810
+ _context.next = 132;
3706
3811
  break;
3707
3812
  }
3708
- _context.next = 64;
3813
+ _context.next = 103;
3709
3814
  return connection.query("SHOW COLUMNS FROM `".concat(diff.tableName, "`"));
3710
- case 64:
3815
+ case 103:
3711
3816
  existingColumns = _context.sent;
3712
3817
  columnNames = existingColumns.map(function (col) {
3713
3818
  return col.Field;
@@ -3716,260 +3821,260 @@ var applyDifferences = /*#__PURE__*/function () {
3716
3821
  return !columnNames.includes(col);
3717
3822
  }) : [];
3718
3823
  if (!(missingColumns.length > 0)) {
3719
- _context.next = 70;
3824
+ _context.next = 109;
3720
3825
  break;
3721
3826
  }
3722
3827
  logger("Cannot create index ".concat(diff.index.Name, " on ").concat(diff.tableName, ". Missing columns: ").concat(missingColumns.join(', ')));
3723
3828
  return _context.abrupt("return", 0);
3724
- case 70:
3829
+ case 109:
3725
3830
  // Prepare the index columns with proper formatting
3726
3831
  indexColumns = diff.index.ColumnName.map(function (col) {
3727
3832
  return "`".concat(col, "`");
3728
3833
  }); // Format column names
3729
3834
  // Handle PRIMARY index creation
3730
3835
  if (!(diff.index.Name === 'PRIMARY')) {
3731
- _context.next = 82;
3836
+ _context.next = 121;
3732
3837
  break;
3733
3838
  }
3734
3839
  if (!(indexColumns.length > 0)) {
3735
- _context.next = 79;
3840
+ _context.next = 118;
3736
3841
  break;
3737
3842
  }
3738
3843
  primaryKeySQL = "ALTER TABLE `".concat(diff.tableName, "` ADD PRIMARY KEY (").concat(indexColumns.join(', '), ");");
3739
3844
  console.log("Executing: ".concat(primaryKeySQL));
3740
- _context.next = 77;
3845
+ _context.next = 116;
3741
3846
  return connection.query(primaryKeySQL);
3742
- case 77:
3743
- _context.next = 80;
3847
+ case 116:
3848
+ _context.next = 119;
3744
3849
  break;
3745
- case 79:
3850
+ case 118:
3746
3851
  logger("Cannot create PRIMARY index on ".concat(diff.tableName, ". ColumnName is undefined or empty."), diff.index);
3747
- case 80:
3748
- _context.next = 91;
3852
+ case 119:
3853
+ _context.next = 130;
3749
3854
  break;
3750
- case 82:
3855
+ case 121:
3751
3856
  // Create the new index with UNIQUE if applicable
3752
3857
  uniqueSQL = diff.index.Unique ? 'UNIQUE ' : ''; // Check if the index is unique
3753
3858
  if (!(indexColumns.length > 0)) {
3754
- _context.next = 90;
3859
+ _context.next = 129;
3755
3860
  break;
3756
3861
  }
3757
3862
  addIndexSQL = "ALTER TABLE `".concat(diff.tableName, "` ADD ").concat(uniqueSQL, "INDEX `").concat(diff.index.Name, "` (").concat(indexColumns.join(', '), ");");
3758
3863
  console.log("Executing: ".concat(addIndexSQL));
3759
- _context.next = 88;
3864
+ _context.next = 127;
3760
3865
  return connection.query(addIndexSQL);
3761
- case 88:
3762
- _context.next = 91;
3866
+ case 127:
3867
+ _context.next = 130;
3763
3868
  break;
3764
- case 90:
3869
+ case 129:
3765
3870
  logger("Cannot create index ".concat(diff.index.Name, " on ").concat(diff.tableName, ". ColumnName is undefined or empty."), diff.index);
3766
- case 91:
3767
- _context.next = 210;
3871
+ case 130:
3872
+ _context.next = 249;
3768
3873
  break;
3769
- case 93:
3874
+ case 132:
3770
3875
  if (!(diff.type === 'extra_index')) {
3771
- _context.next = 107;
3876
+ _context.next = 146;
3772
3877
  break;
3773
3878
  }
3774
3879
  if (!(diff.index.Name === 'PRIMARY')) {
3775
- _context.next = 101;
3880
+ _context.next = 140;
3776
3881
  break;
3777
3882
  }
3778
3883
  dropPrimaryKeySQL = "ALTER TABLE `".concat(diff.tableName, "` DROP PRIMARY KEY;");
3779
3884
  console.log("Executing: ".concat(dropPrimaryKeySQL));
3780
- _context.next = 99;
3885
+ _context.next = 138;
3781
3886
  return connection.query(dropPrimaryKeySQL);
3782
- case 99:
3783
- _context.next = 105;
3887
+ case 138:
3888
+ _context.next = 144;
3784
3889
  break;
3785
- case 101:
3890
+ case 140:
3786
3891
  dropIndexSQL = "DROP INDEX `".concat(diff.index.Name, "` ON `").concat(diff.tableName, "`;");
3787
3892
  console.log("Executing: ".concat(dropIndexSQL));
3788
- _context.next = 105;
3893
+ _context.next = 144;
3789
3894
  return connection.query(dropIndexSQL);
3790
- case 105:
3791
- _context.next = 210;
3895
+ case 144:
3896
+ _context.next = 249;
3792
3897
  break;
3793
- case 107:
3898
+ case 146:
3794
3899
  if (!(diff.type === 'mismatched_index')) {
3795
- _context.next = 135;
3900
+ _context.next = 174;
3796
3901
  break;
3797
3902
  }
3798
3903
  _tableName3 = diff.tableName, index = diff.index; // Drop the existing index
3799
3904
  if (!(index.Name === 'PRIMARY')) {
3800
- _context.next = 116;
3905
+ _context.next = 155;
3801
3906
  break;
3802
3907
  }
3803
3908
  _dropPrimaryKeySQL = "ALTER TABLE `".concat(_tableName3, "` DROP PRIMARY KEY;");
3804
3909
  console.log("Executing: ".concat(_dropPrimaryKeySQL));
3805
- _context.next = 114;
3910
+ _context.next = 153;
3806
3911
  return connection.query(_dropPrimaryKeySQL);
3807
- case 114:
3808
- _context.next = 120;
3912
+ case 153:
3913
+ _context.next = 159;
3809
3914
  break;
3810
- case 116:
3915
+ case 155:
3811
3916
  _dropIndexSQL = "DROP INDEX `".concat(index.Name, "` ON `").concat(_tableName3, "`;");
3812
3917
  console.log("Executing: ".concat(_dropIndexSQL));
3813
- _context.next = 120;
3918
+ _context.next = 159;
3814
3919
  return connection.query(_dropIndexSQL);
3815
- case 120:
3920
+ case 159:
3816
3921
  console.log('index', index);
3817
3922
 
3818
3923
  // Create the new index
3819
3924
  _uniqueSQL = index.Unique ? 'UNIQUE ' : ''; // Check if the index is unique
3820
3925
  if (!(index.Name === 'PRIMARY')) {
3821
- _context.next = 129;
3926
+ _context.next = 168;
3822
3927
  break;
3823
3928
  }
3824
3929
  addPrimaryKeySQL = "ALTER TABLE `".concat(_tableName3, "` ADD PRIMARY KEY (").concat(index.ColumnName.join(', '), ");");
3825
3930
  console.log("Executing: ".concat(addPrimaryKeySQL));
3826
- _context.next = 127;
3931
+ _context.next = 166;
3827
3932
  return connection.query(addPrimaryKeySQL);
3828
- case 127:
3829
- _context.next = 133;
3933
+ case 166:
3934
+ _context.next = 172;
3830
3935
  break;
3831
- case 129:
3936
+ case 168:
3832
3937
  _addIndexSQL = "ALTER TABLE `".concat(_tableName3, "` ADD ").concat(_uniqueSQL, "INDEX `").concat(index.Name, "` (").concat(index.ColumnName.join(', '), ");"); // Include UNIQUE if applicable
3833
3938
  console.log("Executing: ".concat(_addIndexSQL));
3834
- _context.next = 133;
3939
+ _context.next = 172;
3835
3940
  return connection.query(_addIndexSQL);
3836
- case 133:
3837
- _context.next = 210;
3941
+ case 172:
3942
+ _context.next = 249;
3838
3943
  break;
3839
- case 135:
3944
+ case 174:
3840
3945
  if (!(diff.type === 'missing_procedure' || diff.type === 'mismatched_procedure')) {
3841
- _context.next = 146;
3946
+ _context.next = 185;
3842
3947
  break;
3843
3948
  }
3844
3949
  // Drop the procedure if it exists
3845
3950
  dropCurrentProcSQL = "DROP PROCEDURE IF EXISTS `".concat(diff.Name, "`;");
3846
3951
  console.log("Executing: ".concat(dropCurrentProcSQL));
3847
- _context.next = 140;
3952
+ _context.next = 179;
3848
3953
  return connection.query(dropCurrentProcSQL);
3849
- case 140:
3954
+ case 179:
3850
3955
  // Create the procedure
3851
3956
  createProcSQL = diff.Definition;
3852
3957
  console.log("Executing: ".concat(createProcSQL)); // Log the SQL statement
3853
- _context.next = 144;
3958
+ _context.next = 183;
3854
3959
  return connection.query(createProcSQL);
3855
- case 144:
3856
- _context.next = 210;
3960
+ case 183:
3961
+ _context.next = 249;
3857
3962
  break;
3858
- case 146:
3963
+ case 185:
3859
3964
  if (!(diff.type === 'missing_view')) {
3860
- _context.next = 157;
3965
+ _context.next = 196;
3861
3966
  break;
3862
3967
  }
3863
3968
  dropViewSQL = "DROP VIEW IF EXISTS `".concat(diff.viewName, "`;");
3864
3969
  console.log("Executing: ".concat(dropViewSQL));
3865
- _context.next = 151;
3970
+ _context.next = 190;
3866
3971
  return connection.query(dropViewSQL);
3867
- case 151:
3972
+ case 190:
3868
3973
  createViewSQL = diff.definition; // Use the expected definition to create the view
3869
3974
  console.log("Executing: ".concat(createViewSQL));
3870
- _context.next = 155;
3975
+ _context.next = 194;
3871
3976
  return connection.query(createViewSQL);
3872
- case 155:
3873
- _context.next = 210;
3977
+ case 194:
3978
+ _context.next = 249;
3874
3979
  break;
3875
- case 157:
3980
+ case 196:
3876
3981
  if (!(diff.type === 'mismatched_view')) {
3877
- _context.next = 168;
3982
+ _context.next = 207;
3878
3983
  break;
3879
3984
  }
3880
3985
  _dropViewSQL = "DROP VIEW IF EXISTS `".concat(diff.viewName, "`;");
3881
3986
  console.log("Executing: ".concat(_dropViewSQL));
3882
- _context.next = 162;
3987
+ _context.next = 201;
3883
3988
  return connection.query(_dropViewSQL);
3884
- case 162:
3989
+ case 201:
3885
3990
  _createViewSQL = diff.definition; // Use the expected definition to create the view
3886
3991
  console.log("Executing: ".concat(_createViewSQL));
3887
- _context.next = 166;
3992
+ _context.next = 205;
3888
3993
  return connection.query(_createViewSQL);
3889
- case 166:
3890
- _context.next = 210;
3994
+ case 205:
3995
+ _context.next = 249;
3891
3996
  break;
3892
- case 168:
3997
+ case 207:
3893
3998
  if (!(diff.type === 'extra_view')) {
3894
- _context.next = 175;
3999
+ _context.next = 214;
3895
4000
  break;
3896
4001
  }
3897
4002
  _dropViewSQL2 = "DROP VIEW IF EXISTS `".concat(diff.viewName, "`;");
3898
4003
  console.log("Executing: ".concat(_dropViewSQL2));
3899
- _context.next = 173;
4004
+ _context.next = 212;
3900
4005
  return connection.query(_dropViewSQL2);
3901
- case 173:
3902
- _context.next = 210;
4006
+ case 212:
4007
+ _context.next = 249;
3903
4008
  break;
3904
- case 175:
4009
+ case 214:
3905
4010
  if (!(diff.type === 'missing_trigger')) {
3906
- _context.next = 183;
4011
+ _context.next = 222;
3907
4012
  break;
3908
4013
  }
3909
4014
  createTriggerSQL = diff.trigger.Definition;
3910
4015
  logger('fixing trigger', diff.trigger.Name);
3911
4016
  console.log("Executing: ".concat(createTriggerSQL));
3912
- _context.next = 181;
4017
+ _context.next = 220;
3913
4018
  return connection.query(createTriggerSQL);
3914
- case 181:
3915
- _context.next = 210;
4019
+ case 220:
4020
+ _context.next = 249;
3916
4021
  break;
3917
- case 183:
4022
+ case 222:
3918
4023
  if (!(diff.type === 'mismatched_trigger')) {
3919
- _context.next = 194;
4024
+ _context.next = 233;
3920
4025
  break;
3921
4026
  }
3922
4027
  dropTriggerSQL = "DROP TRIGGER IF EXISTS `".concat(diff.trigger.Name, "`;");
3923
4028
  console.log("Executing: ".concat(dropTriggerSQL));
3924
- _context.next = 188;
4029
+ _context.next = 227;
3925
4030
  return connection.query(dropTriggerSQL);
3926
- case 188:
4031
+ case 227:
3927
4032
  _createTriggerSQL = diff.trigger.Definition;
3928
4033
  console.log("Executing: ".concat(_createTriggerSQL));
3929
- _context.next = 192;
4034
+ _context.next = 231;
3930
4035
  return connection.query(_createTriggerSQL);
3931
- case 192:
3932
- _context.next = 210;
4036
+ case 231:
4037
+ _context.next = 249;
3933
4038
  break;
3934
- case 194:
4039
+ case 233:
3935
4040
  if (!(diff.type === 'extra_trigger')) {
3936
- _context.next = 201;
4041
+ _context.next = 240;
3937
4042
  break;
3938
4043
  }
3939
4044
  _dropTriggerSQL = "DROP TRIGGER IF EXISTS `".concat(diff.trigger.Name, "`;");
3940
4045
  console.log("Executing: ".concat(_dropTriggerSQL));
3941
- _context.next = 199;
4046
+ _context.next = 238;
3942
4047
  return connection.query(_dropTriggerSQL);
3943
- case 199:
3944
- _context.next = 210;
4048
+ case 238:
4049
+ _context.next = 249;
3945
4050
  break;
3946
- case 201:
4051
+ case 240:
3947
4052
  if (!(diff.type === 'missing_database')) {
3948
- _context.next = 209;
4053
+ _context.next = 248;
3949
4054
  break;
3950
4055
  }
3951
4056
  logger('fixing missing database', diff.database);
3952
4057
  _createDatabaseSQL = "CREATE DATABASE `".concat(diff.database, "`;");
3953
4058
  console.log("Executing: ".concat(_createDatabaseSQL));
3954
- _context.next = 207;
4059
+ _context.next = 246;
3955
4060
  return connection.query(_createDatabaseSQL);
3956
- case 207:
3957
- _context.next = 210;
4061
+ case 246:
4062
+ _context.next = 249;
3958
4063
  break;
3959
- case 209:
4064
+ case 248:
3960
4065
  logger("Error applying difference of type:".concat(diff.type), diff);
3961
- case 210:
3962
- _context.next = 215;
4066
+ case 249:
4067
+ _context.next = 254;
3963
4068
  break;
3964
- case 212:
3965
- _context.prev = 212;
4069
+ case 251:
4070
+ _context.prev = 251;
3966
4071
  _context.t0 = _context["catch"](1);
3967
4072
  logger("Error applying difference of type:".concat(diff.type, ". Error: ").concat(_context.t0.message), diff);
3968
- case 215:
4073
+ case 254:
3969
4074
  case "end":
3970
4075
  return _context.stop();
3971
4076
  }
3972
- }, _loop, null, [[1, 212]]);
4077
+ }, _loop, null, [[1, 251]]);
3973
4078
  });
3974
4079
  _iterator.s();
3975
4080
  case 5:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mysqlsyncr",
3
- "version": "1.1.2",
3
+ "version": "1.1.6",
4
4
  "description": "",
5
5
  "main": "dist/index.cjs.js",
6
6
  "module": "dist/index.esm.js",
package/src/apply.js CHANGED
@@ -82,18 +82,122 @@ export const applyDifferences = async (connection, database, differences) => {
82
82
  await connection.query(dropFieldSQL);
83
83
 
84
84
  } else if (diff.type === 'mismatched_field') {
85
- const { tableName, field } = diff;
86
- const defaultClause = field.Default === 'CURRENT_TIMESTAMP'
87
- ? 'DEFAULT CURRENT_TIMESTAMP'
88
- : field.Default === 'NULL'
89
- ? 'DEFAULT NULL'
90
- : field.Default !== undefined && field.Default !== null
91
- ? `DEFAULT '${field.Default}'`
92
- : 'DEFAULT NULL';
85
+ const { tableName, field, currentField } = diff;
93
86
 
94
- const dropFieldSQL = `ALTER TABLE \`${tableName}\` CHANGE \`${field.Field}\` \`${field.Field}\` ${field.Type} ${field.NotNull ? 'NOT NULL' : ''} ${defaultClause};`;
95
- console.log(`Executing: ${dropFieldSQL}`);
96
- await connection.query(dropFieldSQL);
87
+ // Helper function to determine if we need batch processing
88
+ const needsBatchProcessing = () => {
89
+ const currentType = currentField.Type.toLowerCase();
90
+ const newType = field.Type.toLowerCase();
91
+
92
+ // Decimal changes
93
+ if (currentType.includes('decimal') && newType.includes('decimal')) {
94
+ return true;
95
+ }
96
+
97
+ // VARCHAR/CHAR length reductions
98
+ if ((currentType.includes('varchar') || currentType.includes('char')) &&
99
+ (newType.includes('varchar') || newType.includes('char'))) {
100
+ const currentLength = parseInt(currentType.match(/\((\d+)\)/)?.[1] || '0');
101
+ const newLength = parseInt(newType.match(/\((\d+)\)/)?.[1] || '0');
102
+ return newLength < currentLength;
103
+ }
104
+
105
+ // TEXT to VARCHAR conversions
106
+ if (currentType.includes('text') && newType.includes('varchar')) {
107
+ return true;
108
+ }
109
+
110
+ // Numeric type downgrades
111
+ const numericDowngrades = {
112
+ 'bigint': ['int', 'mediumint', 'smallint', 'tinyint'],
113
+ 'int': ['mediumint', 'smallint', 'tinyint'],
114
+ 'mediumint': ['smallint', 'tinyint'],
115
+ 'smallint': ['tinyint'],
116
+ 'double': ['float', 'decimal'],
117
+ 'float': ['decimal']
118
+ };
119
+
120
+ for (const [larger, smaller] of Object.entries(numericDowngrades)) {
121
+ if (currentType.includes(larger) && smaller.some(t => newType.includes(t))) {
122
+ return true;
123
+ }
124
+ }
125
+
126
+ return false;
127
+ };
128
+
129
+ if (needsBatchProcessing()) {
130
+ // Step 1: Add new column
131
+ const addColumnSQL = `ALTER TABLE \`${tableName}\` ADD COLUMN \`${field.Field}_new\` ${field.Type} DEFAULT NULL;`;
132
+ logger(`Adding new column for type conversion: ${addColumnSQL}`);
133
+ await connection.query(addColumnSQL);
134
+
135
+ // Step 2: Copy data in batches
136
+ let totalUpdated = 0;
137
+ let batchSize = 10000;
138
+ let batchCount = 0;
139
+
140
+ while (true) {
141
+ const updateSQL = `
142
+ UPDATE \`${tableName}\`
143
+ SET \`${field.Field}_new\` = \`${field.Field}\`
144
+ WHERE \`${field.Field}_new\` IS NULL
145
+ AND \`${field.Field}\` IS NOT NULL
146
+ LIMIT ${batchSize};
147
+ `;
148
+ const result = await connection.query(updateSQL);
149
+ const rowsAffected = result.affectedRows;
150
+
151
+ if (rowsAffected === 0) break;
152
+
153
+ totalUpdated += rowsAffected;
154
+ batchCount++;
155
+ logger(`Batch ${batchCount}: Converted ${rowsAffected} rows. Total converted: ${totalUpdated}`);
156
+ }
157
+
158
+ // Step 3: Verify data (optional)
159
+ const verifySQL = `
160
+ SELECT COUNT(*) as mismatch FROM \`${tableName}\`
161
+ WHERE \`${field.Field}\` IS NOT NULL
162
+ AND \`${field.Field}_new\` IS NULL;
163
+ `;
164
+ const [verifyResult] = await connection.query(verifySQL);
165
+ if (verifyResult.mismatch > 0) {
166
+ logger(`Warning: ${verifyResult.mismatch} rows may have failed conversion`);
167
+ }
168
+
169
+ // Step 4: Swap columns
170
+ const swapColumnsSQL = `
171
+ ALTER TABLE \`${tableName}\`
172
+ DROP COLUMN \`${field.Field}\`,
173
+ RENAME COLUMN \`${field.Field}_new\` TO \`${field.Field}\`
174
+ `;
175
+ logger(`Swapping columns: ${swapColumnsSQL}`);
176
+ await connection.query(swapColumnsSQL);
177
+
178
+ logger(`Completed type conversion for ${field.Field}. Total rows converted: ${totalUpdated}`);
179
+ } else {
180
+ // Original mismatched field handling for simple changes
181
+ const isTimestamp = field.Type.toLowerCase().includes('timestamp');
182
+
183
+ // Handle timestamp specific attributes
184
+ const defaultClause = field.Default === 'CURRENT_TIMESTAMP'
185
+ ? 'DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP'
186
+ : field.Default === 'NULL'
187
+ ? isTimestamp ? 'NULL DEFAULT NULL' : 'DEFAULT NULL'
188
+ : field.Default !== undefined && field.Default !== null
189
+ ? `DEFAULT '${field.Default}'`
190
+ : isTimestamp ? 'NULL DEFAULT NULL' : 'DEFAULT NULL';
191
+
192
+ // Remove ON UPDATE CURRENT_TIMESTAMP if we're changing away from CURRENT_TIMESTAMP
193
+ const currentField = diff.currentField;
194
+ const hasOnUpdate = currentField?.Default === 'CURRENT_TIMESTAMP' &&
195
+ field.Default !== 'CURRENT_TIMESTAMP';
196
+
197
+ const modifyFieldSQL = `ALTER TABLE \`${tableName}\` CHANGE \`${field.Field}\` \`${field.Field}\` ${field.Type} ${field.NotNull ? 'NOT NULL' : ''} ${defaultClause}${hasOnUpdate ? ' ON UPDATE CURRENT_TIMESTAMP' : ''};`;
198
+ console.log(`Executing: ${modifyFieldSQL}`);
199
+ await connection.query(modifyFieldSQL);
200
+ }
97
201
 
98
202
  } else if (diff.type === 'missing_index') {
99
203
  const existingColumns = await connection.query(`SHOW COLUMNS FROM \`${diff.tableName}\``);