API Docs for: v3.16.0-alpha.2
Show:

File: ../store/addon/-private/system/store/record-data-store-wrapper.ts

import { RecordDataStoreWrapper as IRecordDataStoreWrapper } from '../../ts-interfaces/record-data-store-wrapper';
import { AttributesSchema, RelationshipsSchema } from '../../ts-interfaces/record-data-schemas';
import { BRAND_SYMBOL } from '../../ts-interfaces/utils/brand';
import { upgradeForInternal } from '../ts-upgrade-map';
import RecordData from '../../ts-interfaces/record-data';
import { internalModelFactoryFor } from './internal-model-factory';
import { IDENTIFIERS, CUSTOM_MODEL_CLASS } from '@ember-data/canary-features';
import { identifierCacheFor, IdentifierCache } from '../../identifiers/cache';
import CoreStore from '../core-store';
import constructResource from '../../utils/construct-resource';
import { StableRecordIdentifier } from '../../ts-interfaces/identifier';

/**
  @module @ember-data/store
*/

type StableIdentifierOrString = StableRecordIdentifier | string;

export default class RecordDataStoreWrapper implements IRecordDataStoreWrapper {
  [BRAND_SYMBOL]: 'RecordDataStoreWrapper';
  _willUpdateManyArrays: boolean;
  private _pendingManyArrayUpdates: StableIdentifierOrString[];

  constructor(public _store: CoreStore) {
    this._willUpdateManyArrays = false;
    this._pendingManyArrayUpdates = [];
  }

  get identifierCache(): IdentifierCache {
    if (!IDENTIFIERS) {
      throw new Error(`Store.identifierCache is unavailable in this build of EmberData`);
    }
    return identifierCacheFor(this._store);
  }

  /**
   * Exists so that DefaultRecordData can check for model types
   * in DEBUG for relationships. Should be refactored away.
   *
   * @internal
   */
  _hasModelFor(type: string) {
    return this._store._hasModelFor(type);
  }

  /**
   * @internal
   */
  _scheduleManyArrayUpdate(identifier: StableRecordIdentifier, key: string) {
    let pending = (this._pendingManyArrayUpdates = this._pendingManyArrayUpdates || []);
    pending.push(identifier, key);

    if (this._willUpdateManyArrays === true) {
      return;
    }

    this._willUpdateManyArrays = true;
    let backburner: any = this._store._backburner;

    backburner.join(() => {
      backburner.schedule('syncRelationships', this, this._flushPendingManyArrayUpdates);
    });
  }

  notifyErrorsChange(type: string, id: string, lid: string | null): void;
  notifyErrorsChange(type: string, id: string | null, lid: string): void;
  notifyErrorsChange(type: string, id: string | null, lid: string | null): void {
    const resource = constructResource(type, id, lid);
    const identifier = identifierCacheFor(this._store).getOrCreateRecordIdentifier(resource);

    let internalModel = internalModelFactoryFor(this._store).peek(identifier);

    if (internalModel) {
      internalModel.notifyErrorsChange();
    }
  }

  _flushPendingManyArrayUpdates(): void {
    if (this._willUpdateManyArrays === false) {
      return;
    }

    let pending = this._pendingManyArrayUpdates;
    this._pendingManyArrayUpdates = [];
    this._willUpdateManyArrays = false;
    const factory = internalModelFactoryFor(this._store);

    for (let i = 0; i < pending.length; i += 2) {
      let identifier = pending[i] as StableRecordIdentifier;
      let key = pending[i + 1] as string;
      let internalModel = factory.peek(identifier);

      if (internalModel) {
        internalModel.notifyHasManyChange(key);
      }
    }
  }

  attributesDefinitionFor(type: string): AttributesSchema {
    return this._store._attributesDefinitionFor(type);
  }

  relationshipsDefinitionFor(type: string): RelationshipsSchema {
    return this._store._relationshipsDefinitionFor(type);
  }

  inverseForRelationship(type: string, key: string): string | null {
    const modelClass = this._store.modelFor(type);
    const definition = upgradeForInternal(this.relationshipsDefinitionFor(type)[key]);
    if (CUSTOM_MODEL_CLASS) {
      if (definition.inverse !== undefined) {
        return definition.inverse;
      } else {
        //TODO add a test for this branch
        if (!definition._inverseKey) {
          return null;
        }
        return definition._inverseKey(this._store, modelClass);
      }
    } else {
      return definition._inverseKey(this._store, modelClass);
    }
  }

  inverseIsAsyncForRelationship(type: string, key: string): boolean {
    const modelClass = this._store.modelFor(type);
    const definition = upgradeForInternal(this.relationshipsDefinitionFor(type)[key]);
    if (CUSTOM_MODEL_CLASS) {
      if (definition.inverse === null) {
        return false;
      }
      if (definition.inverseIsAsync !== undefined) {
        return !!definition.inverseIsAsync;
      } else {
        return definition._inverseIsAsync(this._store, modelClass);
      }
    } else {
      return definition._inverseIsAsync(this._store, modelClass);
    }
  }

  notifyPropertyChange(type: string, id: string | null, lid: string, key: string): void;
  notifyPropertyChange(type: string, id: string, lid: string | null | undefined, key: string): void;
  notifyPropertyChange(type: string, id: string | null, lid: string | null | undefined, key: string): void {
    const resource = constructResource(type, id, lid);
    const identifier = identifierCacheFor(this._store).getOrCreateRecordIdentifier(resource);
    let internalModel = internalModelFactoryFor(this._store).peek(identifier);

    if (internalModel) {
      internalModel.notifyPropertyChange(key);
    }
  }

  notifyHasManyChange(type: string, id: string | null, lid: string, key: string): void;
  notifyHasManyChange(type: string, id: string, lid: string | null | undefined, key: string): void;
  notifyHasManyChange(type: string, id: string | null, lid: string | null | undefined, key: string): void {
    const resource = constructResource(type, id, lid);
    const identifier = identifierCacheFor(this._store).getOrCreateRecordIdentifier(resource);
    this._scheduleManyArrayUpdate(identifier, key);
  }

  notifyBelongsToChange(type: string, id: string | null, lid: string, key: string): void;
  notifyBelongsToChange(type: string, id: string, lid: string | null | undefined, key: string): void;
  notifyBelongsToChange(type: string, id: string | null, lid: string | null | undefined, key: string): void {
    const resource = constructResource(type, id, lid);
    const identifier = identifierCacheFor(this._store).getOrCreateRecordIdentifier(resource);
    let internalModel = internalModelFactoryFor(this._store).peek(identifier);

    if (internalModel) {
      internalModel.notifyBelongsToChange(key);
    }
  }

  notifyStateChange(type: string, id: string, lid: string | null, key?: string): void;
  notifyStateChange(type: string, id: string | null, lid: string, key?: string): void;
  notifyStateChange(type: string, id: string | null, lid: string | null, key?: string): void {
    const resource = constructResource(type, id, lid);
    const identifier = identifierCacheFor(this._store).getOrCreateRecordIdentifier(resource);
    let internalModel = internalModelFactoryFor(this._store).peek(identifier);

    if (internalModel) {
      internalModel.notifyStateChange(key);
    }
  }

  recordDataFor(type: string, id: string, lid?: string | null): RecordData;
  recordDataFor(type: string, id: string | null, lid: string): RecordData;
  recordDataFor(type: string): RecordData;
  recordDataFor(type: string, id?: string | null, lid?: string | null): RecordData {
    let identifier: StableRecordIdentifier | { type: string };
    let isCreate: boolean = false;
    if (!id && !lid) {
      isCreate = true;
      identifier = { type };
    } else {
      const resource = constructResource(type, id, lid);
      identifier = identifierCacheFor(this._store).getOrCreateRecordIdentifier(resource);
    }

    return this._store.recordDataFor(identifier, isCreate);
  }

  setRecordId(type: string, id: string, lid: string) {
    this._store.setRecordId(type, id, lid);
  }

  isRecordInUse(type: string, id: string | null, lid: string): boolean;
  isRecordInUse(type: string, id: string, lid?: string | null): boolean;
  isRecordInUse(type: string, id: string | null, lid?: string | null): boolean {
    const resource = constructResource(type, id, lid);
    const identifier = identifierCacheFor(this._store).getOrCreateRecordIdentifier(resource);
    let internalModel = internalModelFactoryFor(this._store).peek(identifier);
    if (!internalModel) {
      return false;
    }
    return internalModel.isRecordInUse();
  }

  disconnectRecord(type: string, id: string | null, lid: string): void;
  disconnectRecord(type: string, id: string, lid?: string | null): void;
  disconnectRecord(type: string, id: string | null, lid?: string | null): void {
    const resource = constructResource(type, id, lid);
    const identifier = identifierCacheFor(this._store).getOrCreateRecordIdentifier(resource);
    let internalModel = internalModelFactoryFor(this._store).peek(identifier);
    if (internalModel) {
      internalModel.destroyFromRecordData();
    }
  }
}