Socket
Socket
Sign inDemoInstall

pg-sql2

Package Overview
Dependencies
Maintainers
1
Versions
59
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

pg-sql2 - npm Package Compare versions

Comparing version 1.0.0-beta.7 to 1.0.0-beta.8

index.js

307

lib/index.js

@@ -7,3 +7,9 @@ "use strict";

const debug = require("debug")("pg-sql2");
var isSymbol = function isSymbol(sym) {
return typeof sym === "symbol";
};
var isNil = function isNil(o) {
return o === null || o === undefined;
};
var debug = require("debug")("pg-sql2");

@@ -15,3 +21,3 @@ function debugError(err) {

const $$trusted = Symbol("trusted");
var $$trusted = Symbol("trusted");
/*::

@@ -41,41 +47,38 @@ type SQLRawNode = {

function makeRawNode(text /*: string */) /*: SQLRawNode */{
if (typeof text !== "string") {
throw new Error("Invalid argument to makeRawNode - expected string");
}
// $FlowFixMe: flow doesn't like symbols
return { type: "RAW", text, [$$trusted]: true };
function makeTrustedNode /*:: <Node>*/(node /*: Node */) /*: Node */{
Object.defineProperty(node, $$trusted, {
enumerable: false,
configurable: false,
value: true
});
return node;
}
function isStringOrSymbol(val) {
return typeof val === "string" || typeof val === "symbol";
function makeRawNode(text /*: string */) /*: SQLRawNode */{
return makeTrustedNode({ type: "RAW", text });
}
function makeIdentifierNode(names /*: Array<string | Symbol> */
function makeIdentifierNode(names /*: Array<mixed> */
) /*: SQLIdentifierNode */{
if (!Array.isArray(names) || !names.every(isStringOrSymbol)) {
throw new Error("Invalid argument to makeIdentifierNode - expected array of strings/symbols");
}
// $FlowFixMe
return { type: "IDENTIFIER", names, [$$trusted]: true };
return makeTrustedNode({ type: "IDENTIFIER", names });
}
function makeValueNode(value /*: mixed */) /*: SQLValueNode */{
// $FlowFixMe
return { type: "VALUE", value, [$$trusted]: true };
return makeTrustedNode({ type: "VALUE", value });
}
function ensureNonEmptyArray /*:: <T>*/(array /*: Array<T>*/
, allowZeroLength = false) /*: Array<T> */{
function ensureNonEmptyArray(array) {
var allowZeroLength = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
if (!Array.isArray(array)) {
throw debugError(new Error("Expected array"));
}
if (!allowZeroLength && array.length < 1) {
if (array.length < 1 && !allowZeroLength) {
throw debugError(new Error("Expected non-empty array"));
}
for (let idx = 0, l = array.length; idx < l; idx++) {
if (array[idx] == null) {
throw debugError(new Error(`Array index ${idx} is ${String(array[idx])}`));
array.forEach(function (entry, idx) {
if (entry == null) {
throw debugError(new Error(`Array index ${idx} is ${String(entry)}`));
}
}
});
return array;

@@ -86,3 +89,3 @@ }

// Join this to generate the SQL query
const sqlFragments = [];
var sqlFragments = [];

@@ -92,3 +95,3 @@ // Values hold the JavaScript values that are represented in the query

// compile time.
const values = [];
var values = [];

@@ -98,30 +101,35 @@ // When we come accross a symbol in our identifier, we create a unique

// sanity when constructing large Sql queries with many aliases.
let nextSymbolId = 0;
const symbolToIdentifier = new Map();
var nextSymbolId = 0;
var symbolToIdentifier = new Map();
const items = Array.isArray(sql) ? sql : [sql];
var items = Array.isArray(sql) ? sql : [sql];
for (let i = 0, l = items.length; i < l; i++) {
const rawItem = items[i];
const item /*: SQLNode */ = enforceValidNode(rawItem);
switch (item.type) {
case "RAW":
if (typeof item.text !== "string") {
throw new Error("RAW node expected string");
}
sqlFragments.push(item.text);
break;
case "IDENTIFIER":
if (item.names.length === 0) throw new Error("Identifier must have a name");
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;
sqlFragments.push(item.names.map(rawName => {
if (typeof rawName === "string") {
const name /*: string */ = rawName;
return escapeSqlIdentifier(name);
// $FlowFixMe: flow doesn't like symbols
} else if (typeof rawName === "symbol") {
const name /*: Symbol */ = /*:: (*/rawName /*: any) */;
try {
for (var _iterator = items[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
var rawItem = _step.value;
var item /*: SQLNode */ = enforceValidNode(rawItem);
switch (item.type) {
case "RAW":
sqlFragments.push(item.text);
break;
case "IDENTIFIER":
if (item.names.length === 0) throw new Error("Identifier must have a name");
sqlFragments.push(item.names.map(function (rawName) {
if (typeof rawName === "string") {
var _name /*: string */ = rawName;
return escapeSqlIdentifier(_name);
}
if (!isSymbol(rawName)) {
throw debugError(new Error(`Expected string or symbol, received '${String(rawName)}'`));
}
var name /*: Symbol */ = /*:: (*/rawName /*: any) */;
// Get the correct identifier string for this symbol.
let identifier = symbolToIdentifier.get(name);
var identifier = symbolToIdentifier.get(name);

@@ -137,16 +145,27 @@ // If there is no identifier, create one and set it.

return identifier;
} else {
throw debugError(new Error(`Expected string or symbol, received '${String(rawName)}'`));
}
}).join("."));
break;
case "VALUE":
values.push(item.value);
sqlFragments.push(`$${values.length}`);
break;
default:
}).join("."));
break;
case "VALUE":
values.push(item.value);
sqlFragments.push(`$${values.length}`);
break;
default:
}
}
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally {
try {
if (!_iteratorNormalCompletion && _iterator.return) {
_iterator.return();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
}
const text = sqlFragments.join("");
var text = sqlFragments.join("");
return {

@@ -159,6 +178,15 @@ text,

function enforceValidNode(node /*: mixed */) /*: SQLNode */{
// $FlowFixMe: flow doesn't like symbols
if (node !== null && typeof node === "object" && node[$$trusted] === true) {
// $FlowFixMe: this has been validated
return node;
if (node != null && typeof node === "object") {
var isRaw = node.type === "RAW" && typeof node.text === "string";
var isIdentifier = node.type === "IDENTIFIER" && Array.isArray(node.names) && node.names.every(function (name) {
return typeof name === "string" || typeof name === "symbol";
});
var isValue = node.type === "VALUE";
// $FlowFixMe: flow doesn't like symbols here?
var isTrusted = node[$$trusted] === true;
if ((isRaw || isIdentifier || isValue) && isTrusted) {
// $FlowFixMe: this has been validated
return node;
}
}

@@ -176,29 +204,29 @@ throw new Error(`Expected SQL item, instead received '${String(node)}'.`);

*/
function query(strings /*: Array<string> */
, ...values /*: Array<SQL> */
) /*: SQLQuery */{
function query(strings /*: mixed */
) /*: Array<mixed> */
/*: SQLQuery */{
for (var _len = arguments.length, values = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
values[_key - 1] = arguments[_key];
}
if (!Array.isArray(strings)) {
throw new Error("sql.query should be used as a template literal, not a function call!");
}
const items = [];
for (let i = 0, l = strings.length; i < l; i++) {
const text = strings[i];
return strings.reduce(function (items, text, i) {
if (typeof text !== "string") {
throw new Error("sql.query should be used as a template literal, not a function call.");
}
if (text.length > 0) {
items.push(makeRawNode(text));
}
if (values[i]) {
const value = values[i];
if (Array.isArray(value)) {
const nodes /*: SQLQuery */ = value.map(enforceValidNode);
items.push(...nodes);
if (!values[i]) {
return items.concat(makeRawNode(text));
} else {
var _value = values[i];
if (Array.isArray(_value)) {
var nodes /*: SQLQuery */ = _value.map(enforceValidNode);
return items.concat(makeRawNode(text), nodes);
} else {
const node /*: SQLNode */ = enforceValidNode(value);
items.push(node);
var node /*: SQLNode */ = enforceValidNode(_value);
return items.concat(makeRawNode(text), node);
}
}
}
return items;
}, []);
}

@@ -211,5 +239,5 @@

*/
function raw(text /*: string */) /*: SQLNode */{
var raw = function raw(text /*: mixed */) {
return makeRawNode(String(text));
}
};

@@ -221,6 +249,11 @@ /**

*/
function identifier(...names /*: Array<string | Symbol> */) /*: SQLNode */{
return makeIdentifierNode(ensureNonEmptyArray(names));
}
var identifier = function identifier() {
for (var _len2 = arguments.length, names = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
names[_key2] = arguments[_key2];
}
return (/*: Array<mixed> */makeIdentifierNode(ensureNonEmptyArray(names))
);
};
/**

@@ -230,10 +263,6 @@ * Creates a Sql item for a value that will be included in our final query.

*/
function value(val /*: mixed */) /*: SQLNode */{
var value = function value(val /*: mixed */) {
return makeValueNode(val);
}
};
const trueNode = raw(`TRUE`);
const falseNode = raw(`FALSE`);
const nullNode = raw(`NULL`);
/**

@@ -243,3 +272,3 @@ * If the value is simple will inline it into the query, otherwise will defer

*/
function literal(val /*: mixed */) /*: SQLNode */{
var literal = function literal(val /*: mixed */) {
if (typeof val === "string" && val.match(/^[a-zA-Z0-9_-]*$/)) {

@@ -254,9 +283,13 @@ return raw(`'${val}'`);

} else if (typeof val === "boolean") {
return val ? trueNode : falseNode;
} else if (val == null) {
return nullNode;
if (val) {
return raw(`TRUE`);
} else {
return raw(`FALSE`);
}
} else if (isNil(val)) {
return raw(`NULL`);
} else {
return makeValueNode(val);
}
}
};

@@ -267,27 +300,27 @@ /**

*/
function join(items /*: Array<SQL> */
, rawSeparator /*: string */ = "") /*: SQLQuery */{
ensureNonEmptyArray(items, true);
var join = function join(rawItems /*: mixed */) {
var rawSeparator /*: mixed */ = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : "";
if (!Array.isArray(rawItems)) {
throw new Error("Items to join must be an array");
}
var items = rawItems;
if (typeof rawSeparator !== "string") {
throw new Error("Invalid separator - must be a string");
}
const separator = rawSeparator;
const currentItems = [];
const sepNode = makeRawNode(separator);
for (let i = 0, l = items.length; i < l; i++) {
const rawItem /*: SQL */ = items[i];
let itemsToAppend /*: SQLNode | SQLQuery */;
var separator = rawSeparator;
return ensureNonEmptyArray(items, true).reduce(function (currentItems, rawItem, i) {
var item = void 0 /*: SQLNode | SQLQuery */;
if (Array.isArray(rawItem)) {
itemsToAppend = rawItem.map(enforceValidNode);
item = rawItem.map(enforceValidNode);
} else {
itemsToAppend = [enforceValidNode(rawItem)];
item = enforceValidNode(rawItem);
}
if (i === 0 || !separator) {
currentItems.push(...itemsToAppend);
return currentItems.concat(item);
} else {
currentItems.push(sepNode, ...itemsToAppend);
return currentItems.concat(makeRawNode(separator), item);
}
}
return currentItems;
}
}, []);
};

@@ -299,3 +332,3 @@ // Copied from https://github.com/brianc/node-postgres/blob/860cccd53105f7bc32fed8b1de69805f0ecd12eb/lib/client.js#L285-L302

for (var i = 0, l = str.length; i < l; i++) {
for (var i = 0; i < str.length; i++) {
var c = str[i];

@@ -314,19 +347,45 @@ if (c === '"') {

exports.query = query;
// The types we export are stricter so people get the right hinting
exports.query = function sqlQuery(strings /*: string[] */
) /*: Array<SQL> */
/*: SQLQuery */{
for (var _len3 = arguments.length, values = Array(_len3 > 1 ? _len3 - 1 : 0), _key3 = 1; _key3 < _len3; _key3++) {
values[_key3 - 1] = arguments[_key3];
}
return query.apply(undefined, [strings].concat(values));
};
exports.fragment = exports.query;
exports.raw = raw;
exports.raw = function sqlRaw(text /*: string */) /*: SQLNode */{
return raw(text);
};
exports.identifier = identifier;
exports.identifier = function sqlIdentifier() /*: Array<string | Symbol> */
/*: SQLNode */{
return identifier.apply(undefined, arguments);
};
exports.value = value;
exports.value = function sqlValue(val /*: mixed */) /*: SQLNode */{
return value(val);
};
exports.literal = literal;
exports.literal = function sqlLiteral(val /*: mixed */) /*: SQLNode */{
return literal(val);
};
exports.join = join;
exports.join = function sqlJoin(items /*: Array<SQL> */
) /*: SQLQuery */{
var separator /*: string */ = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : "";
exports.compile = compile;
return join(items, separator);
};
exports.null = nullNode;
exports.compile = function sqlCompile(sql /*: SQLQuery */) /*: QueryConfig */{
return compile(sql);
};
exports.null = exports.literal(null);
exports.blank = exports.query``;
{
"name": "pg-sql2",
"version": "1.0.0-beta.7",
"version": "1.0.0-beta.8",
"description": "Generate safe Postgres-compliant SQL with tagged template literals",
"main": "lib/index.js",
"main": "index.js",
"scripts": {

@@ -10,4 +10,3 @@ "flow": "flow",

"lint": "eslint .",
"test": "node src/index.js && eslint . && flow check && jest && markdown-doctest",
"test:u": "node src/index.js && eslint . && flow check && jest -u && markdown-doctest",
"test": "node index.js && eslint . && flow check && jest && markdown-doctest",
"test:docs": "markdown-doctest",

@@ -45,7 +44,7 @@ "prepublish": "babel --out-dir lib src"

"eslint-plugin-jest": "^20.0.3",
"eslint-plugin-prettier": "2.6.0",
"flow-bin": "0.66.0",
"eslint-plugin-prettier": "^2.1.2",
"flow-bin": "^0.52.0",
"jest": "20.0.4",
"markdown-doctest": "^0.9.1",
"prettier": "1.11.0"
"prettier": "^1.5.3"
},

@@ -62,6 +61,3 @@ "jest": {

"index.js"
],
"engines": {
"node": ">=8.6"
}
]
}

@@ -1,2 +0,3 @@

# pg-sql2
pg-sql2
=======

@@ -7,3 +8,3 @@ Create SQL in a powerful and flexible manner without opening yourself to SQL

```js
const sql = require("pg-sql2");
const sql = require('pg-sql2');
// or import sql from 'pg-sql2';

@@ -23,10 +24,8 @@

// statement, to ensure that no SQL injection can occur.
const sqlConditions = sql.query`created_at > NOW() - interval '3 years' and age > ${sql.value(
22
)}`;
const sqlConditions =
sql.query`created_at > NOW() - interval '3 years' and age > ${sql.value(22)}`;
// This could be a full query, but we're going to embed it in another query safely
const innerQuery = sql.query`select ${sqlFields} from ${sql.identifier(
tableName
)} where ${sqlConditions}`;
const innerQuery =
sql.query`select ${sqlFields} from ${sql.identifier(tableName)} where ${sqlConditions}`;

@@ -60,5 +59,6 @@ // Symbols are automatically assigned unique identifiers

## API
API
---
### `` sql.query`...` ``
### ``sql.query`...` ``

@@ -68,5 +68,4 @@ Builds part of (or the whole of) an SQL query, safely interpretting the embedded expressions. If a non `sql.*` expression is passed in, e.g.:

<!-- skip-example -->
```js
sql.query`select ${1}`;
sql.query`select ${1}`
```

@@ -97,15 +96,11 @@

```js
const arrayOfSqlFields = ["a", "b", "c", "d"].map(n => sql.identifier(n));
sql.query`select ${sql.join(arrayOfSqlFields, ", ")}`; // -> select "a", "b", "c", "d"
const arrayOfSqlFields = ['a', 'b', 'c', 'd'].map(n => sql.identifier(n));
sql.query`select ${sql.join(arrayOfSqlFields, ', ')}` // -> select "a", "b", "c", "d"
const arrayOfSqlConditions = [
sql.query`a = 1`,
sql.query`b = 2`,
sql.query`c = 3`
];
sql.query`where (${sql.join(arrayOfSqlConditions, ") and (")})`; // -> where (a = 1) and (b = 2) and (c = 3)
const arrayOfSqlConditions = [sql.query`a = 1`, sql.query`b = 2`, sql.query`c = 3`];
sql.query`where (${sql.join(arrayOfSqlConditions, ') and (')})` // -> where (a = 1) and (b = 2) and (c = 3)
const fragments = [
{ alias: "name", sqlFragment: sql.identifier("user", "name") },
{ alias: "age", sqlFragment: sql.identifier("user", "age") }
{alias: 'name', sqlFragment: sql.identifier('user', 'name')},
{alias: 'age', sqlFragment: sql.identifier('user', 'age')},
];

@@ -125,5 +120,5 @@ sql.query`

sql.query`inner join bar on (bar.foo_id = foo.id)`,
sql.query`inner join baz on (baz.bar_id = bar.id)`
sql.query`inner join baz on (baz.bar_id = bar.id)`,
];
sql.query`select * from foo ${sql.join(arrayOfSqlInnerJoins, " ")}`;
sql.query`select * from foo ${sql.join(arrayOfSqlInnerJoins, " ")}`
// select * from foo inner join bar on (bar.foo_id = foo.id) inner join baz on (baz.bar_id = bar.id)

@@ -143,3 +138,4 @@ ```

## History
History
-------

@@ -152,14 +148,11 @@ This is a replacement for [@calebmer's

* Better development experience for people not using Flow/TypeScript (throws
- Better development experience for people not using Flow/TypeScript (throws
errors a lot earlier allowing you to catch issues at the source)
* Slightly more helpful error messages
* Uses a symbol-key on the query nodes to protect against an object
accidentally being inserted verbatim and being treated as valid (because
every Symbol is unique an attacker would need control of the code to get a
reference to the Symbol in order to set it on an object (it cannot be
serialised/deserialised via JSON or any other medium), and if the attacker
has control of the code then you've already lost)
* Adds `sql.literal` which is similar to `sql.value` but when used with simple
- Slightly more helpful error messages
- Uses a hidden non-enumerable symbol as the type of the query nodes to protect
against an object accidentally being inserted verbatim and being treated as
valid
- Adds `sql.literal` which is similar to `sql.value` but when used with simple
values can write the valid direct to the SQL statement. **USE WITH CAUTION**.
The purpose for this is if you are using _trusted_ values (e.g. for the keys
The purpose for this is if you are using *trusted* values (e.g. for the keys
to

@@ -166,0 +159,0 @@ [`json_build_object(...)`](https://www.postgresql.org/docs/9.6/static/functions-json.html))

@@ -10,2 +10,4 @@ "use strict";

const isSymbol = sym => typeof sym === "symbol";
const isNil = o => o === null || o === undefined;
const debug = require("debug")("pg-sql2");

@@ -43,48 +45,37 @@

function makeRawNode(text /*: string */) /*: SQLRawNode */ {
if (typeof text !== "string") {
throw new Error("Invalid argument to makeRawNode - expected string");
}
// $FlowFixMe: flow doesn't like symbols
return { type: "RAW", text, [$$trusted]: true };
function makeTrustedNode /*:: <Node>*/(node /*: Node */) /*: Node */ {
Object.defineProperty(node, $$trusted, {
enumerable: false,
configurable: false,
value: true,
});
return node;
}
function isStringOrSymbol(val) {
return typeof val === "string" || typeof val === "symbol";
function makeRawNode(text /*: string */) /*: SQLRawNode */ {
return makeTrustedNode({ type: "RAW", text });
}
function makeIdentifierNode(
names /*: Array<string | Symbol> */
names /*: Array<mixed> */
) /*: SQLIdentifierNode */ {
if (!Array.isArray(names) || !names.every(isStringOrSymbol)) {
throw new Error(
"Invalid argument to makeIdentifierNode - expected array of strings/symbols"
);
}
// $FlowFixMe
return { type: "IDENTIFIER", names, [$$trusted]: true };
return makeTrustedNode({ type: "IDENTIFIER", names });
}
function makeValueNode(value /*: mixed */) /*: SQLValueNode */ {
// $FlowFixMe
return { type: "VALUE", value, [$$trusted]: true };
return makeTrustedNode({ type: "VALUE", value });
}
function ensureNonEmptyArray /*:: <T>*/(
array /*: Array<T>*/,
allowZeroLength = false
) /*: Array<T> */ {
function ensureNonEmptyArray(array, allowZeroLength = false) {
if (!Array.isArray(array)) {
throw debugError(new Error("Expected array"));
}
if (!allowZeroLength && array.length < 1) {
if (array.length < 1 && !allowZeroLength) {
throw debugError(new Error("Expected non-empty array"));
}
for (let idx = 0, l = array.length; idx < l; idx++) {
if (array[idx] == null) {
throw debugError(
new Error(`Array index ${idx} is ${String(array[idx])}`)
);
array.forEach((entry, idx) => {
if (entry == null) {
throw debugError(new Error(`Array index ${idx} is ${String(entry)}`));
}
}
});
return array;

@@ -110,10 +101,6 @@ }

for (let i = 0, l = items.length; i < l; i++) {
const rawItem = items[i];
for (const rawItem of items) {
const item /*: SQLNode */ = enforceValidNode(rawItem);
switch (item.type) {
case "RAW":
if (typeof item.text !== "string") {
throw new Error("RAW node expected string");
}
sqlFragments.push(item.text);

@@ -131,19 +118,4 @@ break;

return escapeSqlIdentifier(name);
// $FlowFixMe: flow doesn't like symbols
} else if (typeof rawName === "symbol") {
const name /*: Symbol */ = /*:: (*/ rawName /*: any) */;
// Get the correct identifier string for this symbol.
let identifier = symbolToIdentifier.get(name);
// If there is no identifier, create one and set it.
if (!identifier) {
identifier = `__local_${nextSymbolId++}__`;
symbolToIdentifier.set(name, identifier);
}
// Return the identifier. Since we create it, we won’t have to
// escape it because we know all of the characters are safe.
return identifier;
} else {
}
if (!isSymbol(rawName)) {
throw debugError(

@@ -155,2 +127,16 @@ new Error(

}
const name /*: Symbol */ = /*:: (*/ rawName /*: any) */;
// Get the correct identifier string for this symbol.
let identifier = symbolToIdentifier.get(name);
// If there is no identifier, create one and set it.
if (!identifier) {
identifier = `__local_${nextSymbolId++}__`;
symbolToIdentifier.set(name, identifier);
}
// Return the identifier. Since we create it, we won’t have to
// escape it because we know all of the characters are safe.
return identifier;
})

@@ -176,6 +162,18 @@ .join(".")

function enforceValidNode(node /*: mixed */) /*: SQLNode */ {
// $FlowFixMe: flow doesn't like symbols
if (node !== null && typeof node === "object" && node[$$trusted] === true) {
// $FlowFixMe: this has been validated
return node;
if (node != null && typeof node === "object") {
const isRaw = node.type === "RAW" && typeof node.text === "string";
const isIdentifier =
node.type === "IDENTIFIER" &&
Array.isArray(node.names) &&
node.names.every(
name => typeof name === "string" || typeof name === "symbol"
);
const isValue = node.type === "VALUE";
// $FlowFixMe: flow doesn't like symbols here?
const isTrusted = node[$$trusted] === true;
if ((isRaw || isIdentifier || isValue) && isTrusted) {
// $FlowFixMe: this has been validated
return node;
}
}

@@ -194,4 +192,4 @@ throw new Error(`Expected SQL item, instead received '${String(node)}'.`);

function query(
strings /*: Array<string> */,
...values /*: Array<SQL> */
strings /*: mixed */,
...values /*: Array<mixed> */
) /*: SQLQuery */ {

@@ -203,5 +201,3 @@ if (!Array.isArray(strings)) {

}
const items = [];
for (let i = 0, l = strings.length; i < l; i++) {
const text = strings[i];
return strings.reduce((items, text, i) => {
if (typeof text !== "string") {

@@ -212,17 +208,15 @@ throw new Error(

}
if (text.length > 0) {
items.push(makeRawNode(text));
}
if (values[i]) {
if (!values[i]) {
return items.concat(makeRawNode(text));
} else {
const value = values[i];
if (Array.isArray(value)) {
const nodes /*: SQLQuery */ = value.map(enforceValidNode);
items.push(...nodes);
return items.concat(makeRawNode(text), nodes);
} else {
const node /*: SQLNode */ = enforceValidNode(value);
items.push(node);
return items.concat(makeRawNode(text), node);
}
}
}
return items;
}, []);
}

@@ -235,5 +229,3 @@

*/
function raw(text /*: string */) /*: SQLNode */ {
return makeRawNode(String(text));
}
const raw = (text /*: mixed */) => makeRawNode(String(text));

@@ -245,5 +237,4 @@ /**

*/
function identifier(...names /*: Array<string | Symbol> */) /*: SQLNode */ {
return makeIdentifierNode(ensureNonEmptyArray(names));
}
const identifier = (...names /*: Array<mixed> */) =>
makeIdentifierNode(ensureNonEmptyArray(names));

@@ -254,10 +245,4 @@ /**

*/
function value(val /*: mixed */) /*: SQLNode */ {
return makeValueNode(val);
}
const value = (val /*: mixed */) => makeValueNode(val);
const trueNode = raw(`TRUE`);
const falseNode = raw(`FALSE`);
const nullNode = raw(`NULL`);
/**

@@ -267,3 +252,3 @@ * If the value is simple will inline it into the query, otherwise will defer

*/
function literal(val /*: mixed */) /*: SQLNode */ {
const literal = (val /*: mixed */) => {
if (typeof val === "string" && val.match(/^[a-zA-Z0-9_-]*$/)) {

@@ -278,9 +263,13 @@ return raw(`'${val}'`);

} else if (typeof val === "boolean") {
return val ? trueNode : falseNode;
} else if (val == null) {
return nullNode;
if (val) {
return raw(`TRUE`);
} else {
return raw(`FALSE`);
}
} else if (isNil(val)) {
return raw(`NULL`);
} else {
return makeValueNode(val);
}
}
};

@@ -291,7 +280,7 @@ /**

*/
function join(
items /*: Array<SQL> */,
rawSeparator /*: string */ = ""
) /*: SQLQuery */ {
ensureNonEmptyArray(items, true);
const join = (rawItems /*: mixed */, rawSeparator /*: mixed */ = "") => {
if (!Array.isArray(rawItems)) {
throw new Error("Items to join must be an array");
}
const items = rawItems;
if (typeof rawSeparator !== "string") {

@@ -301,20 +290,16 @@ throw new Error("Invalid separator - must be a string");

const separator = rawSeparator;
const currentItems = [];
const sepNode = makeRawNode(separator);
for (let i = 0, l = items.length; i < l; i++) {
const rawItem /*: SQL */ = items[i];
let itemsToAppend /*: SQLNode | SQLQuery */;
return ensureNonEmptyArray(items, true).reduce((currentItems, rawItem, i) => {
let item /*: SQLNode | SQLQuery */;
if (Array.isArray(rawItem)) {
itemsToAppend = rawItem.map(enforceValidNode);
item = rawItem.map(enforceValidNode);
} else {
itemsToAppend = [enforceValidNode(rawItem)];
item = enforceValidNode(rawItem);
}
if (i === 0 || !separator) {
currentItems.push(...itemsToAppend);
return currentItems.concat(item);
} else {
currentItems.push(sepNode, ...itemsToAppend);
return currentItems.concat(makeRawNode(separator), item);
}
}
return currentItems;
}
}, []);
};

@@ -326,3 +311,3 @@ // Copied from https://github.com/brianc/node-postgres/blob/860cccd53105f7bc32fed8b1de69805f0ecd12eb/lib/client.js#L285-L302

for (var i = 0, l = str.length; i < l; i++) {
for (var i = 0; i < str.length; i++) {
var c = str[i];

@@ -341,19 +326,43 @@ if (c === '"') {

exports.query = query;
// The types we export are stricter so people get the right hinting
exports.query = function sqlQuery(
strings /*: string[] */,
...values /*: Array<SQL> */
) /*: SQLQuery */ {
return query(strings, ...values);
};
exports.fragment = exports.query;
exports.raw = raw;
exports.raw = function sqlRaw(text /*: string */) /*: SQLNode */ {
return raw(text);
};
exports.identifier = identifier;
exports.identifier = function sqlIdentifier(
...names /*: Array<string | Symbol> */
) /*: SQLNode */ {
return identifier(...names);
};
exports.value = value;
exports.value = function sqlValue(val /*: mixed */) /*: SQLNode */ {
return value(val);
};
exports.literal = literal;
exports.literal = function sqlLiteral(val /*: mixed */) /*: SQLNode */ {
return literal(val);
};
exports.join = join;
exports.join = function sqlJoin(
items /*: Array<SQL> */,
separator /*: string */ = ""
) /*: SQLQuery */ {
return join(items, separator);
};
exports.compile = compile;
exports.compile = function sqlCompile(sql /*: SQLQuery */) /*: QueryConfig */ {
return compile(sql);
};
exports.null = nullNode;
exports.null = exports.literal(null);
exports.blank = exports.query``;
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc