mythix-orm 1.6.3 → 1.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  import { EventEmitter } from 'events';
2
- import { Moment } from 'moment';
2
+ import { DateTime } from 'luxon';
3
3
  import { Literals } from '.';
4
4
  import Field from '../field';
5
5
  import { GenericObject } from '../interfaces/common';
@@ -120,7 +120,7 @@ declare class ConnectionBase extends EventEmitter {
120
120
  public _uuidV5TypeToString(type: UUIDV5Type): string;
121
121
  public _xidTypeToString(type: XIDType): string;
122
122
  public typeToString(type: Type, options?: GenericObject): string;
123
- public convertDateToDBTime(value: Date | Moment): Date;
123
+ public convertDateToDBTime(value: Date | DateTime, type: Type): Date;
124
124
  public ensureAllModelsAreInstances(Model: ModelClass, models: Array<Model | GenericObject> | PreparedModels, options?: GenericObject): Array<Model>;
125
125
  public prepareAllModelsForOperation(Model: ModelClass, models: Array<Model | GenericObject> | PreparedModels, options?: GenericObject): PreparedModels;
126
126
  public splitModelAndSubModels(Model: ModelClass, primaryModel: Model, relationMap?: Map<string, Set<Model>>): Map<string, Set<Model>>;
@@ -141,20 +141,24 @@ declare class ConnectionBase extends EventEmitter {
141
141
  public stop(): Promise<void>;
142
142
 
143
143
  public runSaveHooks(Model: ModelClass, models: Array<Model>, operationHookName: string, saveHookName: string, options: GenericObject): Promise<Array<any>>;
144
+
145
+ public defineTable(): Promise<any>;
146
+ public defineConstraints(): Promise<any>;
147
+ public defineIndexes(): Promise<any>;
148
+
144
149
  public dropTable(Model: ModelClass, options?: GenericObject): Promise<any>;
145
150
  public dropTables(Models: Models, options?: GenericObject): Promise<Array<any>>;
146
151
  public createTable(Model: ModelClass, options?: GenericObject): Promise<any>;
147
152
  public createTables(Models: Models, options?: GenericObject): Promise<Array<any>>;
148
- public defineTable(): Promise<any>;
149
- public defineConstraints(): Promise<any>;
150
- public defineIndexes(): Promise<any>;
151
- public renameTable(): Promise<any>;
152
- public renameColumn(): Promise<any>;
153
- public dropColumn(): Promise<any>;
154
- public alterColumn(): Promise<any>;
155
- public addColumn(): Promise<any>;
156
- public addConstraint(): Promise<any>;
157
- public addIndex(): Promise<any>;
153
+ public alterTable(Model: ModelClass, newModelAttributes: GenericObject, options?: GenericObject): Promise<void>;
154
+
155
+ public dropColumn(Field: Field, options?: GenericObject): Promise<void>;
156
+ public alterColumn(Field: Field, newFieldAttributes: GenericObject, options?: GenericObject): Promise<void>;
157
+ public addColumn(Field: Field, options?: GenericObject): Promise<void>;
158
+
159
+ public addIndex(Model: ModelClass, indexFieldNames?: Array<string>, options?: GenericObject): Promise<void>;
160
+ public dropIndex(Model: ModelClass, indexFieldNames?: Array<string>, options?: GenericObject): Promise<void>;
161
+
158
162
  public insert(Model: ModelClass, models: Array<Model | GenericObject> | Model | GenericObject, options?: GenericObject): Promise<Array<Models> | undefined>;
159
163
  public upsert(Model: ModelClass, models: Array<Model | GenericObject> | Model | GenericObject, options?: GenericObject): Promise<Array<Models> | undefined>;
160
164
  public update(Model: ModelClass, models: Array<Model | GenericObject> | Model | GenericObject, options?: GenericObject): Promise<Array<Models> | undefined>;
@@ -171,6 +175,7 @@ declare class ConnectionBase extends EventEmitter {
171
175
  public pluck(queryEngine: QueryEngine, fields: Array<Field> | Array<string> | Field | string, options?: GenericObject): Promise<Array<any> | Array<Array<any>>>;
172
176
  public exists(queryEngine: QueryEngine, options?: GenericObject): Promise<boolean>;
173
177
  public truncate(Model: ModelClass, options?: GenericObject): Promise<void>;
178
+
174
179
  public query(sql: string | GenericObject, options?: GenericObject): Promise<any>;
175
180
  public transaction(callback: (connection: ConnectionBase) => any, options?: GenericObject): Promise<any>;
176
181
  public getDefaultFieldValue(type: string | LiteralBase, context: DefaultValueContext): Promise<any>;
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- const moment = require('moment');
3
+ const { DateTime } = require('luxon');
4
4
  const EventEmitter = require('events');
5
5
  const Nife = require('nife');
6
6
  const SqlString = require('sqlstring');
@@ -479,12 +479,12 @@ class ConnectionBase extends EventEmitter {
479
479
 
480
480
  // eslint-disable-next-line no-unused-vars
481
481
  _dateTypeToString(type) {
482
- return 'DATE';
482
+ return 'TIMESTAMP';
483
483
  }
484
484
 
485
485
  // eslint-disable-next-line no-unused-vars
486
486
  _datetimeTypeToString(type) {
487
- return 'DATETIME';
487
+ return 'TIMESTAMP';
488
488
  }
489
489
 
490
490
  // eslint-disable-next-line no-unused-vars
@@ -574,11 +574,17 @@ class ConnectionBase extends EventEmitter {
574
574
  throw new Error(`${this.constructor.name}::typeToString: Unsupported type ${type}.`);
575
575
  }
576
576
 
577
- convertDateToDBTime(value) {
578
- if (value instanceof Date || (value && value.constructor && value.constructor.name === 'Date'))
577
+ convertDateToDBTime(value, type) {
578
+ if (Nife.instanceOf(value, 'number'))
579
579
  return value;
580
- else if (moment.isMoment(value))
581
- return value.toDate();
580
+ else if (Nife.instanceOf(value, 'bigint'))
581
+ return Number(value).valueOf();
582
+ else if (DateTime.isDateTime(value))
583
+ return value.toMillis();
584
+ else if (value instanceof Date || (value && value.constructor && value.constructor.name === 'Date'))
585
+ return value.valueOf();
586
+ else if (Nife.instanceOf(value, 'string'))
587
+ return DateTime.fromISO(value).toMillis();
582
588
 
583
589
  return value;
584
590
  }
@@ -894,7 +900,7 @@ class ConnectionBase extends EventEmitter {
894
900
  if (batchModels) {
895
901
  for (let i = 0, il = batchModels.length; i < il; i++) {
896
902
  let batchModel = batchModels[i];
897
- batchModel.clearDirty();
903
+ // batchModel.clearDirty();
898
904
  finalResults.push(batchModel);
899
905
  }
900
906
  }
@@ -916,6 +922,7 @@ class ConnectionBase extends EventEmitter {
916
922
  let groupedModelMap = this.prepareAllModelsAndSubModelsForOperation(Model, models, options);
917
923
  let alreadyStored = {};
918
924
  let allDirtyModels = new Set();
925
+ let allStoredModels = new Set();
919
926
  let primaryResult;
920
927
 
921
928
  for (let [ modelName, models ] of groupedModelMap) {
@@ -935,6 +942,8 @@ class ConnectionBase extends EventEmitter {
935
942
  primaryResult = results;
936
943
 
937
944
  for (let storedModel of results) {
945
+ allStoredModels.add(storedModel);
946
+
938
947
  for (let [ groupModelName, groupModels ] of groupedModelMap) {
939
948
  if (groupModelName === modelName)
940
949
  continue;
@@ -947,9 +956,8 @@ class ConnectionBase extends EventEmitter {
947
956
  continue;
948
957
 
949
958
  for (let targetModel of groupModels) {
950
- Utils.setRelationalValues(this, TargetModel, targetModel, GroupModel, storedModel);
951
-
952
- if (targetModel.isDirty())
959
+ let hasChanges = Utils.setRelationalValues(this, TargetModel, targetModel, GroupModel, storedModel);
960
+ if (hasChanges)
953
961
  allDirtyModels.add(targetModel);
954
962
  }
955
963
  }
@@ -962,6 +970,12 @@ class ConnectionBase extends EventEmitter {
962
970
  if (allDirtyModels.size > 0 && typeof afterOperationCallback === 'function')
963
971
  await afterOperationCallback.call(this, Model, allDirtyModels, options, queryGenerator);
964
972
 
973
+ // Now mark all models as clean and persisted
974
+ for (let storedModel of allStoredModels) {
975
+ storedModel.clearDirty();
976
+ storedModel._persisted = true;
977
+ }
978
+
965
979
  return (inputIsArray || !primaryResult) ? primaryResult : primaryResult[0];
966
980
  }
967
981
 
@@ -1112,31 +1126,27 @@ class ConnectionBase extends EventEmitter {
1112
1126
 
1113
1127
  // Alter operations
1114
1128
 
1115
- async renameTable() {
1129
+ async alterTable(Model, newModelAttributes, options) {
1116
1130
  throw new Error(`${this.constructor.name}::renameTable: This operation is not supported for this connection type.`);
1117
1131
  }
1118
1132
 
1119
- async renameColumn() {
1120
- throw new Error(`${this.constructor.name}::renameColumn: This operation is not supported for this connection type.`);
1121
- }
1122
-
1123
- async dropColumn() {
1133
+ async dropColumn(Field, options) {
1124
1134
  throw new Error(`${this.constructor.name}::dropColumn: This operation is not supported for this connection type.`);
1125
1135
  }
1126
1136
 
1127
- async alterColumn() {
1137
+ async alterColumn(Field, newFieldAttributes, options) {
1128
1138
  throw new Error(`${this.constructor.name}::alterColumn: This operation is not supported for this connection type.`);
1129
1139
  }
1130
1140
 
1131
- async addColumn() {
1141
+ async addColumn(Field, options) {
1132
1142
  throw new Error(`${this.constructor.name}::addColumn: This operation is not supported for this connection type.`);
1133
1143
  }
1134
1144
 
1135
- async addConstraint() {
1136
- throw new Error(`${this.constructor.name}::addConstraint: This operation is not supported for this connection type.`);
1145
+ async addIndex(Model, indexFields, options) {
1146
+ throw new Error(`${this.constructor.name}::addIndex: This operation is not supported for this connection type.`);
1137
1147
  }
1138
1148
 
1139
- async addIndex() {
1149
+ async dropIndex(Model, indexFields, options) {
1140
1150
  throw new Error(`${this.constructor.name}::addIndex: This operation is not supported for this connection type.`);
1141
1151
  }
1142
1152
 
@@ -734,7 +734,7 @@ class QueryGeneratorBase {
734
734
  order = queryPart.value;
735
735
  }
736
736
 
737
- if (Nife.isEmpty(order)) {
737
+ if (order === undefined) {
738
738
  if (options && options.selectStatement === true)
739
739
  order = this.connection.getDefaultOrder(rootModel, options);
740
740
  }
package/lib/field.js CHANGED
@@ -243,6 +243,7 @@ class Field {
243
243
  this.allowNull = true;
244
244
  this.index = false;
245
245
  this.unique = false;
246
+ this.columnName = (fieldDefinition && fieldDefinition.fieldName);
246
247
 
247
248
  Object.assign(this, fieldDefinition || {});
248
249
  }
package/lib/model.js CHANGED
@@ -5,6 +5,7 @@ const Inflection = require('inflection');
5
5
  const Type = require('./types/type');
6
6
  const DefaultHelpers = require('./types/helpers/default-helpers');
7
7
  const Field = require('./field');
8
+ const ModelUtils = require('./utils/model-utils');
8
9
 
9
10
  /// Used as a unique key for cache.
10
11
  /// Caches will generally be stored in
@@ -1319,13 +1320,22 @@ class Model {
1319
1320
  /// Arguments:
1320
1321
  /// fieldName: string
1321
1322
  /// The specified field name to find. This **is not** the `columnName` of the field.
1322
- static getField(findFieldName) {
1323
+ static getField(_findFieldName) {
1323
1324
  let fields = this.getFields();
1324
- if (!fields || !findFieldName)
1325
+ if (!fields || !_findFieldName)
1325
1326
  return;
1326
1327
 
1327
1328
  let foundField;
1329
+ let def = ModelUtils.parseQualifiedName(_findFieldName);
1330
+ if (def.modelName && Nife.isEmpty(def.fieldNames)) {
1331
+ def.fieldNames = [ def.modelName ];
1332
+ def.modelName = undefined;
1333
+ }
1334
+
1335
+ if (def.modelName && def.modelName !== this.getModelName())
1336
+ throw new Error(`Model::getField: Can't find a field from another model. Field requested: "${_findFieldName}".`);
1328
1337
 
1338
+ let findFieldName = def.fieldNames[0];
1329
1339
  this.iterateFields(({ field, fieldName, stop }) => {
1330
1340
  if (fieldName === findFieldName) {
1331
1341
  foundField = field;
@@ -1,11 +1,10 @@
1
1
  'use strict';
2
2
 
3
3
  const Nife = require('nife');
4
- const moment = require('moment');
4
+ const { DateTime } = require('luxon');
5
5
  const Type = require('../type');
6
6
  const { DATE_NOW } = require('../helpers/default-helpers');
7
-
8
- moment.suppressDeprecationWarnings = true;
7
+ const MiscUtils = require('../../utils/misc-utils');
9
8
 
10
9
  /// `DATE` type.
11
10
  ///
@@ -13,7 +12,7 @@ moment.suppressDeprecationWarnings = true;
13
12
  /// in the underlying database.
14
13
  ///
15
14
  /// Client-side storage for this field will be backed by
16
- /// a [moment](https://momentjs.com/docs/) instance.
15
+ /// a Luxon [DateTime](https://moment.github.io/luxon/#/) instance.
17
16
  ///
18
17
  /// You can optionally provide a `format` argument when constructing
19
18
  /// this type. **This is a client-side format only**. It doesn't
@@ -24,7 +23,7 @@ moment.suppressDeprecationWarnings = true;
24
23
  /// Example:
25
24
  /// class Dates extends Model {
26
25
  /// static fields = {
27
- /// date1: Types.DATE('YYYY-MM-DD'),
26
+ /// date1: Types.DATE('yyyy-MM-dd'),
28
27
  /// date2: new Types.DateType(),
29
28
  /// };
30
29
  /// }
@@ -66,8 +65,8 @@ class DateType extends Type {
66
65
  /// Construct a new `DATE` type.
67
66
  ///
68
67
  /// The `format` argument will specify the
69
- /// date format for this field. See the
70
- /// [moment](https://momentjs.com/docs/#/displaying/format/) docs
68
+ /// date format for this field. See the Luxon
69
+ /// [DateTime](https://moment.github.io/luxon/#/formatting?id=table-of-tokens) docs
71
70
  /// for a reference on this format.
72
71
  ///
73
72
  /// This format **is not** the format that will be used
@@ -86,16 +85,16 @@ class DateType extends Type {
86
85
  constructor(format) {
87
86
  super(format);
88
87
 
89
- this.format = format || 'YYYY-MM-DD';
88
+ this.format = format || 'yyyy-MM-dd';
90
89
  }
91
90
 
92
91
  /// Cast provided value to underlying type.
93
92
  ///
94
93
  /// This will cast the incoming value to the
95
- /// underlying type of this field, a [moment](https://momentjs.com/docs/)
94
+ /// underlying type of this field, a Luxon [DateTime](https://moment.github.io/luxon/#/)
96
95
  /// instance. If the provided value results in
97
96
  /// an invalid date, then an exception will be thrown.
98
- /// Once a valid [moment](https://momentjs.com/docs/) instance
97
+ /// Once a valid Luxon [DateTime](https://moment.github.io/luxon/#/) instance
99
98
  /// is constructed from the value provided,
100
99
  /// `dateTime.startOf('day')` is returned, forcing
101
100
  /// this `DATE` type to zero its time (start at the
@@ -104,7 +103,7 @@ class DateType extends Type {
104
103
  /// See <see>Type.castToType</see> for a more
105
104
  /// detailed description.
106
105
  ///
107
- /// Return: moment | null | undefined
106
+ /// Return: DateTime | null | undefined
108
107
  /// Return the incoming `value`, cast to this
109
108
  /// type. `null` and `undefined` are simply
110
109
  /// returned without casting.
@@ -116,7 +115,7 @@ class DateType extends Type {
116
115
  return value;
117
116
 
118
117
  let dateTime = this.deserialize(value, connection);
119
- if (!dateTime.isValid())
118
+ if (!dateTime || !dateTime.isValid)
120
119
  throw new TypeError(`DateType::castToType: Value provided ("${value}") can not be cast into a date.`);
121
120
 
122
121
  return dateTime.startOf('day');
@@ -126,11 +125,11 @@ class DateType extends Type {
126
125
  ///
127
126
  /// This will check if the provided value is
128
127
  /// a valid date. It does so by calling
129
- /// `moment(value).isValid()`. If this check
128
+ /// `DateTime.isValid`. If this check
130
129
  /// results in `true`, then this method will
131
130
  /// return `true`, otherwise it will return `false`.
132
131
  ///
133
- /// See the [moment](https://momentjs.com/docs/) library documentation for more information.
132
+ /// See the Luxon [DateTime](https://moment.github.io/luxon/#/) library documentation for more information.
134
133
  ///
135
134
  /// Return: boolean
136
135
  ///
@@ -138,7 +137,11 @@ class DateType extends Type {
138
137
  /// value: any
139
138
  /// The value to check.
140
139
  isValidValue(value) {
141
- return moment(value).isValid();
140
+ try {
141
+ return (MiscUtils.valueToDateTime(value)).isValid;
142
+ } catch (error) {
143
+ return false;
144
+ }
142
145
  }
143
146
 
144
147
  /// Stringify the type itself.
@@ -148,7 +151,7 @@ class DateType extends Type {
148
151
  /// for the underlying database. If no connection is
149
152
  /// provided, then a "standard" SQL type will be returned
150
153
  /// for this type instead. The "standard" type returned
151
- /// when no `connection` is provided is `'DATE'`.
154
+ /// when no `connection` is provided is `'TIMESTAMP'`.
152
155
  ///
153
156
  /// Return: string
154
157
  ///
@@ -163,7 +166,7 @@ class DateType extends Type {
163
166
  toString(connection) {
164
167
  return (connection)
165
168
  ? this.toConnectionType(connection)
166
- : 'DATE';
169
+ : 'TIMESTAMP';
167
170
  }
168
171
 
169
172
  /// Serialize the field value.
@@ -184,31 +187,35 @@ class DateType extends Type {
184
187
  /// Return: string | null | undefined
185
188
  ///
186
189
  /// Arguments:
187
- /// value: moment
190
+ /// value: DateTime
188
191
  /// The date value to serialize.
189
192
  /// connection?: <see>Connection</see>
190
193
  /// A connection instance, which if provided, will
191
194
  /// proxy serialization to the underlying database connection
192
195
  /// via the <see>connection.convertDateToDBTime</see> method.
193
- serialize(value, connection) {
196
+ serialize(_value, connection) {
197
+ let value = _value;
194
198
  if (value == null)
195
199
  return (connection) ? null : value;
196
200
 
201
+ if (!DateTime.isDateTime(value))
202
+ value = this.deserialize(value);
203
+
197
204
  if (connection)
198
- return connection.convertDateToDBTime(value);
205
+ return connection.convertDateToDBTime(value, this);
199
206
 
200
207
  if (this.format)
201
- return value.format(this.format);
208
+ return value.toFormat(this.format || 'yyyy-MM-dd');
202
209
 
203
- return value.toISOString();
210
+ return value.toISO();
204
211
  }
205
212
 
206
213
  /// Deserialize the field value.
207
214
  ///
208
215
  /// This method is used to deserialize a provided
209
- /// field value. If the value provided is a `moment`
216
+ /// field value. If the value provided is a `DateTime`
210
217
  /// instance, then simply return it. Otherwise,
211
- /// if a string is provided, convert it to a `moment`
218
+ /// if a string is provided, convert it to a `DateTime`
212
219
  /// instance, using the `format` provided (if any).
213
220
  ///
214
221
  /// The `connection` argument is not used by this
@@ -220,12 +227,12 @@ class DateType extends Type {
220
227
  ///
221
228
  /// Note:
222
229
  /// This method is called by `castToType` to cast
223
- /// incoming values into `moment` instances.
230
+ /// incoming values into `DateTime` instances.
224
231
  ///
225
- /// Return: moment
232
+ /// Return: DateTime
226
233
  ///
227
234
  /// Arguments:
228
- /// value: string | moment | null | undefined
235
+ /// value: DateTime | Date | string | number | BigInt | null | undefined
229
236
  /// The value to deserialize.
230
237
  /// connection?: <see>Connection</see>
231
238
  /// An optional connection that might be provided
@@ -240,15 +247,15 @@ class DateType extends Type {
240
247
  return value;
241
248
 
242
249
  if (Nife.instanceOf(value, 'string') && this.format) {
243
- value = moment(_value, this.format);
250
+ value = MiscUtils.valueToDateTime(_value, this.format);
244
251
 
245
- if (!value.isValid())
246
- value = moment(_value);
252
+ if (!value.isValid)
253
+ value = MiscUtils.valueToDateTime(_value);
247
254
  } else {
248
- value = moment(value);
255
+ value = MiscUtils.valueToDateTime(_value);
249
256
  }
250
257
 
251
- if (!value.isValid())
258
+ if (!value.isValid)
252
259
  throw new TypeError(`DateType::deserialize: Value provided ("${_value}") can not be cast into a date.`);
253
260
 
254
261
  return value;
@@ -1,11 +1,10 @@
1
1
  'use strict';
2
2
 
3
3
  const Nife = require('nife');
4
- const moment = require('moment');
4
+ const { DateTime } = require('luxon');
5
5
  const Type = require('../type');
6
6
  const { DATETIME_NOW } = require('../helpers/default-helpers');
7
-
8
- moment.suppressDeprecationWarnings = true;
7
+ const MiscUtils = require('../../utils/misc-utils');
9
8
 
10
9
  /// `DATETIME` type.
11
10
  ///
@@ -13,7 +12,7 @@ moment.suppressDeprecationWarnings = true;
13
12
  /// in the underlying database.
14
13
  ///
15
14
  /// Client-side storage for this field will be backed by
16
- /// a [moment](https://momentjs.com/docs/) instance.
15
+ /// a Luxon [DateTime](https://moment.github.io/luxon/#/) instance.
17
16
  ///
18
17
  /// You can optionally provide a `format` argument when constructing
19
18
  /// this type. **This is a client-side format only**. It doesn't
@@ -24,7 +23,7 @@ moment.suppressDeprecationWarnings = true;
24
23
  /// Example:
25
24
  /// class DatesWithTimes extends Model {
26
25
  /// static fields = {
27
- /// dateTime1: Types.DATETIME('YYYY-MM-DD HH:mm:ss'),
26
+ /// dateTime1: Types.DATETIME('yyyy-MM-dd HH:mm:ss'),
28
27
  /// dateTime2: new Types.DateTimeType(),
29
28
  /// };
30
29
  /// }
@@ -66,8 +65,8 @@ class DateTimeType extends Type {
66
65
  /// Construct a new `DATETIME` type.
67
66
  ///
68
67
  /// The `format` argument will specify the
69
- /// date format for this field. See the
70
- /// [moment](https://momentjs.com/docs/#/displaying/format/) docs
68
+ /// date format for this field. See the Luxon
69
+ /// [DateTime](https://moment.github.io/luxon/#/formatting?id=table-of-tokens) docs
71
70
  /// for a reference on this format.
72
71
  ///
73
72
  /// This format **is not** the format that will be used
@@ -99,14 +98,14 @@ class DateTimeType extends Type {
99
98
  /// Cast provided value to underlying type.
100
99
  ///
101
100
  /// This will cast the incoming value to the
102
- /// underlying type of this field, a [moment](https://momentjs.com/docs/)
101
+ /// underlying type of this field, a Luxon [DateTime](https://moment.github.io/luxon/#/)
103
102
  /// instance. If the provided value results in
104
103
  /// an invalid date, then an exception will be thrown.
105
104
  ///
106
105
  /// See <see>Type.castToType</see> for a more
107
106
  /// detailed description.
108
107
  ///
109
- /// Return: moment | null | undefined
108
+ /// Return: DateTime | null | undefined
110
109
  /// Return the incoming `value`, cast to this
111
110
  /// type. `null` and `undefined` are simply
112
111
  /// returned without casting.
@@ -118,7 +117,7 @@ class DateTimeType extends Type {
118
117
  return value;
119
118
 
120
119
  let dateTime = this.deserialize(value, connection);
121
- if (!dateTime.isValid())
120
+ if (!dateTime || !dateTime.isValid)
122
121
  throw new TypeError(`DateTimeType::castToType: Value provided ("${value}") can not be cast into a date.`);
123
122
 
124
123
  return dateTime;
@@ -128,11 +127,11 @@ class DateTimeType extends Type {
128
127
  ///
129
128
  /// This will check if the provided value is
130
129
  /// a valid date. It does so by calling
131
- /// `moment(value).isValid()`. If this check
130
+ /// `DateTime.isValid`. If this check
132
131
  /// results in `true`, then this method will
133
132
  /// return `true`, otherwise it will return `false`.
134
133
  ///
135
- /// See the [moment](https://momentjs.com/docs/) library documentation for more information.
134
+ /// See the Luxon [DateTime](https://moment.github.io/luxon/#/) library documentation for more information.
136
135
  ///
137
136
  /// Return: boolean
138
137
  ///
@@ -140,7 +139,11 @@ class DateTimeType extends Type {
140
139
  /// value: any
141
140
  /// The value to check.
142
141
  isValidValue(value) {
143
- return moment(value).isValid();
142
+ try {
143
+ return (MiscUtils.valueToDateTime(value)).isValid;
144
+ } catch (error) {
145
+ return false;
146
+ }
144
147
  }
145
148
 
146
149
  /// Stringify the type itself.
@@ -150,7 +153,7 @@ class DateTimeType extends Type {
150
153
  /// for the underlying database. If no connection is
151
154
  /// provided, then a "standard" SQL type will be returned
152
155
  /// for this type instead. The "standard" type returned
153
- /// when no `connection` is provided is `'DATETIME'`.
156
+ /// when no `connection` is provided is `'TIMESTAMP'`.
154
157
  ///
155
158
  /// Return: string
156
159
  ///
@@ -165,7 +168,7 @@ class DateTimeType extends Type {
165
168
  toString(connection) {
166
169
  return (connection)
167
170
  ? this.toConnectionType(connection)
168
- : 'DATETIME';
171
+ : 'TIMESTAMP';
169
172
  }
170
173
 
171
174
  /// Serialize the field value.
@@ -186,7 +189,7 @@ class DateTimeType extends Type {
186
189
  /// Return: string | null | undefined
187
190
  ///
188
191
  /// Arguments:
189
- /// value: moment
192
+ /// value: DateTime
190
193
  /// The date value to serialize.
191
194
  /// connection?: <see>Connection</see>
192
195
  /// A connection instance, which if provided, will
@@ -197,24 +200,24 @@ class DateTimeType extends Type {
197
200
  if (value == null)
198
201
  return (connection) ? null : value;
199
202
 
200
- if (!moment.isMoment(value))
203
+ if (!DateTime.isDateTime(value))
201
204
  value = this.deserialize(value);
202
205
 
203
206
  if (connection)
204
- return connection.convertDateToDBTime(value);
207
+ return connection.convertDateToDBTime(value, this);
205
208
 
206
209
  if (this.format)
207
- return value.format(this.format);
210
+ return value.toFormat(this.format);
208
211
 
209
- return value.toISOString();
212
+ return value.toISO();
210
213
  }
211
214
 
212
215
  /// Deserialize the field value.
213
216
  ///
214
217
  /// This method is used to deserialize a provided
215
- /// field value. If the value provided is a `moment`
218
+ /// field value. If the value provided is a `DateTime`
216
219
  /// instance, then simply return it. Otherwise,
217
- /// if a string is provided, convert it to a `moment`
220
+ /// if a string is provided, convert it to a `DateTime`
218
221
  /// instance, using the `format` provided (if any).
219
222
  ///
220
223
  /// The `connection` argument is not used by this
@@ -226,12 +229,12 @@ class DateTimeType extends Type {
226
229
  ///
227
230
  /// Note:
228
231
  /// This method is called by `castToType` to cast
229
- /// incoming values into `moment` instances.
232
+ /// incoming values into `DateTime` instances.
230
233
  ///
231
- /// Return: moment
234
+ /// Return: DateTime
232
235
  ///
233
236
  /// Arguments:
234
- /// value: string | moment | null | undefined
237
+ /// value: DateTime | Date | string | number | BigInt | null | undefined
235
238
  /// The value to deserialize.
236
239
  /// connection?: <see>Connection</see>
237
240
  /// An optional connection that might be provided
@@ -246,15 +249,15 @@ class DateTimeType extends Type {
246
249
  return value;
247
250
 
248
251
  if (Nife.instanceOf(value, 'string') && this.format) {
249
- value = moment(_value, this.format);
252
+ value = MiscUtils.valueToDateTime(_value, this.format);
250
253
 
251
- if (!value.isValid())
252
- value = moment(_value);
254
+ if (!value.isValid)
255
+ value = MiscUtils.valueToDateTime(_value);
253
256
  } else {
254
- value = moment(_value);
257
+ value = MiscUtils.valueToDateTime(_value);
255
258
  }
256
259
 
257
- if (!value.isValid())
260
+ if (!value.isValid)
258
261
  throw new TypeError(`DateType::deserialize: Value provided ("${_value}") can not be cast into a date.`);
259
262
 
260
263
  return value;
@@ -11,7 +11,8 @@ export const FLAG_LITERAL: number;
11
11
  export const FLAG_REMOTE: number;
12
12
 
13
13
  export declare interface DefaultValueContext {
14
- _initial: boolean;
14
+ _initial?: boolean;
15
+ _static?: boolean;
15
16
  connection: ConnectionBase;
16
17
  data: GenericObject | undefined;
17
18
  field: Field;
@@ -7,6 +7,7 @@ const QueryUtils = require('./query-utils');
7
7
  const {
8
8
  collect,
9
9
  objectAssignSpecial,
10
+ valueToDateTime,
10
11
  } = MiscUtils;
11
12
 
12
13
  const {
@@ -39,6 +40,7 @@ module.exports = {
39
40
  // MiscUtils
40
41
  collect,
41
42
  objectAssignSpecial,
43
+ valueToDateTime,
42
44
 
43
45
  // ModelUtils
44
46
  assignRelatedModels,
@@ -1,4 +1,6 @@
1
+ import { DateTime } from 'luxon';
1
2
  import { GenericObject } from '../interfaces/common';
2
3
 
3
4
  declare function collect(iterator: AsyncIterator<any>): Promise<Array<any>>;
4
5
  declare function objectAssignSpecial(obj: GenericObject, proto?: GenericObject | null, skipKeys?: Array<string> | GenericObject): GenericObject;
6
+ declare function valueToDateTime(value: DateTime | Date | number | BigInt | string, format?: string): DateTime;
@@ -1,5 +1,8 @@
1
1
  'use strict';
2
2
 
3
+ const Nife = require('nife');
4
+ const { DateTime } = require('luxon');
5
+
3
6
  async function collect(iterator) {
4
7
  let items = [];
5
8
 
@@ -32,7 +35,30 @@ function objectAssignSpecial(obj, proto, skipKeys) {
32
35
  return newObj;
33
36
  }
34
37
 
38
+ function valueToDateTime(value, format) {
39
+ if (DateTime.isDateTime(value)) {
40
+ return value;
41
+ } else if (Nife.instanceOf(value, 'number')) {
42
+ return DateTime.fromMillis(value);
43
+ } else if (Nife.instanceOf(value, 'bigint')) {
44
+ return DateTime.fromMillis(Number(value).valueOf());
45
+ } else if (value instanceof Date || (value && value.constructor && value.constructor.name === 'Date')) {
46
+ return DateTime.fromJSDate(value);
47
+ } else if (Nife.instanceOf(value, 'string')) {
48
+ if ((/^\d+$/).test(value))
49
+ return DateTime.fromMillis(parseInt(value, 10));
50
+
51
+ if (Nife.isNotEmpty(format))
52
+ return DateTime.fromFormat(value, format);
53
+
54
+ return DateTime.fromISO(value);
55
+ } else {
56
+ throw new Error(`MiscUtils::valueToDateTime: Invalid value provided: "${value}"`);
57
+ }
58
+ }
59
+
35
60
  module.exports = {
36
61
  collect,
37
62
  objectAssignSpecial,
63
+ valueToDateTime,
38
64
  };
@@ -18,7 +18,7 @@ export declare interface RelationStatus {
18
18
  }
19
19
 
20
20
  export declare interface ModelsRelationStatuses {
21
- [ key: string ]: RelationStatus
21
+ [key: string]: RelationStatus
22
22
  }
23
23
 
24
24
  export declare function isUUID(value: any): boolean;
@@ -70,7 +70,7 @@ export declare function setRelationalValues<T extends Model = Model>(
70
70
  targetModelInstance: T,
71
71
  SourceModel: ModelClass,
72
72
  sourceModelInstance: Model,
73
- ): T;
73
+ ): boolean;
74
74
 
75
75
  export declare function assignRelatedModels(model: Model, relatedModels: Model | Array<Model>): void;
76
76
  export declare function getPrimaryKeysForModels(
@@ -81,7 +81,7 @@ export declare function getPrimaryKeysForModels(
81
81
  includeRelations?: boolean | Array<string>,
82
82
  skipRelations?: Array<string>,
83
83
  },
84
- ): Array<any> | { [ key: string ]: Array<any> };
84
+ ): Array<any> | { [key: string]: Array<any> };
85
85
 
86
86
  export declare function buildQueryFromModelsAttributes(
87
87
  connection: ConnectionBase,
@@ -531,9 +531,10 @@ function setRelationalValues(connection, TargetModel, targetModelInstance, Sourc
531
531
  let sourceModelName = SourceModel.getModelName();
532
532
 
533
533
  if (targetModelName === sourceModelName)
534
- return targetModelInstance;
534
+ return false;
535
535
 
536
- let fieldSets = TargetModel.getForeignKeysTargetFieldNames(connection, sourceModelName);
536
+ let fieldSets = TargetModel.getForeignKeysTargetFieldNames(connection, sourceModelName);
537
+ let hasChanges = false;
537
538
 
538
539
  // Update fields to related model
539
540
  for (let i = 0, il = fieldSets.length; i < il; i++) {
@@ -548,10 +549,13 @@ function setRelationalValues(connection, TargetModel, targetModelInstance, Sourc
548
549
  let sourceFieldName = fieldSet.targetFieldName;
549
550
  let sourceModelValue = (sourceModelInstance) ? sourceModelInstance[sourceFieldName] : null;
550
551
 
551
- targetModelInstance[targetFieldName] = sourceModelValue;
552
+ if (targetModelInstance[targetFieldName] !== sourceModelValue) {
553
+ targetModelInstance[targetFieldName] = sourceModelValue;
554
+ hasChanges = true;
555
+ }
552
556
  }
553
557
 
554
- return targetModelInstance;
558
+ return hasChanges;
555
559
  }
556
560
 
557
561
  function assignRelatedModels(model, _relatedModels) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mythix-orm",
3
- "version": "1.6.3",
3
+ "version": "1.7.1",
4
4
  "description": "ORM for Mythix framework",
5
5
  "main": "lib/index",
6
6
  "type": "commonjs",
@@ -45,7 +45,7 @@
45
45
  "dependencies": {
46
46
  "events": "^3.3.0",
47
47
  "inflection": "^1.13.2",
48
- "moment": "^2.29.4",
48
+ "luxon": "^3.0.4",
49
49
  "nife": "^1.12.1",
50
50
  "sqlstring": "^2.3.3",
51
51
  "uuid": "^9.0.0",