Last active
January 27, 2020 02:34
-
-
Save skyjur/6d776f28202148297c8b851caf990b33 to your computer and use it in GitHub Desktop.
javascript string literal tag for pg queries
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const { query } = require("../connection") | |
/** | |
* @template T | |
* @param {Pg.QueryConfig | string} queryConfig | |
* @param {Ork.Context} ctx | |
* @returns {Sql.LazyQuery<T>} | |
*/ | |
function lazyQuery(queryConfig, ctx = {}) { | |
let { name = "", text, values = [] } = | |
typeof queryConfig === "string" ? { text: queryConfig } : queryConfig | |
name = name || text.replace(/\s+/gm, " ").slice(0, 30) + "..." | |
return { | |
get [Symbol.toStringTag]() { | |
return `LazyQuery<${name}>` | |
}, | |
name, | |
text, | |
values, | |
run(runCtx = {}) { | |
return query(this, { ...ctx, ...runCtx }) | |
}, | |
then(onfulfilled, onrejected) { | |
return this.run().then(onfulfilled, onrejected) | |
}, | |
catch(onrejected) { | |
return this.run().catch(onrejected) | |
} | |
} | |
} | |
module.exports = { lazyQuery } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const safeMarker = Symbol("Safe sql marker") | |
/** | |
* @param {TemplateStringsArray} strings | |
* @args {any[]} args | |
* @returns {{text: string, values: any[]}} | |
*/ | |
function sql(strings, ...args) { | |
let text = strings[0] | |
let values = [] | |
args.forEach((val, i) => { | |
if (val && val[safeMarker]) { | |
const offset = values.length | |
text += val.text.replace(/\$\d+/g, (match) => { | |
const j = parseInt(match.slice(1), 10) | |
return "$" + (offset + j) | |
}) | |
values.push(...(val.values || [])) | |
text += strings[i + 1] | |
} else { | |
values.push(val) | |
text += "$" + values.length + strings[i + 1] | |
} | |
}) | |
return safe({ text, values }) | |
} | |
sql.id = function id(name) { | |
if (name instanceof Array && name.length === 2) { | |
return safe({ | |
text: `${id(name[0]).text}.${id(name[1]).text}`, | |
values: [] | |
}) | |
} else if (typeof name === "string") { | |
if (/[^a-zA-Z_]/.test(name)) { | |
throw new Error(`Invalid pg identifier`) | |
} | |
return safe({ | |
text: `"${camelToSnakeKey(name)}"`, | |
values: [] | |
}) | |
} else { | |
throw new Error("Invalid type") | |
} | |
} | |
sql.ids = function(names) { | |
return safe({ | |
text: names.map((name) => this.id(name).text).join(", "), | |
values: [] | |
}) | |
} | |
sql.idsIn = function(table, names) { | |
return sql.ids(names.map((name) => [table, name])) | |
} | |
sql.now = sql`now()` | |
sql.join = | |
/** | |
* | |
* @param {any[]} sqlList | |
* @returns {Pg.QueryConfig} | |
*/ | |
function join(sqlList) { | |
return sqlList.slice(1).reduce((a, b) => sql`${a}, ${b}`, sqlList[0]) | |
} | |
sql.insert = | |
/** | |
* @type {<T extends keyof Sql.Schema> | |
* (def: Sql.InsertDef<T>) => Pg.QueryConfig} | |
*/ | |
function insert({ table, data, conflict }) { | |
let query = sql` | |
insert into ${sql.id(table)} ( | |
${sql.ids(Object.keys(data))} | |
) | |
values ( | |
${sql.join(Object.keys(data).map((key) => data[key]))} | |
) | |
` | |
if (conflict) { | |
query = sql`${query} on conflict (${sql.ids(conflict.fields)}) do` | |
const updateFields = | |
conflict.updateFields === "all" | |
? Object.keys(data) | |
: conflict.updateFields | |
if (updateFields.length > 0) { | |
query = sql`${query} update set ${sql.join( | |
updateFields.map( | |
(key) => sql`${sql.id(key)} = excluded.${sql.id(key)}` | |
) | |
)}` | |
} else { | |
query = sql`${query} nothing` | |
} | |
} | |
return query | |
} | |
/** | |
* @template T | |
* @param {T} val | |
* @returns T | |
*/ | |
function safe(val) { | |
val[safeMarker] = true | |
return val | |
} | |
module.exports = { sql, safe } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment