{"version":3,"sources":["jsdelivr-header.js","/npm/pg-promise-sandbox@0.0.1/index.js"],"names":[],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA,ACNA,MAAM,WAAa,QAAQ,eACrB,KAAO,QAAQ,SACf,OAAC,OAAM,QAAE,QAAO,SAAE,UAAY,QAAQ,eAO5C,MAAM,UACJ,WAAA,CAAY,EAAU,CAAC,GACrB,KAAK,GAAK,EAAQ,GAClB,KAAK,KAAO,EAAQ,MAAQ,OAC5B,KAAK,UAAY,CAAC,EAClB,KAAK,QAAU,IAAI,IAEf,EAAQ,OAAS,SAUnB,WAAW,WAAW,CACpB,KAAM,CAAC,EAAS,EAAO,KACjB,KAAK,QAAQ,IAAI,IACnB,KAAK,QAAQ,IAAI,EAAS,KAAK,QAAQ,IAAI,GAC7C,EAEF,QAAU,IACJ,KAAK,QAAQ,IAAI,IACjB,KAAK,QAAQ,OAAO,EACxB,IAED,QAEP,CAEA,QAAA,GAKE,GAAI,KAAK,OAAS,OAAQ,OAAO,KAAK,GAEtC,MAAM,EAAK,KAAK,QAAQ,IAAI,WAAW,oBACjC,EAAQ,KAAK,UAAU,GAE7B,OADW,EAAQ,EAAM,GAAK,KAAK,EAErC,CAMA,aAAA,GACE,MAAM,EAAK,KAAK,KAChB,KAAK,QAAQ,IAAI,WAAW,mBAAoB,GAEhD,MAAM,EAA4B,GAAc,GAAO,IAAI,SAAQ,CAAC,EAAG,KACrE,KAAK,UAAU,GAAM,CAAE,KAAI,YAC3B,EAAS,EAAE,IAIb,OAAO,IAAI,SAAQ,CAAC,EAAS,KAC3B,IAAI,GAAW,EACf,KAAK,GAAG,GAAG,GAA0B,IACnC,GAAW,EACX,EAAQ,EAAE,KAEX,OAAO,IACD,GAAY,IAAQ,UACvB,EAAO,EACT,GAED,GAEL,CAKA,kBAAM,GACJ,MAAM,EAAK,KAAK,QAAQ,IAAI,WAAW,oBACjC,EAAO,KAAK,UAAU,GAC5B,OAAK,SAEC,EAAK,SAAS,iBAEb,KAAK,UAAU,GACf,MALW,IAMpB,EAcF,MAAM,UAAa,IACjB,MAAM,EAAU,IAAI,UAAU,GAW9B,OAAO,IAAI,MAAM,EAVD,CACd,GAAA,CAAI,EAAQ,EAAM,GAChB,IAAK,QAAQ,IAAI,EAAQ,GAAO,CAC9B,MAAM,EAAO,EAAO,WACpB,OAAO,QAAQ,IAAI,EAAM,EAAM,EACjC,CACA,OAAO,QAAQ,IAAI,EAAQ,EAAM,EACnC,GAG+B,EAEnC,OAAO,QAAU,CAAE","file":"/npm/pg-promise-sandbox@0.0.1/index.js","sourceRoot":"","sourcesContent":["/**\n * Minified by jsDelivr using Terser v5.39.0.\n * Original file: /npm/pg-promise-sandbox@0.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","const asyncHooks = require('async_hooks')\nconst uuid = require('uuid')\nconst {NORMAL, SANDBOX, ROLLBACK} = require('./constants')\n\n/** \n *  Create a wrapper around pg-postgres that can capture references to transactions\n *  and trace async function calls.\n */\n\nclass Sandboxer {\n  constructor(options = {}) {\n    this.pg = options.pg\n    this.mode = options.mode || NORMAL\n    this.sandboxes = {}\n    this.context = new Map()\n\n    if (options.mode === SANDBOX ) {\n      \n      // With async_hooks, we can capture references to event and promise \n      // creation/destruction by id. Each async call has an id, and each \n      // function that triggers an async call has an id. \n      // \n      // We can store a reference to the initial trigger on every promise, and \n      // keep track of what \"scope\" our function is in. We can use this reference\n      // to isolate our postgres transactions.\n\n      asyncHooks.createHook({\n        init: (asyncId, _type, triggerAsyncId) =>{\n          if (this.context.has(triggerAsyncId)) {\n            this.context.set(asyncId, this.context.get(triggerAsyncId))\n          }\n        },\n        destroy: (asyncId) => {\n          if (this.context.has(asyncId)) {\n              this.context.delete(asyncId);\n          }\n        }\n      }).enable()\n    }\n  }\n\n  _getConn() {\n    // if we're scoped within a sandbox, grab the sandbox client so we can\n    // transparently add the next query to the sandboxed transaction, otherwise \n    // use the base database client.\n\n    if (this.mode === NORMAL) return this.pg\n\n    const id = this.context.get(asyncHooks.executionAsyncId())\n    const found = this.sandboxes[id] \n    let conn = found ? found.tx : this.pg\n    return conn\n  }\n\n  /**\n   * Creates a transaction sandbox. Puts all database calls made within the \n   * \"promise chain\"/async function stack into the current transaction.\n   */\n  createSandbox() {\n    const id = uuid.v4()\n    this.context.set(asyncHooks.executionAsyncId(), id)\n\n    const grabTransactionReference = (callback) => (tx) => new Promise((_, rollback)=> {\n      this.sandboxes[id] = { tx, rollback }\n      callback(id)\n    })\n\n\n    return new Promise((resolve, reject) => {\n      let resolved = false\n      this.pg.tx(grabTransactionReference((id) => { \n        resolved = true\n        resolve(id) \n      }))\n      .catch((err) => {\n        if (!resolved || err !== ROLLBACK) {\n          reject(err)\n        }\n\n      })\n    })\n  }\n\n  /**\n   * Closes a transaction sandbox, rolling back all changes.\n   */\n  async closeSandbox() {\n    const id = this.context.get(asyncHooks.executionAsyncId());\n    const conn = this.sandboxes[id]\n    if (!conn) return this\n    \n    await conn.rollback(ROLLBACK)\n\n    delete this.sandboxes[id]\n    return this\n  }\n\n}\n\n\n/**\n * Wrap up your pg-promise client with a sandbox mode.\n * \n * @param {*} options - an object of options.\n * @param options.pg - your pg-promise client, initalized.\n * @param options.mode - Either 'normal' or 'sandbox'. 'normal' mode does not \n * initialize async_hooks.\n * @returns {pgPromise.IDatabase<{}, pg.IClient>} a wrapped pg promise client.\n */\nconst pgSandbox = (options) => {\n  const sandbox = new Sandboxer(options)\n  const handler = {\n    get(target, name, reciever) {\n      if (!Reflect.has(target, name)) {\n        const conn = target._getConn()\n        return Reflect.get(conn, name, reciever)  \n      }\n      return Reflect.get(target, name, reciever)\n    }\n  }\n\n  return new Proxy(sandbox, handler)\n}\nmodule.exports = { pgSandbox }"]}