{"version":3,"sources":["jsdelivr-header.js","/npm/dobo@2.0.1/index.js"],"names":[],"mappings":"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","file":"/npm/dobo@2.0.1/index.js","sourceRoot":"","sourcesContent":["/**\n * Minified by jsDelivr using Terser v5.39.0.\n * Original file: /npm/dobo@2.0.1/index.js\n *\n * Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files\n */\n","import collectConnections from './lib/collect-connections.js'\r\nimport collectDrivers from './lib/collect-drivers.js'\r\nimport collectFeatures from './lib/collect-features.js'\r\nimport collectSchemas from './lib/collect-schemas.js'\r\nimport memDbStart from './lib/mem-db/start.js'\r\nimport memDbInstantiate from './lib/mem-db/instantiate.js'\r\nimport nql from '@tryghost/nql'\r\nimport path from 'path'\r\n\r\n/**\r\n * @typedef {string} TRecordSortKey\r\n */\r\n\r\n/**\r\n * Key value pairs used as sort information:\r\n * - Key represent model's field name\r\n * - value represent its sort order: ```1``` for ascending order, and ```-1``` for descending order\r\n *\r\n * Example: to sort by firstName (ascending) and lastName (descending)\r\n * ```javascript\r\n * const sort = {\r\n *   firstName: 1,\r\n *   lastName: -1\r\n * }\r\n * ```\r\n *\r\n * @typedef {Object.<string, TRecordSortKey>} TRecordSort\r\n */\r\n\r\n/**\r\n * @typedef {Object} TRecordPagination\r\n * @property {number} limit - Number of records per page\r\n * @property {number} page - Page number\r\n * @property {number} skip - Records to skip\r\n * @property {TRecordSort} sort - Sort order\r\n */\r\n\r\n/**\r\n * @typedef {Object} TPropType\r\n * @property {Object} integer\r\n * @property {string} [integer.validator=number]\r\n * @property {Object} smallint\r\n * @property {string} [smallint.validator=number]\r\n * @property {Object} text\r\n * @property {string} [text.validator=string]\r\n * @property {string} [text.textType=string]\r\n * @property {string[]} [text.values=['text', 'mediumtext', 'longtext']]\r\n * @property {Object} string\r\n * @property {string} [string.validator=string]\r\n * @property {maxLength} [string.maxLength=255]\r\n * @property {minLength} [string.minLength=0]\r\n * @property {Object} float\r\n * @property {string} [float.validator=number]\r\n * @property {Object} double\r\n * @property {string} [double.validator=number]\r\n * @property {Object} boolean\r\n * @property {string} [boolean.validator=boolean]\r\n * @property {Object} datetime\r\n * @property {string} [datetime.validator=date]\r\n * @property {Object} date\r\n * @property {string} [date.validator=date]\r\n * @property {Object} time\r\n * @property {string} [time.validator=date]\r\n * @property {Object} timestamp\r\n * @property {string} [timestamp.validator=timestamp]\r\n * @property {Object} object={}\r\n * @property {Object} array={}\r\n */\r\nconst propType = {\r\n  integer: {\r\n    validator: 'number'\r\n  },\r\n  smallint: {\r\n    validator: 'number'\r\n  },\r\n  text: {\r\n    validator: 'string',\r\n    textType: 'text',\r\n    values: ['text', 'mediumtext', 'longtext']\r\n  },\r\n  string: {\r\n    validator: 'string',\r\n    maxLength: 255,\r\n    minLength: 0\r\n  },\r\n  float: {\r\n    validator: 'number'\r\n  },\r\n  double: {\r\n    validator: 'number'\r\n  },\r\n  boolean: {\r\n    validator: 'boolean'\r\n  },\r\n  date: {\r\n    validator: 'date'\r\n  },\r\n  datetime: {\r\n    validator: 'date'\r\n  },\r\n  time: {\r\n    validator: 'date'\r\n  },\r\n  timestamp: {\r\n    validator: 'timestamp'\r\n  },\r\n  object: {},\r\n  array: {}\r\n}\r\n\r\n/**\r\n * Plugin factory\r\n *\r\n * @param {string} pkgName - NPM package name\r\n * @returns {class}\r\n */\r\nasync function factory (pkgName) {\r\n  const me = this\r\n\r\n  /**\r\n   * Dobo Database Framework for {@link https://github.com/ardhi/bajo|Bajo}.\r\n   *\r\n   * See {@tutorial ecosystem} for available drivers & tools\r\n   *\r\n   * @class\r\n   */\r\n  class Dobo extends this.app.pluginClass.base {\r\n    /**\r\n     * @constant {string}\r\n     * @memberof Dobo\r\n     * @default 'db'\r\n     */\r\n    static alias = 'db'\r\n\r\n    /**\r\n     * @constant {string[]}\r\n     * @memberof Dobo\r\n     * @default ['count', 'avg', 'min', 'max', 'sum']\r\n     */\r\n    static aggregateTypes = ['count', 'avg', 'min', 'max', 'sum']\r\n    /**\r\n     * @constant {TPropType}\r\n     * @memberof Dobo\r\n     */\r\n    static propType = propType\r\n\r\n    constructor () {\r\n      super(pkgName, me.app)\r\n      this.config = {\r\n        connections: [],\r\n        validationParams: {\r\n          abortEarly: false,\r\n          convert: false,\r\n          allowUnknown: true\r\n        },\r\n        default: {\r\n          property: {\r\n            text: {\r\n              textType: 'text'\r\n            },\r\n            string: {\r\n              length: 50\r\n            }\r\n          },\r\n          filter: {\r\n            limit: 25,\r\n            maxLimit: 200,\r\n            hardLimit: 10000,\r\n            sort: ['dt:-1', 'updatedAt:-1', 'updated_at:-1', 'createdAt:-1', 'createdAt:-1', 'ts:-1', 'username', 'name']\r\n          },\r\n          idField: {\r\n            type: 'string',\r\n            maxLength: 50,\r\n            required: true,\r\n            index: { type: 'primary' }\r\n          }\r\n        },\r\n        memDb: {\r\n          createDefConnAtStart: true,\r\n          persistence: {\r\n            syncPeriodDur: '1s'\r\n          }\r\n        },\r\n        applet: {\r\n          confirmation: false\r\n        }\r\n      }\r\n\r\n      /**\r\n       * @type {Object[]}\r\n       */\r\n      this.drivers = []\r\n\r\n      /**\r\n       * @type {Object[]}\r\n       */\r\n      this.connections = []\r\n\r\n      /**\r\n       * @type {Object[]}\r\n       */\r\n      this.features = []\r\n\r\n      /**\r\n       * @type {Object[]}\r\n       */\r\n      this.schemas = []\r\n    }\r\n\r\n    /**\r\n     * Initialize plugin and performing the following tasks:\r\n     * - {@link module:Lib.collectDrivers|Collecting all drivers}\r\n     * - {@link module:Lib.collectConnections|Collecting all connections}\r\n     * - {@link module:Lib.collectFeatures|Collecting all features}\r\n     * - {@link module:Lib.collectSchemas|Collecting all schemas}\r\n     * @method\r\n     * @async\r\n     */\r\n    init = async () => {\r\n      const { buildCollections } = this.app.bajo\r\n      const { fs } = this.app.lib\r\n      const checkType = async (item, items) => {\r\n        const { filter } = this.app.lib._\r\n        const existing = filter(items, { type: 'dobo:memory' })\r\n        if (existing.length > 1) this.fatal('onlyOneConnType%s', item.type)\r\n      }\r\n\r\n      fs.ensureDirSync(`${this.dir.data}/attachment`)\r\n      await collectDrivers.call(this)\r\n      if (this.config.memDb.createDefConnAtStart) {\r\n        this.config.connections.push({\r\n          type: 'dobo:memory',\r\n          name: 'memory'\r\n        })\r\n      }\r\n      this.connections = await buildCollections({ ns: this.ns, container: 'connections', handler: collectConnections, dupChecks: ['name', checkType] })\r\n      if (this.connections.length === 0) this.log.warn('notFound%s', this.t('connection'))\r\n      await collectFeatures.call(this)\r\n      await collectSchemas.call(this)\r\n    }\r\n\r\n    /**\r\n     * Start plugin\r\n     *\r\n     * @method\r\n     * @async\r\n     * @param {(string|Array)} [conns=all] - Which connections should be run on start\r\n     * @param {boolean} [noRebuild=false] - Set ```true``` to ALWAYS rebuild model on start. Yes, only set it to ```true``` if you REALLY know what you're doing!!!\r\n     */\r\n    start = async (conns = 'all', noRebuild = true) => {\r\n      const { importModule, breakNsPath } = this.app.bajo\r\n      const { find, filter, isString, map } = this.app.lib._\r\n      if (conns === 'all') conns = this.connections\r\n      else if (isString(conns)) conns = filter(this.connections, { name: conns })\r\n      else conns = map(conns, c => find(this.connections, { name: c }))\r\n      for (const c of conns) {\r\n        const { ns } = breakNsPath(c.type)\r\n        const schemas = filter(this.schemas, { connection: c.name })\r\n        const mod = c.type === 'dobo:memory' ? memDbInstantiate : await importModule(`${ns}:/extend/${this.ns}/boot/instantiate.js`)\r\n        await mod.call(this.app[ns], { connection: c, noRebuild, schemas })\r\n        this.log.trace('driverInstantiated%s%s', c.driver, c.name)\r\n      }\r\n      await memDbStart.call(this)\r\n    }\r\n\r\n    /**\r\n     * Pick only fields defined from a record\r\n     *\r\n     * @method\r\n     * @async\r\n     * @param {Object} [options={}] - Options object\r\n     * @param {Object} options.record - Record to pick fields from\r\n     * @param {Array} options.fields - Array of field names to be picked\r\n     * @param {Object} options.schema - Associated record's schema\r\n     * @param {Object} [options.hidden=[]] - Additional fields to be hidden in addition the one defined in schema\r\n     * @param {boolean} [options.forceNoHidden] - Force ALL fields to be picked, thus ignoring hidden fields\r\n     * @returns {Object}\r\n     */\r\n    pickRecord = async ({ record, fields, schema = {}, hidden = [], forceNoHidden } = {}) => {\r\n      const { isArray, pick, clone, isEmpty, omit } = this.app.lib._\r\n      const { dayjs } = this.app.lib\r\n\r\n      const transform = async ({ record, schema, hidden = [], forceNoHidden } = {}) => {\r\n        if (record._id) {\r\n          record.id = record._id\r\n          delete record._id\r\n        }\r\n        const defHidden = [...schema.hidden, ...hidden]\r\n        let result = {}\r\n        for (const p of schema.properties) {\r\n          if (!forceNoHidden && defHidden.includes(p.name)) continue\r\n          result[p.name] = record[p.name] ?? null\r\n          if (record[p.name] === null) continue\r\n          switch (p.type) {\r\n            case 'boolean': result[p.name] = !!result[p.name]; break\r\n            case 'time': result[p.name] = dayjs(record[p.name]).format('HH:mm:ss'); break\r\n            case 'date': result[p.name] = dayjs(record[p.name]).format('YYYY-MM-DD'); break\r\n            case 'datetime': result[p.name] = dayjs(record[p.name]).toISOString(); break\r\n          }\r\n        }\r\n        result = await this.sanitizeBody({ body: result, schema, partial: true, ignoreNull: true })\r\n        if (record._rel) result._rel = record._rel\r\n        return result\r\n      }\r\n\r\n      if (isEmpty(record)) return record\r\n      if (hidden.length > 0) record = omit(record, hidden)\r\n      if (!isArray(fields)) return await transform.call(this, { record, schema, hidden, forceNoHidden })\r\n      const fl = clone(fields)\r\n      if (!fl.includes('id')) fl.unshift('id')\r\n      if (record._rel) fl.push('_rel')\r\n      return pick(await transform.call(this, { record, schema, hidden, forceNoHidden }), fl)\r\n    }\r\n\r\n    /**\r\n     * Prepare records pagination:\r\n     * - making sure records limit is obeyed\r\n     * - making sure page is a positive value\r\n     * - if skip is given, recalculate limit to use skip instead of page number\r\n     * - Build sort info\r\n     *\r\n     * @method\r\n     * @async\r\n     * @param {Object} [filter={}] - Filter object\r\n     * @param {Object} schema - Model's schema\r\n     * @param {Object} options - Options\r\n     * @returns {TRecordPagination}\r\n     */\r\n    prepPagination = async (filter = {}, schema, options = {}) => {\r\n      const buildPageSkipLimit = (filter) => {\r\n        let limit = parseInt(filter.limit) || this.config.default.filter.limit\r\n        if (limit === -1) limit = this.config.default.filter.maxLimit\r\n        if (limit > this.config.default.filter.maxLimit) limit = this.config.default.filter.maxLimit\r\n        if (limit < 1) limit = 1\r\n        let page = parseInt(filter.page) || 1\r\n        if (page < 1) page = 1\r\n        let skip = (page - 1) * limit\r\n        if (filter.skip) {\r\n          skip = parseInt(filter.skip) || skip\r\n          page = undefined\r\n        }\r\n        if (skip < 0) skip = 0\r\n        return { page, skip, limit }\r\n      }\r\n\r\n      const buildSort = (input, schema, allowSortUnindexed) => {\r\n        const { isEmpty, map, each, isPlainObject, isString, trim, keys } = this.app.lib._\r\n        let sort\r\n        if (schema && isEmpty(input)) {\r\n          const columns = map(schema.properties, 'name')\r\n          each(this.config.default.filter.sort, s => {\r\n            const [col] = s.split(':')\r\n            if (columns.includes(col)) {\r\n              input = s\r\n              return false\r\n            }\r\n          })\r\n        }\r\n        if (!isEmpty(input)) {\r\n          if (isPlainObject(input)) sort = input\r\n          else if (isString(input)) {\r\n            const item = {}\r\n            each(input.split('+'), text => {\r\n              let [col, dir] = map(trim(text).split(':'), i => trim(i))\r\n              dir = (dir ?? '').toUpperCase()\r\n              dir = dir === 'DESC' ? -1 : parseInt(dir) || 1\r\n              item[col] = dir / Math.abs(dir)\r\n            })\r\n            sort = item\r\n          }\r\n          if (schema) {\r\n            const items = keys(sort)\r\n            each(items, i => {\r\n              if (!schema.sortables.includes(i) && !allowSortUnindexed) throw this.error('sortOnUnindexedField%s%s', i, schema.name)\r\n              // if (schema.fullText.fields.includes(i)) throw this.error('Can\\'t sort on full-text index: \\'%s@%s\\'', i, schema.name)\r\n            })\r\n          }\r\n        }\r\n        return sort\r\n      }\r\n\r\n      const { page, skip, limit } = buildPageSkipLimit.call(this, filter)\r\n      let sortInput = filter.sort\r\n      try {\r\n        sortInput = JSON.parse(sortInput)\r\n      } catch (err) {}\r\n      const sort = buildSort.call(this, sortInput, schema, options.allowSortUnindexed)\r\n      return { limit, page, skip, sort }\r\n    }\r\n\r\n    buildMatch = ({ input = '', schema, options }) => {\r\n      const { isPlainObject, trim } = this.app.lib._\r\n      if (isPlainObject(input)) return input\r\n      const split = (value, schema) => {\r\n        let [field, val] = value.split(':').map(i => i.trim())\r\n        if (!val) {\r\n          val = field\r\n          field = '*'\r\n        }\r\n        return { field, value: val }\r\n      }\r\n      input = trim(input)\r\n      let items = {}\r\n      if (isPlainObject(input)) items = input\r\n      else if (input[0] === '{') items = JSON.parse(input)\r\n      else {\r\n        for (const item of input.split('+').map(i => i.trim())) {\r\n          const part = split(item, schema)\r\n          if (!items[part.field]) items[part.field] = []\r\n          items[part.field].push(...part.value.split(' ').filter(v => ![''].includes(v)))\r\n        }\r\n      }\r\n      const matcher = {}\r\n      for (const f of schema.fullText.fields) {\r\n        const value = []\r\n        if (typeof items[f] === 'string') items[f] = [items[f]]\r\n        if (Object.prototype.hasOwnProperty.call(items, f)) value.push(...items[f])\r\n        matcher[f] = value\r\n      }\r\n      if (Object.prototype.hasOwnProperty.call(items, '*')) matcher['*'] = items['*']\r\n      return matcher\r\n    }\r\n\r\n    buildQuery = ({ filter, schema, options = {} } = {}) => {\r\n      const { trim, find, isString, isPlainObject } = this.app.lib._\r\n      let query = {}\r\n      if (isString(filter.query)) {\r\n        try {\r\n          filter.query = trim(filter.query)\r\n          filter.orgQuery = filter.query\r\n          if (trim(filter.query).startsWith('{')) query = JSON.parse(filter.query)\r\n          else if (filter.query.includes(':')) query = nql(filter.query).parse()\r\n          else {\r\n            const fields = schema.sortables.filter(f => {\r\n              const field = find(schema.properties, { name: f, type: 'string' })\r\n              return !!field\r\n            })\r\n            const parts = fields.map(f => {\r\n              if (filter.query[0] === '*') return `${f}:~$'${filter.query.replaceAll('*', '')}'`\r\n              if (filter.query[filter.length - 1] === '*') return `${f}:~^'${filter.query.replaceAll('*', '')}'`\r\n              return `${f}:~'${filter.query.replaceAll('*', '')}'`\r\n            })\r\n            if (parts.length === 1) query = nql(parts[0]).parse()\r\n            else if (parts.length > 1) query = nql(parts.join(',')).parse()\r\n          }\r\n        } catch (err) {\r\n          this.error('invalidQuery', { orgMessage: err.message })\r\n        }\r\n      } else if (isPlainObject(filter.query)) query = filter.query\r\n      return this.sanitizeQuery(query, schema)\r\n    }\r\n\r\n    sanitizeQuery = (query, schema, parent) => {\r\n      const { cloneDeep, isPlainObject, isArray, find } = this.app.lib._\r\n      const { isSet } = this.app.lib.aneka\r\n      const { dayjs } = this.app.lib\r\n      const obj = cloneDeep(query)\r\n      const keys = Object.keys(obj)\r\n      const sanitize = (key, val, p) => {\r\n        if (!isSet(val)) return val\r\n        const prop = find(schema.properties, { name: key.startsWith('$') ? p : key })\r\n        if (!prop) return val\r\n        if (['datetime', 'date', 'time'].includes(prop.type)) {\r\n          const dt = dayjs(val)\r\n          return dt.isValid() ? dt.toDate() : val\r\n        } else if (['smallint', 'integer'].includes(prop.type)) return parseInt(val) || val\r\n        else if (['float', 'double'].includes(prop.type)) return parseFloat(val) || val\r\n        else if (['boolean'].includes(prop.type)) return !!val\r\n        return val\r\n      }\r\n      keys.forEach(k => {\r\n        const v = obj[k]\r\n        if (isPlainObject(v)) obj[k] = this.sanitizeQuery(v, schema, k)\r\n        else if (isArray(v)) {\r\n          v.forEach((i, idx) => {\r\n            if (isPlainObject(i)) obj[k][idx] = this.sanitizeQuery(i, schema, k)\r\n          })\r\n        } else obj[k] = sanitize(k, v, parent)\r\n      })\r\n      return obj\r\n    }\r\n\r\n    validationErrorMessage = (err) => {\r\n      let text = err.message\r\n      if (err.details) {\r\n        text += ' -> '\r\n        text += this.app.bajo.join(err.details.map((d, idx) => {\r\n          return `${d.field}@${err.model}: ${d.error} (${d.value})`\r\n        }))\r\n      }\r\n      return text\r\n    }\r\n\r\n    getConnection = (name) => {\r\n      const { find } = this.app.lib._\r\n      return find(this.connections, { name })\r\n    }\r\n\r\n    getInfo = (name) => {\r\n      const { breakNsPath } = this.app.bajo\r\n      const { find, map, isEmpty } = this.app.lib._\r\n      const schema = this.getSchema(name)\r\n      const conn = this.getConnection(schema.connection)\r\n      let { ns, path: type } = breakNsPath(conn.type)\r\n      if (isEmpty(type)) type = conn.type\r\n      const driver = find(this.drivers, { type, ns, driver: conn.driver })\r\n      const instance = find(this.app[driver.ns].instances, { name: schema.connection })\r\n      const opts = conn.type === 'mssql' ? { includeTriggerModifications: true } : undefined\r\n      const returning = [map(schema.properties, 'name'), opts]\r\n      return { instance, driver, connection: conn, returning, schema }\r\n    }\r\n\r\n    getSchema = (input, cloned = true) => {\r\n      const { find, isPlainObject, cloneDeep } = this.app.lib._\r\n      const { pascalCase } = this.app.lib.aneka\r\n      let name = isPlainObject(input) ? input.name : input\r\n      name = pascalCase(name)\r\n      const schema = find(this.schemas, { name })\r\n      if (!schema) throw this.error('unknownModelSchema%s', name)\r\n      return cloned ? cloneDeep(schema) : schema\r\n    }\r\n\r\n    getField = (name, model) => {\r\n      const { getInfo } = this.app.dobo\r\n      const { find } = this.app.lib._\r\n      const { schema } = getInfo(model)\r\n\r\n      return find(schema.properties, { name })\r\n    }\r\n\r\n    hasField = (name, model) => {\r\n      return !!this.getField(name, model)\r\n    }\r\n\r\n    getMemdbStorage = (name, fields = []) => {\r\n      const { map, pick } = this.app.lib._\r\n      const all = this.memDb.storage[name] ?? []\r\n      if (fields.length === 0) return all\r\n      return map(all, item => pick(item, fields))\r\n    }\r\n\r\n    listAttachments = async ({ model, id = '*', field = '*', file = '*' } = {}, { uriEncoded = true } = {}) => {\r\n      const { map, kebabCase } = this.app.lib._\r\n      const { pascalCase } = this.app.lib.aneka\r\n      const { importPkg, getPluginDataDir } = this.app.bajo\r\n      const mime = await importPkg('waibu:mime')\r\n      const { fastGlob } = this.app.lib\r\n      const root = `${getPluginDataDir('dobo')}/attachment`\r\n      model = pascalCase(model)\r\n      let pattern = `${root}/${model}/${id}/${field}/${file}`\r\n      if (uriEncoded) pattern = pattern.split('/').map(p => decodeURI(p)).join('/')\r\n      return map(await fastGlob(pattern), f => {\r\n        const mimeType = mime.getType(path.extname(f)) ?? ''\r\n        const fullPath = f.replace(root, '')\r\n        const row = {\r\n          file: f,\r\n          fileName: path.basename(fullPath),\r\n          fullPath,\r\n          mimeType,\r\n          params: { model, id, field, file }\r\n        }\r\n        if (this.app.waibuMpa) {\r\n          const { routePath } = this.app.waibu\r\n          const [, _model, _id, _field, _file] = fullPath.split('/')\r\n          row.url = routePath(`dobo:/attachment/${kebabCase(_model)}/${_id}/${_field}/${_file}`)\r\n        }\r\n        return row\r\n      })\r\n    }\r\n  }\r\n\r\n  return Dobo\r\n}\r\n\r\nexport default factory\r\n"]}