text: "use strict";
  // Copyright IBM Corp. 2017,2018. All Rights Reserved.
  // Node module: @loopback/repository
  // This file is licensed under the MIT License.
  // License text available at https://opensource.org/licenses/MIT
  Object.defineProperty(exports, "__esModule", { value: true });
  const legacy = require("loopback-datasource-juggler");
  const assert = require("assert");
  const context_1 = require("@loopback/context");
  const relation_factory_1 = require("./relation.factory");
  var juggler;
  (function (juggler) {
      juggler.DataSource = legacy.DataSource;
      juggler.ModelBase = legacy.ModelBase;
      juggler.PersistedModel = legacy.PersistedModel;
      juggler.KeyValueModel = legacy.KeyValueModel;
  })(juggler = exports.juggler || (exports.juggler = {}));
  /**
   * This is a bridge to the legacy DAO class. The function mixes DAO methods
   * into a model class and attach it to a given data source
   * @param modelClass {} Model class
   * @param ds {DataSource} Data source
   * @returns {} The new model class with DAO (CRUD) operations
   */
  function bindModel(modelClass, ds) {
      const boundModelClass = class extends modelClass {
      };
      boundModelClass.attachTo(ds);
      return boundModelClass;
  }
  exports.bindModel = bindModel;
  /**
   * Ensure the value is a promise
   * @param p Promise or void
   */
  /* tslint:disable-next-line:no-any */
  function ensurePromise(p) {
      if (p && context_1.isPromiseLike(p)) {
          // Juggler uses promise-like Bluebird instead of native Promise
          // implementation. We need to convert the promise returned by juggler
          // methods to proper native Promise instance.
          return Promise.resolve(p);
      }
      else {
          return Promise.reject(new Error('The value should be a Promise: ' + p));
      }
  }
  exports.ensurePromise = ensurePromise;
  /**
   * Default implementation of CRUD repository using legacy juggler model
   * and data source
   */
  class DefaultCrudRepository {
      /**
       * Constructor of DefaultCrudRepository
       * @param modelClass Legacy model class
       * @param dataSource Legacy data source
       */
      constructor(
      // entityClass should have type "typeof T", but that's not supported by TSC
      entityClass, dataSource) {
          this.entityClass = entityClass;
          this.dataSource = dataSource;
          const definition = entityClass.definition;
          assert(!!definition, `Entity ${entityClass.name} must have valid model definition.`);
          assert(definition.idProperties().length > 0, `Entity ${entityClass.name} must have at least one id/pk property.`);
          this.setupPersistedModel(definition);
      }
      // Create an internal legacy Model attached to the datasource
      setupPersistedModel(definition) {
          const dataSource = this.dataSource;
          const model = dataSource.getModel(definition.name);
          if (model) {
              // The backing persisted model has been already defined.
              this.modelClass = model;
              return;
          }
          // We need to convert property definitions from PropertyDefinition
          // to plain data object because of a juggler limitation
          const properties = {};
          // We need to convert PropertyDefinition into the definition that
          // the juggler understands
          Object.entries(definition.properties).forEach(([key, value]) => {
              if (value.type === 'array' || value.type === Array) {
                  value = Object.assign({}, value, { type: [value.itemType] });
                  delete value.itemType;
              }
              properties[key] = Object.assign({}, value);
          });
          this.modelClass = dataSource.createModel(definition.name, properties, Object.assign({ strict: true, strictDelete: true }, definition.settings));
          this.modelClass.attachTo(dataSource);
      }
      /**
       * Function to create a constrained relation repository factory
       *
       * ```ts
       * class CustomerRepository extends DefaultCrudRepository<
       *   Customer,
       *   typeof Customer.prototype.id
       * > {
       *   public orders: HasManyRepositoryFactory<Order, typeof Customer.prototype.id>;
       *
       *   constructor(
       *     protected db: juggler.DataSource,
       *     orderRepository: EntityCrudRepository<Order, typeof Order.prototype.id>,
       *   ) {
       *     super(Customer, db);
       *     this.orders = this._createHasManyRepositoryFactoryFor(
       *       'orders',
       *       orderRepository,
       *     );
       *   }
       * }
       * ```
       *
       * @param relationName Name of the relation defined on the source model
       * @param targetRepo Target repository instance
       */
      _createHasManyRepositoryFactoryFor(relationName, targetRepo) {
          const meta = this.entityClass.definition.relations[relationName];
          return relation_factory_1.createHasManyRepositoryFactory(meta, targetRepo);
      }
      async create(entity, options) {
          const model = await ensurePromise(this.modelClass.create(entity, options));
          return this.toEntity(model);
      }
      async createAll(entities, options) {
          const models = await ensurePromise(this.modelClass.create(entities, options));
          return this.toEntities(models);
      }
      save(entity, options) {
          const id = this.entityClass.getIdOf(entity);
          if (id == null) {
              return this.create(entity, options);
          }
          else {
              return this.replaceById(id, entity, options).then(result => result ? new this.entityClass(entity.toObject()) : null);
          }
      }
      async find(filter, options) {
          const models = await ensurePromise(this.modelClass.find(filter, options));
          return this.toEntities(models);
      }
      async findOne(filter, options) {
          const model = await ensurePromise(this.modelClass.findOne(filter, options));
          if (!model)
              return null;
          return this.toEntity(model);
      }
      async findById(id, filter, options) {
          const model = await ensurePromise(this.modelClass.findById(id, filter, options));
          if (!model) {
              throw new Error(`no ${this.modelClass.name} found with id "${id}"`);
          }
          return this.toEntity(model);
      }
      update(entity, options) {
          return this.updateById(entity.getId(), entity, options);
      }
      delete(entity, options) {
          return this.deleteById(entity.getId(), options);
      }
      updateAll(data, where, options) {
          where = where || {};
          return ensurePromise(this.modelClass.updateAll(where, data, options)).then(result => result.count);
      }
      updateById(id, data, options) {
          const idProp = this.modelClass.definition.idName();
          const where = {};
          where[idProp] = id;
          return this.updateAll(data, where, options).then(count => count > 0);
      }
      replaceById(id, data, options) {
          return ensurePromise(this.modelClass.replaceById(id, data, options)).then(result => !!result);
      }
      deleteAll(where, options) {
          return ensurePromise(this.modelClass.deleteAll(where, options)).then(result => result.count);
      }
      deleteById(id, options) {
          return ensurePromise(this.modelClass.deleteById(id, options)).then(result => result.count > 0);
      }
      count(where, options) {
          return ensurePromise(this.modelClass.count(where, options));
      }
      exists(id, options) {
          return ensurePromise(this.modelClass.exists(id, options));
      }
      async execute(command, 
      // tslint:disable:no-any
      parameters, options) {
          /* istanbul ignore next */
          throw new Error('Not implemented');
      }
      toEntity(model) {
          return new this.entityClass(model.toObject());
      }
      toEntities(models) {
          return models.map(m => this.toEntity(m));
      }
  }
  exports.DefaultCrudRepository = DefaultCrudRepository;
  //# sourceMappingURL=legacy-juggler-bridge.js.map