Name

sn_aisearch_global.AisMigrationRecord

Description

Wrapper around GlideRecord that stages changes rather than committing them to DB

Script

var AisMigrationRecord = Class.create();
AisMigrationRecord.prototype = {

  initialize: function(migrationSysID, targetTableName) {
      if (!targetTableName)
          throw 'Cannot create a record without table name';

      if (!migrationSysID)
          throw 'Cannot create a record without migrationSysID';

      this.targetTableName = targetTableName;
      this.migrationSysID = migrationSysID;
      this.queries = [];
      this.setValues = {};
      this.conflictResolver = new AisMigrationConflictResolver(migrationSysID);
  },

  setNeedsReview: function(needsReview) {
      this.needsReview = needsReview;
  },

  addQuery: function(key, operator, value) {
      var query = {
          key: key,
          operator: operator,
          value: value
      };
      this.queries.push(query);
  },

  query: function() {
      this.targetGr = new GlideRecord(this.targetTableName);
      for (var i = 0; i < this.queries.length; i++) {
          var query = this.queries[i];
          this.targetGr.addQuery(query.key, query.operator, query.value);
      }

      this.targetGr.query();
  },

  setValue: function(key, value) {
      this.setValues[key] = value;
  },

  insert: function() {
      // Indexed sources are special. We cannot insert more than one per table.
      if (this.targetTableName === 'ais_datasource') {
          var existingStagingGr = this._isIndexedSourceStaged(this.setValues['source']);
          if (this._indexedSourceExists(this.setValues['source']) && existingStagingGr != null) {
              this.conflictResolver.resolveWithStagingRecord(this.targetTableName, existingStagingGr, this.setValues);

              this.setValues = {};
              return 'sn_aisearch_global_job_staging_' + existingStagingGr.getUniqueValue();
          }
      }

      var stagingGr = new GlideRecord('sn_aisearch_global_job_staging');
      stagingGr.initialize();
      stagingGr.setValue('table_name', this.targetTableName);
      stagingGr.setValue('operation', 'insert');
      stagingGr.setValue('migration_orchestration', this.migrationSysID);
      if (this.needsReview)
          stagingGr.setValue('state', 'needs_review');

      var stagingRecordSysID = stagingGr.insert();
      var values = this.setValues;
      Object.keys(values).forEach(function(key) {
          var value = values[key];

          var stagingChangeGr = new GlideRecord('sn_aisearch_global_job_staging_change');
          stagingChangeGr.initialize();
          stagingChangeGr.setValue('migration_staging_record', stagingRecordSysID);
          stagingChangeGr.setValue('field', key);
          stagingChangeGr.setValue('new_value', value);
          stagingChangeGr.insert();
      });

      this.setValues = {};
      return 'sn_aisearch_global_job_staging_' + stagingRecordSysID; // A special prefix to help us identify generated records
  },

  update: function() {
      // Indexed sources are special. We cannot insert more than one per table.
      if (this.targetTableName === 'ais_datasource') {
          var existingStagingGr = this._isIndexedSourceStaged(this.setValues['source']);
          if (existingStagingGr != null) {
              this.conflictResolver.resolveWithStagingRecord(this.targetTableName, existingStagingGr, this.setValues);
              this.setValues = {};
              return;
          }
      }

      var stagingGr = new GlideRecord('sn_aisearch_global_job_staging');
      stagingGr.initialize();
      if (this.needsReview)
          stagingGr.setValue('state', 'needs_review');

      stagingGr.setValue('table_name', this.targetTableName);

      stagingGr.setValue('table_sys_id', this.targetGr.getUniqueValue());
      stagingGr.setValue('operation', 'update');

      stagingGr.setValue('migration_orchestration', this.migrationSysID);

      var stagingRecordSysID = stagingGr.insert();
      var insertedChanges = 0;

      var values = this.setValues;
      var targetGr = this.targetGr;
      Object.keys(values).forEach(function(key) {
          var value = values[key];

          var stagingChangeGr = new GlideRecord('sn_aisearch_global_job_staging_change');
          stagingChangeGr.initialize();
          stagingChangeGr.setValue('migration_staging_record', stagingRecordSysID);
          stagingChangeGr.setValue('field', key);
          stagingChangeGr.setValue('previous_value', targetGr.getValue(key));
          stagingChangeGr.setValue('new_value', value);
          stagingChangeGr.insert();

          insertedChanges = insertedChanges + 1;
      });

      // In case of no changes, remove the staging record
      if (insertedChanges === 0) {
          gs.info('No changes found for the record. Deleting staged record.');
          stagingGr.get(stagingRecordSysID);
          stagingGr.deleteRecord();
          return;
      }

      this.setValues = {};
  },

  next: function() {
      this.setValues = {};
      return this.targetGr.next();
  },

  hasNext: function() {
      return this.targetGr.hasNext();
  },

  getValue: function(fieldName) {
      return this.targetGr.getValue(fieldName);
  },

  getUniqueValue: function() {
      return this.targetGr.getUniqueValue();
  },

  get: function(sysID) {
      this.addQuery('sys_id', '=', sysID);
      this.query();
      this.next();
  },

  _isIndexedSourceStaged: function(tableName) {
      var stagingChangeGr = new GlideRecord('sn_aisearch_global_job_staging_change');
      stagingChangeGr.addQuery('field', 'source');

      stagingChangeGr.addQuery('new_value', tableName);
      stagingChangeGr.addQuery('migration_staging_record.table_name', 'ais_datasource');
      stagingChangeGr.orderByDesc('migration_staging_record.sequence');
      stagingChangeGr.query();

      if (!stagingChangeGr.next()) {
          gs.info("Found no staging record for table_name" + tableName);
          return null;
      }

      gs.info("Found an existing staging record for table_name" + tableName);
      var stagingGr = new GlideRecord('sn_aisearch_global_job_staging');
      stagingGr.get(stagingChangeGr.getValue('migration_staging_record'));
      return stagingGr;

  },

  _indexedSourceExists: function(tableName) {
      var indexedSourceGR = new GlideRecord('ais_datasource');
      indexedSourceGR.addQuery('source', tableName);
      indexedSourceGR.query();
      if (indexedSourceGR.next())
          return true;

      return false;
  },
  type: 'AisMigrationRecord'
};

Sys ID

9d83fe74b71101107f033307fe11a928

Offical Documentation

Official Docs: