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

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);
  }
}