#

API Docs for: v3.16.0-alpha.2
Show: Inherited Protected Private Deprecated

# File: ../store/addon/-private/system/schema-definition-service.ts

    import Store from './ds-model-store';
    import { RecordIdentifier } from '../ts-interfaces/identifier';
    import { get } from '@ember/object';
    import { getOwner } from '@ember/application';
    import normalizeModelName from './normalize-model-name';
    import { RelationshipsSchema, AttributesSchema } from '../ts-interfaces/record-data-schemas';
    import require from 'require';
    import CoreStore from './core-store';
    import { HAS_MODEL_PACKAGE } from '@ember-data/private-build-infra';

    type Model = import('@ember-data/model').default;

    let _Model;
    function getModel() {
      if (HAS_MODEL_PACKAGE) {
        _Model = _Model || require('@ember-data/model').default;
      }
      return _Model;
    }

    export class DSModelSchemaDefinitionService {
      private _modelFactoryCache = Object.create(null);
      private _relationshipsDefCache = Object.create(null);
      private _attributesDefCache = Object.create(null);

      constructor(public store: Store) {}

      // Following the existing RD implementation
      attributesDefinitionFor(identifier: RecordIdentifier | string): AttributesSchema {
        let modelName, attributes;
        if (typeof identifier === 'string') {
          modelName = identifier;
        } else {
          modelName = identifier.type;
        }

        attributes = this._attributesDefCache[modelName];

        if (attributes === undefined) {
          let modelClass = this.store.modelFor(modelName);
          let attributeMap = get(modelClass, 'attributes');

          attributes = Object.create(null);
          attributeMap.forEach((meta, name) => (attributes[name] = meta));
          this._attributesDefCache[modelName] = attributes;
        }

        return attributes;
      }

      // Following the existing RD implementation
      relationshipsDefinitionFor(identifier: RecordIdentifier | string): RelationshipsSchema {
        let modelName, relationships;
        if (typeof identifier === 'string') {
          modelName = identifier;
        } else {
          modelName = identifier.type;
        }

        relationships = this._relationshipsDefCache[modelName];

        if (relationships === undefined) {
          let modelClass = this.store.modelFor(modelName);
          relationships = get(modelClass, 'relationshipsObject') || null;
          this._relationshipsDefCache[modelName] = relationships;
        }

        return relationships;
      }

      doesTypeExist(modelName: string): boolean {
        let normalizedModelName = normalizeModelName(modelName);
        let factory = getModelFactory(this.store, this._modelFactoryCache, normalizedModelName);

        return factory !== null;
      }
    }

    /**
     *
     * @param store
     * @param cache modelFactoryCache
     * @param normalizedModelName already normalized modelName
     * @return {*}
     */
    export function getModelFactory(store: CoreStore, cache, normalizedModelName: string): Model | null {
      let factory = cache[normalizedModelName];

      if (!factory) {
        factory = _lookupModelFactory(store, normalizedModelName);

        if (!factory) {
          //Support looking up mixins as base types for polymorphic relationships
          factory = _modelForMixin(store, normalizedModelName);
        }

        if (!factory) {
          // we don't cache misses in case someone wants to register a missing model
          return null;
        }

        let klass = factory.class;

        if (klass.isModel) {
          let hasOwnModelNameSet = klass.modelName && Object.prototype.hasOwnProperty.call(klass, 'modelName');
          if (!hasOwnModelNameSet) {
            Object.defineProperty(klass, 'modelName', { value: normalizedModelName });
          }
        }

        cache[normalizedModelName] = factory;
      }

      return factory;
    }

    export function _lookupModelFactory(store, normalizedModelName) {
      let owner = getOwner(store);

      return owner.factoryFor(`model:${normalizedModelName}`);
    }

    /*
        In case someone defined a relationship to a mixin, for example:
        ```
          let Comment = Model.extend({
            owner: belongsTo('commentable'. { polymorphic: true })
          });
          let Commentable = Ember.Mixin.create({
            comments: hasMany('comment')
          });
        ```
        we want to look up a Commentable class which has all the necessary
        relationship metadata. Thus, we look up the mixin and create a mock
        Model, so we can access the relationship CPs of the mixin (`comments`)
        in this case
      */
    export function _modelForMixin(store, normalizedModelName) {
      if (HAS_MODEL_PACKAGE) {
        let owner = getOwner(store);
        let MaybeMixin = owner.factoryFor(`mixin:${normalizedModelName}`);
        let mixin = MaybeMixin && MaybeMixin.class;

        if (mixin) {
          let ModelForMixin = getModel().extend(mixin);
          ModelForMixin.reopenClass({
            __isMixin: true,
            __mixin: mixin,
          });

          //Cache the class as a model
          owner.register('model:' + normalizedModelName, ModelForMixin);
        }

        return _lookupModelFactory(store, normalizedModelName);
      }
    }