{"version":3,"sources":["../src/MongoProvider.ts"],"sourcesContent":["import {\n  asJson,\n  asNumber,\n  asString,\n  choose,\n  Condition,\n  Database,\n  entries,\n  Exception,\n  FetchOptions,\n  Field,\n  Id,\n  ifDefined,\n  ifTrue,\n  isArray,\n  isDefined,\n  isField,\n  isSortCondition,\n  json,\n  Json,\n  JsonValue,\n  LogicalCondition,\n  OneOrMore,\n  PageList,\n  Sort,\n  toArray,\n  toPageList,\n  tuple2,\n  tuple3,\n  use,\n  when,\n} from '@thisisagile/easy';\nimport {\n  AggregationCursor,\n  Collection as MongoCollection,\n  CreateIndexesOptions,\n  Document,\n  FindCursor,\n  FindOptions as MongoFindOptions,\n  IndexSpecification,\n  MongoClient,\n  StrictFilter as MongoFilter,\n} from 'mongodb';\nimport { Collection } from './Collection';\nimport { toMongoType } from './Utils';\n\nconst omitId = (j: Json): Json => json.delete(j, '_id');\n\nexport type Projection = Record<string, 0 | 1>;\nexport type FindOptions = FetchOptions & { projection?: Projection };\nexport type Filter<T = unknown> = MongoFilter<T>;\nexport type Query = Condition | LogicalCondition | Filter<any>;\n\nexport type IndexOptions = {\n  unique?: boolean;\n  filter?: Query;\n  languageOverride?: string;\n  languageDefault?: string;\n};\n\nexport type Indexes = OneOrMore<string | Field | Sort | Record<string, 1 | -1>>;\n\nexport type Options = { maxTimeMS?: number };\n\nexport class MongoProvider {\n  protected static readonly clients: { [key: string]: Promise<MongoClient> } = {};\n\n  constructor(readonly coll: Collection) {}\n\n  static destroyAll(): Promise<void> {\n    return Promise.all(entries(MongoProvider.clients).map(([u, c]) => c.then(c => c.close()).then(() => delete MongoProvider.clients[u]))).then(\n      () => undefined\n    );\n  }\n\n  private static connect(u: string, db: Database) {\n    return MongoClient.connect(u, {\n      auth: {\n        username: asString(db.options?.user),\n        password: asString(db.options?.password),\n      },\n      ...(db.options?.maxPoolSize && { maxPoolSize: db.options?.maxPoolSize }),\n      ...(db.options?.minPoolSize && { minPoolSize: db.options?.minPoolSize }),\n      ...(db.options?.maxIdleTimeMS && { maxIdleTimeMS: db.options?.maxIdleTimeMS }),\n    })\n      .then(c => {\n        c.on('error', () => delete MongoProvider.clients[u]);\n        c.on('close', () => delete MongoProvider.clients[u]);\n        return c;\n      })\n      .catch(err => {\n        delete MongoProvider.clients[u];\n        return Promise.reject(err);\n      });\n  }\n\n  cluster(): Promise<MongoClient> {\n    return use(this.coll.db, db =>\n      when(db.options?.cluster)\n        .not.isDefined.reject(Exception.IsNotValid.because('Missing cluster in database options.'))\n        .then(c => MongoProvider.clients[c] ?? (MongoProvider.clients[c] = MongoProvider.connect(c, db)))\n    );\n  }\n\n  collection<T extends Document = Document>(): Promise<MongoCollection<T>> {\n    return this.cluster()\n      .then(c => c.db(this.coll.db.name))\n      .then(db => db.collection<T>(asString(this.coll)));\n  }\n\n  toMongoJson(query: Query): Json {\n    return toMongoType(asJson(query));\n  }\n\n  find(query: Query, options?: FindOptions & Options): Promise<PageList<Json>> {\n    const { maxTimeMS, ...opts } = options ?? {};\n    return tuple3(this.collection(), this.toMongoJson(query), this.toFindOptions(opts))\n      .then(([c, q, o]) =>\n        tuple2(\n          c.find(q, { ...o, ...ifDefined(maxTimeMS, { maxTimeMS }, {}) }),\n          ifTrue(o.total, () =>\n            ifDefined(\n              maxTimeMS,\n              maxTimeMS => c.countDocuments(q, { maxTimeMS }),\n              () => c.countDocuments(q)\n            )\n          )\n        )\n      )\n      .then(([res, total]) => this.toArray(res, { ...opts, total }));\n  }\n\n  all(options?: FindOptions): Promise<PageList<Json>> {\n    return this.find({}, options);\n  }\n\n  byId(id: Id, options?: FindOptions): Promise<Json> {\n    return this.collection().then(c => c.findOne(this.toMongoJson({ id: id }), this.toFindOptions(options)) as Promise<Json>);\n  }\n\n  by(key: string, value: JsonValue, options?: FindOptions): Promise<PageList<Json>> {\n    return this.find({ [key]: value }, options);\n  }\n\n  group(qs: Filter<any>[], options?: Options): Promise<PageList<Json>> {\n    return this.aggregate(qs, options);\n  }\n\n  aggregate(qs: Filter<any>[], options?: Options): Promise<PageList<Json>> {\n    return this.collection()\n      .then(c =>\n        c.aggregate(\n          qs.map(q => this.toMongoJson(q)),\n          options\n        )\n      )\n      .then(res => this.toArray(res));\n  }\n\n  add(item: Json): Promise<Json> {\n    return this.collection()\n      .then(c => c.insertOne(omitId(item)))\n      .then(() => omitId(item));\n  }\n\n  update(item: Json): Promise<Json> {\n    return this.collection()\n      .then(c => c.updateOne(this.toMongoJson({ id: item.id }), { $set: omitId(item) }))\n      .then(() => this.byId(item.id as Id));\n  }\n\n  remove(id: Id): Promise<boolean> {\n    return this.collection()\n      .then(c => c.deleteOne(this.toMongoJson({ id })))\n      .then(d => d.acknowledged);\n  }\n\n  count(query?: Query, options?: Options): Promise<number> {\n    return this.collection().then(c => c.countDocuments(this.toMongoJson(query ?? {}), options));\n  }\n\n  createIndex(indexes: Indexes, options?: IndexOptions): Promise<string> {\n    return this.collection().then(c => c.createIndex(this.toIndexSpecification(indexes), this.toCreateIndexesOptions(options)));\n  }\n\n  createPartialIndex(indexes: Indexes, filter: Query, options?: Omit<IndexOptions, 'filter'>): Promise<string> {\n    return this.createIndex(indexes, { ...options, filter });\n  }\n\n  createTextIndex(indexes: OneOrMore<Field | string>, options?: IndexOptions): Promise<string> {\n    const ii = toArray(indexes).reduce((i, f) => ({ ...i, [asString(f)]: 'text' }), {});\n    return this.createIndex(ii, { unique: false, ...options });\n  }\n\n  protected toFindOptions(options?: FindOptions): MongoFindOptions & { total: boolean } {\n    return {\n      limit: asNumber(options?.take ?? 250),\n      ...(options?.skip && { skip: asNumber(options?.skip) }),\n      ...((options?.sorts && { sort: options?.sorts }) || (options?.sort && { sort: this.coll.sort(...(options?.sort ?? [])) })),\n      total: isDefined(options?.skip) || isDefined(options?.take),\n      projection: options?.projection ?? { _id: 0 },\n    };\n  }\n\n  protected toIndexSpecification(index: Indexes): IndexSpecification {\n    return choose(index)\n      .type(isField, f => f.property as IndexSpecification)\n      .type(isSortCondition, s => s.toJSON() as IndexSpecification)\n      .type(isArray, aa => aa.map(a => this.toIndexSpecification(a)) as IndexSpecification)\n      .else(i => i as IndexSpecification);\n  }\n\n  protected toCreateIndexesOptions(options?: IndexOptions): CreateIndexesOptions {\n    return {\n      unique: options?.unique ?? true,\n      ...(options?.languageOverride && { language_override: options.languageOverride }),\n      ...(options?.languageDefault && { default_language: options.languageDefault }),\n      ...(options?.filter && { partialFilterExpression: toMongoType(asJson(options.filter)) }),\n    };\n  }\n\n  protected toArray(\n    cursor: FindCursor<Document> | AggregationCursor<Document>,\n    options?: { take?: number; skip?: number; total?: number }\n  ): Promise<PageList<Json>> {\n    return cursor.toArray().then(r => toPageList<Json>(r, options));\n  }\n}\n"],"mappings":"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","names":["c","maxTimeMS"]}