class Collection {
  constructor(tablename, driver) {
    this.driver = driver;
    this.table = tablename;
  }

  getByIdAsync = function (_id) {
    return this.driver.then((driver) => driver.getByIdAsync(this.table, _id));
  };

  updateAsync = function (value) {
    return this.driver.then((driver) =>
      driver.updateAsync(this.table, value, value._id)
    );
  };

  deleteAsync = function deleteAsync(_id) {
    return this.driver.then((driver) => driver.deleteAsync(this.table, _id));
  };

  deleteAllAsync = function deleteAllAsync(criteria) {
    return this.driver.then((driver) =>
      driver.deleteAllAsync(this.table, criteria)
    );
  };

  findAllAsync = function findAllAsync(criteria) {
    return this.driver.then((driver) =>
      driver.findAllAsync(this.table, criteria)
    );
  };

  findOneAsync = function findOneAsync(criteria) {
    return this.driver.then((driver) =>
      driver.findOneAsync(this.table, criteria)
    );
  };

  saveAsync = function (value) {
    return this.driver.then((driver) => driver.saveAsync(this.table, value));
  };

  setAsync = function setAsync(id, values) {
    const update = { $set: values };
    return this.driver
      .then((driver) => driver.partialUpdateAsync(this.table, update, id))
      .then(() => Promise.resolve(true));
  };

  getByPageAsync = function (
    pageNumber,
    pageSize = 50,
    match = {},
    sort = { _updated_at: -1 }
  ) {
    let pipeline = [
      {
        $match: match,
      },
      {
        $sort: sort,
      },
      {
        $group: {
          _id: null,
          total: {
            $sum: 1,
          },
          data: {
            $push: "$$ROOT",
          },
        },
      },
      {
        $project: {
          _id: 0,
          pages: {
            $ceil: {
              $divide: ["$total", pageSize],
            },
          },
          items: {
            $slice: ["$data", (pageNumber - 1) * pageSize, pageSize],
          },
        },
      },
    ];

    return this.driver
      .then((driver) => driver.aggregateAsync(this.table, pipeline))
      .then((array) => array[0]);
  };
}
