174 lines
3.5 KiB
JavaScript
174 lines
3.5 KiB
JavaScript
const originCache = new Map()
|
|
, originStackCache = new Map()
|
|
, originError = Symbol('OriginError')
|
|
|
|
export const CLOSE = {}
|
|
export class Query extends Promise {
|
|
constructor(strings, args, handler, canceller, options = {}) {
|
|
let resolve
|
|
, reject
|
|
|
|
super((a, b) => {
|
|
resolve = a
|
|
reject = b
|
|
})
|
|
|
|
this.tagged = Array.isArray(strings.raw)
|
|
this.strings = strings
|
|
this.args = args
|
|
this.handler = handler
|
|
this.canceller = canceller
|
|
this.options = options
|
|
|
|
this.state = null
|
|
this.statement = null
|
|
|
|
this.resolve = x => (this.active = false, resolve(x))
|
|
this.reject = x => (this.active = false, reject(x))
|
|
|
|
this.active = false
|
|
this.cancelled = null
|
|
this.executed = false
|
|
this.signature = ''
|
|
|
|
this[originError] = this.handler.debug
|
|
? new Error()
|
|
: this.tagged && cachedError(this.strings)
|
|
}
|
|
|
|
get origin() {
|
|
return (this.handler.debug
|
|
? this[originError].stack
|
|
: this.tagged && originStackCache.has(this.strings)
|
|
? originStackCache.get(this.strings)
|
|
: originStackCache.set(this.strings, this[originError].stack).get(this.strings)
|
|
) || ''
|
|
}
|
|
|
|
static get [Symbol.species]() {
|
|
return Promise
|
|
}
|
|
|
|
cancel() {
|
|
return this.canceller && (this.canceller(this), this.canceller = null)
|
|
}
|
|
|
|
simple() {
|
|
this.options.simple = true
|
|
this.options.prepare = false
|
|
return this
|
|
}
|
|
|
|
async readable() {
|
|
this.simple()
|
|
this.streaming = true
|
|
return this
|
|
}
|
|
|
|
async writable() {
|
|
this.simple()
|
|
this.streaming = true
|
|
return this
|
|
}
|
|
|
|
cursor(rows = 1, fn) {
|
|
this.options.simple = false
|
|
if (typeof rows === 'function') {
|
|
fn = rows
|
|
rows = 1
|
|
}
|
|
|
|
this.cursorRows = rows
|
|
|
|
if (typeof fn === 'function')
|
|
return (this.cursorFn = fn, this)
|
|
|
|
let prev
|
|
return {
|
|
[Symbol.asyncIterator]: () => ({
|
|
next: () => {
|
|
if (this.executed && !this.active)
|
|
return { done: true }
|
|
|
|
prev && prev()
|
|
const promise = new Promise((resolve, reject) => {
|
|
this.cursorFn = value => {
|
|
resolve({ value, done: false })
|
|
return new Promise(r => prev = r)
|
|
}
|
|
this.resolve = () => (this.active = false, resolve({ done: true }))
|
|
this.reject = x => (this.active = false, reject(x))
|
|
})
|
|
this.execute()
|
|
return promise
|
|
},
|
|
return() {
|
|
prev && prev(CLOSE)
|
|
return { done: true }
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
describe() {
|
|
this.options.simple = false
|
|
this.onlyDescribe = this.options.prepare = true
|
|
return this
|
|
}
|
|
|
|
stream() {
|
|
throw new Error('.stream has been renamed to .forEach')
|
|
}
|
|
|
|
forEach(fn) {
|
|
this.forEachFn = fn
|
|
this.handle()
|
|
return this
|
|
}
|
|
|
|
raw() {
|
|
this.isRaw = true
|
|
return this
|
|
}
|
|
|
|
values() {
|
|
this.isRaw = 'values'
|
|
return this
|
|
}
|
|
|
|
async handle() {
|
|
!this.executed && (this.executed = true) && await 1 && this.handler(this)
|
|
}
|
|
|
|
execute() {
|
|
this.handle()
|
|
return this
|
|
}
|
|
|
|
then() {
|
|
this.handle()
|
|
return super.then.apply(this, arguments)
|
|
}
|
|
|
|
catch() {
|
|
this.handle()
|
|
return super.catch.apply(this, arguments)
|
|
}
|
|
|
|
finally() {
|
|
this.handle()
|
|
return super.finally.apply(this, arguments)
|
|
}
|
|
}
|
|
|
|
function cachedError(xs) {
|
|
if (originCache.has(xs))
|
|
return originCache.get(xs)
|
|
|
|
const x = Error.stackTraceLimit
|
|
Error.stackTraceLimit = 4
|
|
originCache.set(xs, new Error())
|
|
Error.stackTraceLimit = x
|
|
return originCache.get(xs)
|
|
}
|