Просмотр исходного кода

refactor: improves id generation perfomance

e22m4u 1 неделя назад
Родитель
Сommit
b52f6b71c3
3 измененных файлов с 120 добавлено и 23 удалено
  1. 32 11
      dist/cjs/index.cjs
  2. 41 12
      src/adapter/builtin/memory-adapter.js
  3. 47 0
      src/adapter/builtin/memory-adapter.spec.js

+ 32 - 11
dist/cjs/index.cjs

@@ -3507,10 +3507,9 @@ var init_memory_adapter = __esm({
        */
       _genNextIdValue(modelName, propName) {
         var _a;
-        const propType = this.getService(
-          ModelDefinitionUtils
-        ).getDataTypeByPropertyName(modelName, propName);
-        if (propType !== DataType.ANY && propType !== DataType.NUMBER)
+        const modelUtils = this.getService(ModelDefinitionUtils);
+        const propType = modelUtils.getDataTypeByPropertyName(modelName, propName);
+        if (propType !== DataType.ANY && propType !== DataType.NUMBER) {
           throw new InvalidArgumentError(
             "The memory adapter able to generate only Number identifiers, but the primary key %v of the model %v is defined as %s. Do provide your own value for the %v property, or change the type in the primary key definition to a Number that will be generated automatically.",
             propName,
@@ -3518,16 +3517,34 @@ var init_memory_adapter = __esm({
             capitalize(propType),
             propName
           );
-        const tableName = this.getService(ModelDefinitionUtils).getTableNameByModelName(modelName);
-        const lastId = (_a = this._lastIds.get(tableName)) != null ? _a : 0;
-        const nextId = lastId + 1;
-        this._lastIds.set(tableName, nextId);
+        }
+        const tableName = modelUtils.getTableNameByModelName(modelName);
         const table = this._getTableOrCreate(modelName);
-        const existedIds = Array.from(table.keys());
-        if (existedIds.includes(nextId))
-          return this._genNextIdValue(modelName, propName);
+        let nextId = (_a = this._lastIds.get(tableName)) != null ? _a : 0;
+        do {
+          nextId++;
+        } while (table.has(nextId));
+        this._lastIds.set(tableName, nextId);
         return nextId;
       }
+      /**
+       * Update last id value if needed.
+       *
+       * Если переданное значение последнего использованного
+       * идентификатора больше текущего, то текущее значение
+       * перезаписывается полученным.
+       *
+       * @param {string} modelName
+       * @param {number} idValue
+       */
+      _updateLastIdValueIfNeeded(modelName, idValue) {
+        var _a;
+        const tableName = this.getService(ModelDefinitionUtils).getTableNameByModelName(modelName);
+        const currentLastId = (_a = this._lastIds.get(tableName)) != null ? _a : 0;
+        if (idValue > currentLastId) {
+          this._lastIds.set(tableName, idValue);
+        }
+      }
       /**
        * Create
        *
@@ -3544,6 +3561,8 @@ var init_memory_adapter = __esm({
         let idValue = modelData[pkPropName];
         if (idValue == null || idValue === "" || idValue === 0) {
           idValue = this._genNextIdValue(modelName, pkPropName);
+        } else if (typeof idValue === "number") {
+          this._updateLastIdValueIfNeeded(modelName, idValue);
         }
         const table = this._getTableOrCreate(modelName);
         if (table.has(idValue))
@@ -3612,6 +3631,8 @@ var init_memory_adapter = __esm({
         let idValue = modelData[pkPropName];
         if (idValue == null || idValue === "" || idValue === 0) {
           idValue = this._genNextIdValue(modelName, pkPropName);
+        } else if (typeof idValue === "number") {
+          this._updateLastIdValueIfNeeded(modelName, idValue);
         }
         const table = this._getTableOrCreate(modelName);
         modelData = cloneDeep(modelData);

+ 41 - 12
src/adapter/builtin/memory-adapter.js

@@ -50,10 +50,9 @@ export class MemoryAdapter extends Adapter {
    * @returns {number}
    */
   _genNextIdValue(modelName, propName) {
-    const propType = this.getService(
-      ModelDefinitionUtils,
-    ).getDataTypeByPropertyName(modelName, propName);
-    if (propType !== DataType.ANY && propType !== DataType.NUMBER)
+    const modelUtils = this.getService(ModelDefinitionUtils);
+    const propType = modelUtils.getDataTypeByPropertyName(modelName, propName);
+    if (propType !== DataType.ANY && propType !== DataType.NUMBER) {
       throw new InvalidArgumentError(
         'The memory adapter able to generate only Number identifiers, ' +
           'but the primary key %v of the model %v is defined as %s. ' +
@@ -65,18 +64,36 @@ export class MemoryAdapter extends Adapter {
         capitalize(propType),
         propName,
       );
-    const tableName =
-      this.getService(ModelDefinitionUtils).getTableNameByModelName(modelName);
-    const lastId = this._lastIds.get(tableName) ?? 0;
-    const nextId = lastId + 1;
-    this._lastIds.set(tableName, nextId);
+    }
+    const tableName = modelUtils.getTableNameByModelName(modelName);
     const table = this._getTableOrCreate(modelName);
-    const existedIds = Array.from(table.keys());
-    if (existedIds.includes(nextId))
-      return this._genNextIdValue(modelName, propName);
+    let nextId = this._lastIds.get(tableName) ?? 0;
+    do {
+      nextId++;
+    } while (table.has(nextId));
+    this._lastIds.set(tableName, nextId);
     return nextId;
   }
 
+  /**
+   * Update last id value if needed.
+   *
+   * Если переданное значение последнего использованного
+   * идентификатора больше текущего, то текущее значение
+   * перезаписывается полученным.
+   *
+   * @param {string} modelName
+   * @param {number} idValue
+   */
+  _updateLastIdValueIfNeeded(modelName, idValue) {
+    const tableName =
+      this.getService(ModelDefinitionUtils).getTableNameByModelName(modelName);
+    const currentLastId = this._lastIds.get(tableName) ?? 0;
+    if (idValue > currentLastId) {
+      this._lastIds.set(tableName, idValue);
+    }
+  }
+
   /**
    * Create
    *
@@ -95,6 +112,12 @@ export class MemoryAdapter extends Adapter {
     if (idValue == null || idValue === '' || idValue === 0) {
       idValue = this._genNextIdValue(modelName, pkPropName);
     }
+    // если идентификатор передан вручную и является числом,
+    // то значение последнего использованного идентификатора
+    // обновляется на полученное
+    else if (typeof idValue === 'number') {
+      this._updateLastIdValueIfNeeded(modelName, idValue);
+    }
 
     const table = this._getTableOrCreate(modelName);
     if (table.has(idValue))
@@ -174,6 +197,12 @@ export class MemoryAdapter extends Adapter {
     if (idValue == null || idValue === '' || idValue === 0) {
       idValue = this._genNextIdValue(modelName, pkPropName);
     }
+    // если идентификатор передан вручную и является числом,
+    // то значение последнего использованного идентификатора
+    // обновляется на полученное
+    else if (typeof idValue === 'number') {
+      this._updateLastIdValueIfNeeded(modelName, idValue);
+    }
 
     const table = this._getTableOrCreate(modelName);
     modelData = cloneDeep(modelData);

+ 47 - 0
src/adapter/builtin/memory-adapter.spec.js

@@ -56,6 +56,53 @@ describe('MemoryAdapter', function () {
       expect(id2).to.be.eq(2);
       expect(id3).to.be.eq(3);
     });
+
+    it('increments from the the last known identifier', function () {
+      const dbs = new DatabaseSchema();
+      dbs.defineModel({name: 'model'});
+      const A = dbs.getService(MemoryAdapter);
+      A._lastIds.set('model', 10);
+      const id1 = A._genNextIdValue('model', DEF_PK);
+      const id2 = A._genNextIdValue('model', DEF_PK);
+      const id3 = A._genNextIdValue('model', DEF_PK);
+      expect(id1).to.be.eq(11);
+      expect(id2).to.be.eq(12);
+      expect(id3).to.be.eq(13);
+    });
+  });
+
+  describe('_updateLastIdValueIfNeeded', function () {
+    it('does nothing when the given identifier is lower or equal', function () {
+      const dbs = new DatabaseSchema();
+      dbs.defineModel({name: 'model'});
+      const A = dbs.getService(MemoryAdapter);
+      A._lastIds.set('model', 10);
+      A._updateLastIdValueIfNeeded('model', 9);
+      A._updateLastIdValueIfNeeded('model', 10);
+      const res = A._lastIds.get('model');
+      expect(res).to.be.eq(10);
+    });
+
+    it('updates the last known identifier if the given identifier is greater', function () {
+      const dbs = new DatabaseSchema();
+      dbs.defineModel({name: 'model'});
+      const A = dbs.getService(MemoryAdapter);
+      A._lastIds.set('model', 10);
+      A._updateLastIdValueIfNeeded('model', 15);
+      const res = A._lastIds.get('model');
+      expect(res).to.be.eq(15);
+    });
+
+    it('correctly resolves table name from model name', function () {
+      const dbs = new DatabaseSchema();
+      dbs.defineModel({name: 'MyModel', tableName: 'custom_table_name'});
+      const A = dbs.getService(MemoryAdapter);
+      A._lastIds.set('custom_table_name', 10);
+      A._updateLastIdValueIfNeeded('MyModel', 20);
+      const res = A._lastIds.get('custom_table_name');
+      expect(res).to.be.eq(20);
+      expect(A._lastIds.has('MyModel')).to.be.false;
+    });
   });
 
   describe('create', function () {