import * as mongo from "mongodb" import { Action as UpdateAction } from "./Action" export type Update = { [P in keyof T]?: UpdateAction | Update | any } export namespace Update { function update( query: mongo.UpdateFilter, operation: UpdateAction.Operator, field: string, value: any ): mongo.UpdateFilter { const r: { [f: string]: any } = query[operation] ?? {} r[field] = value query[operation] = r as any return query } export function toMongo( update: Update, ...suppress: (string | undefined)[] ): mongo.UpdateFilter> { const result: mongo.UpdateFilter> = {} for (const field in update) if (Object.prototype.hasOwnProperty.call(update, field) && !suppress.some(s => s == field)) { const value = update[field] toMongoUpdate(result, field, value) } return result } function toMongoUpdate(query: mongo.UpdateFilter, prefix: string, value: any) { if (Array.isArray(value)) update(query, "$push", prefix, { $each: value.filter(v => v != undefined) }) else if (typeof value != "object" && value != undefined) update(query, "$set", prefix, value) else for (const field in value) { if (Object.prototype.hasOwnProperty.call(value, field)) { const v = value[field] if (UpdateAction.Operator.is(field) && v != undefined) update(query, field, prefix, v) else if (!field.startsWith("$")) toMongoUpdate(query, prefix + "." + field, v) } } } export function extract(update: Update): Update { const result: Update = {} for (const field in update) if (Object.prototype.hasOwnProperty.call(update, field)) { const value = UpdateAction.extract(update[field]) if (value != undefined && value != null) result[field] = value } return result } export type Action = UpdateAction export namespace Action { export const extract = UpdateAction.extract } }