adapt-authoring-mongodb/lib/ObjectIdUtils.js

import { App, Utils } from 'adapt-authoring-core'
import { ObjectId } from 'mongodb'
/**
 * Utility functions for dealing with MongoDB ObjectIds
 * @memberof mongodb
 */
class ObjectIdUtils {
  /**
   * Registers the isObjectId JSON schema keyword
   */
  static async addSchemaKeyword () {
    const jsonschema = await App.instance.waitForModule('jsonschema')
    jsonschema.addKeyword({
      keyword: 'isObjectId',
      type: 'string',
      modifying: true,
      schemaType: 'boolean',
      compile: () => {
        return (value, { parentData, parentDataProperty }) => {
          if (!ObjectIdUtils.isValid(value)) {
            return false
          }
          try {
            parentData[parentDataProperty] = ObjectIdUtils.parse(value)
          } catch (e) {
            return false
          }
          return true
        }
      }
    })
  }

  /**
   * Creates a new ObjectId instance
   * @return {external:MongoDBObjectId}
   */
  static create () {
    return new ObjectId()
  }

  /**
   * Checks a string is a valid ObjectId
   * @param {String} s String to check
   * @return {Boolean}
   */
  static isValid (s) {
    try {
      return ObjectIdUtils.parse(s).equals(s)
    } catch (e) {
      return false
    }
  }

  /**
   * Converts a string to an ObjectId
   * @param {String} s The string to convert
   * @return {external:MongoDBObjectId} The converted ID
   * @throws {Error}
   */
  static parse (s) {
    if (ObjectIdUtils.isObjectId(s)) {
      return s
    }
    if (!ObjectId.isValid(s)) {
      throw App.instance.errors.INVALID_OBJECTID.setData({ value: s })
    }
    return new ObjectId(s)
  }

  /**
   * Checks an input object for any strings which pass the parse check and convert matches to ObjectId instances
   * @param {Object} o Object to be checked
   */
  static parseIds (o) {
    if (o === undefined) {
      return
    }
    Object.entries(o).forEach(([k, v]) => {
      if (Utils.isObject(v)) {
        this.parseIds(v)
      } else if (Array.isArray(v)) {
        v.forEach((v2, i) => {
          try {
            if (typeof v2 === 'string') v[i] = this.parse(v2)
          } catch (e) {} // ignore failures
          this.parseIds(v2)
        })
      } else if (typeof v === 'string' && this.isValid(v)) {
        try {
          o[k] = this.parse(v)
        } catch (e) {} // ignore failures
      }
    })
  }

  static isObjectId (data) {
    return data instanceof ObjectId
  }
}

export default ObjectIdUtils