@databases/sql
Advanced tools
Comparing version 2.2.0 to 3.0.0
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
Object.defineProperty(exports, "__esModule", { | ||
value: true | ||
}); | ||
const __1 = require("../"); | ||
test('correctly renders sql', () => { | ||
@@ -12,11 +16,22 @@ const query = __1.default` | ||
`; | ||
expect(query.compile()).toMatchInlineSnapshot(` | ||
Object { | ||
"text": "SELECT * FROM foo WHERE id = $1 AND created_at > $2;", | ||
"values": Array [ | ||
10, | ||
2018-12-19T16:53:20.939Z, | ||
], | ||
} | ||
`); | ||
expect(query.format({ | ||
escapeIdentifier: () => { | ||
throw new Error('not implemented'); | ||
}, | ||
formatValue: value => ({ | ||
placeholder: '?', | ||
value | ||
}) | ||
})).toMatchInlineSnapshot(` | ||
Object { | ||
"text": "SELECT * | ||
FROM foo | ||
WHERE id = ? | ||
AND created_at > ?;", | ||
"values": Array [ | ||
10, | ||
2018-12-19T16:53:20.939Z, | ||
], | ||
} | ||
`); | ||
}); | ||
@@ -30,21 +45,39 @@ test('can join parts of query', () => { | ||
`; | ||
expect(query.compile()).toMatchInlineSnapshot(` | ||
Object { | ||
"text": "SELECT * FROM foo WHERE id = $1 AND created_at > $2;", | ||
"values": Array [ | ||
10, | ||
2018-12-19T16:53:20.939Z, | ||
], | ||
} | ||
`); | ||
expect(query.format({ | ||
escapeIdentifier: () => { | ||
throw new Error('not implemented'); | ||
}, | ||
formatValue: value => ({ | ||
placeholder: '?', | ||
value | ||
}) | ||
})).toMatchInlineSnapshot(` | ||
Object { | ||
"text": "SELECT * | ||
FROM foo | ||
WHERE id = ? AND created_at > ?;", | ||
"values": Array [ | ||
10, | ||
2018-12-19T16:53:20.939Z, | ||
], | ||
} | ||
`); | ||
}); | ||
test('can read in a file', () => { | ||
const query = __1.default.file(`${__dirname}/fixture.sql`); | ||
expect(query.compile()).toMatchInlineSnapshot(` | ||
Object { | ||
"text": "SELECT * FROM my_table;", | ||
"values": Array [], | ||
} | ||
`); | ||
}); | ||
//# sourceMappingURL=index.test.js.map | ||
expect(query.format({ | ||
escapeIdentifier: () => { | ||
throw new Error('not implemented'); | ||
}, | ||
formatValue: value => ({ | ||
placeholder: '?', | ||
value | ||
}) | ||
})).toMatchInlineSnapshot(` | ||
Object { | ||
"text": "SELECT * FROM my_table;", | ||
"values": Array [], | ||
} | ||
`); | ||
}); |
@@ -1,8 +0,8 @@ | ||
import SQLQuery from './SQLQuery'; | ||
import SQLBase from './SQL'; | ||
import { SQL as SQLBase, SQLQuery, SQLItem, SQLItemType, FormatConfig, isSqlQuery } from './web'; | ||
export type { SQLQuery, SQLItem, FormatConfig }; | ||
export { isSqlQuery, SQLItemType }; | ||
export interface SQL extends SQLBase { | ||
file(filename: string): SQLQuery; | ||
} | ||
export { SQLQuery }; | ||
declare const modifiedSQL: SQL; | ||
export default modifiedSQL; | ||
declare const sql: SQL; | ||
export default sql; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
Object.defineProperty(exports, "__esModule", { | ||
value: true | ||
}); | ||
const fs_1 = require("fs"); | ||
const minify = require("pg-minify"); | ||
const SQLQuery_1 = require("./SQLQuery"); | ||
exports.SQLQuery = SQLQuery_1.default; | ||
SQLQuery_1.setPgMinify(minify); | ||
SQLQuery_1.setReadFileSync(fs_1.readFileSync); | ||
// Create the SQL interface we export. | ||
const modifiedSQL = Object.assign((strings, ...values) => SQLQuery_1.default.query(strings, ...values), { | ||
// tslint:disable:no-unbound-method | ||
// tslint:disable-next-line:deprecation | ||
join: SQLQuery_1.default.join, | ||
__dangerous__rawValue: SQLQuery_1.default.raw, | ||
file: filename => SQLQuery_1.default.file(filename), | ||
value: SQLQuery_1.default.value, | ||
ident: SQLQuery_1.default.ident, | ||
registerFormatter: SQLQuery_1.default.registerFormatter | ||
const web_1 = require("./web"); | ||
exports.SQLItemType = web_1.SQLItemType; | ||
exports.isSqlQuery = web_1.isSqlQuery; // Create the SQL interface we export. | ||
const sql = Object.assign(web_1.default, { | ||
file: filename => web_1.default.__dangerous__rawValue(fs_1.readFileSync(filename, 'utf8')) | ||
}); | ||
exports.default = modifiedSQL; | ||
module.exports = modifiedSQL; | ||
module.exports.default = modifiedSQL; | ||
module.exports.SQLQuery = SQLQuery_1.default; | ||
//# sourceMappingURL=index.js.map | ||
exports.default = sql; | ||
module.exports = sql; | ||
module.exports.default = sql; | ||
module.exports.isSqlQuery = web_1.isSqlQuery; | ||
module.exports.SQLItemType = web_1.SQLItemType; |
@@ -1,5 +0,94 @@ | ||
import SQLQuery from './SQLQuery'; | ||
import SQL from './SQL'; | ||
export { SQLQuery, SQL }; | ||
declare const modifiedSQL: SQL; | ||
export default modifiedSQL; | ||
export declare enum SQLItemType { | ||
RAW = 0, | ||
VALUE = 1, | ||
IDENTIFIER = 2 | ||
} | ||
/** | ||
* A single, escaped, `SQLQuery` item. These items are assembled into a SQL | ||
* query through the compile method. | ||
*/ | ||
export declare type SQLItem = { | ||
type: SQLItemType.RAW; | ||
text: string; | ||
} | { | ||
type: SQLItemType.VALUE; | ||
value: any; | ||
} | { | ||
type: SQLItemType.IDENTIFIER; | ||
names: Array<any>; | ||
}; | ||
export interface FormatConfig { | ||
escapeIdentifier: (str: string) => string; | ||
formatValue: (value: unknown, index: number) => { | ||
readonly placeholder: string; | ||
readonly value: unknown; | ||
}; | ||
} | ||
declare const literalSeparators: Set<"" | "," | ", " | " AND " | " OR " | ") AND (" | ") OR (" | ";">; | ||
declare type LiteralSeparator = typeof literalSeparators extends Set<infer T> ? T : never; | ||
/** | ||
* The representation of a SQL query. Call `compile` to turn it into a SQL | ||
* string with value placeholders. | ||
* | ||
* This object is immutable. Instead of changing the object, new `SQLQuery` | ||
* values will be returned. | ||
* | ||
* The constructor for this class is private and may not be called. | ||
*/ | ||
declare class SQLQuery { | ||
static registerFormatter<T>(constructor: new (...args: any[]) => T, format: (value: T) => SQLQuery): void; | ||
/** | ||
* A template string tag that interpolates literal SQL with placeholder SQL | ||
* values. | ||
*/ | ||
static query(strings: TemplateStringsArray, ...values: Array<any>): SQLQuery; | ||
/** | ||
* Joins multiple queries together and puts a separator in between if a | ||
* separator was defined. | ||
*/ | ||
static join(queries: Array<SQLQuery>, separator?: LiteralSeparator | SQLQuery): SQLQuery; | ||
/** | ||
* Creates a new query with the raw text. | ||
*/ | ||
static __dangerous__rawValue(text: string): SQLQuery; | ||
/** | ||
* Creates a new query from the array of `SQLItem` parts | ||
*/ | ||
static __dangerous__constructFromParts(items: readonly SQLItem[]): SQLQuery; | ||
/** | ||
* Creates a new query with the value. This value will be turned into a | ||
* placeholder when the query gets compiled. | ||
*/ | ||
static value(value: any): SQLQuery; | ||
/** | ||
* Creates an identifier query. Each name will be escaped, and the | ||
* names will be concatenated with a period (`.`). | ||
*/ | ||
static ident(...names: Array<any>): SQLQuery; | ||
/** | ||
* The internal array of SQL items. This array is never mutated, only cloned. | ||
*/ | ||
private readonly _items; | ||
private readonly _cache; | ||
private constructor(); | ||
format(config: FormatConfig): { | ||
text: string; | ||
values: unknown[]; | ||
}; | ||
format<T>(formatter: (items: readonly SQLItem[]) => T): T; | ||
} | ||
export type { SQLQuery }; | ||
/** | ||
* The interface we actually expect people to use. | ||
*/ | ||
export declare type SQL = typeof SQLQuery.query & { | ||
readonly join: typeof SQLQuery.join; | ||
readonly __dangerous__rawValue: typeof SQLQuery.__dangerous__rawValue; | ||
readonly __dangerous__constructFromParts: typeof SQLQuery.__dangerous__constructFromParts; | ||
readonly value: typeof SQLQuery.value; | ||
readonly ident: typeof SQLQuery.ident; | ||
readonly registerFormatter: typeof SQLQuery.registerFormatter; | ||
}; | ||
declare const sql: SQL; | ||
export default sql; | ||
export declare function isSqlQuery(query: unknown): query is SQLQuery; |
275
lib/web.js
@@ -1,21 +0,258 @@ | ||
"use strict"; | ||
// @public | ||
"use strict"; // @public | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const SQLQuery_1 = require("./SQLQuery"); | ||
exports.SQLQuery = SQLQuery_1.default; | ||
Object.defineProperty(exports, "__esModule", { | ||
value: true | ||
}); | ||
var SQLItemType; | ||
(function (SQLItemType) { | ||
SQLItemType[SQLItemType["RAW"] = 0] = "RAW"; | ||
SQLItemType[SQLItemType["VALUE"] = 1] = "VALUE"; | ||
SQLItemType[SQLItemType["IDENTIFIER"] = 2] = "IDENTIFIER"; | ||
})(SQLItemType = exports.SQLItemType || (exports.SQLItemType = {})); | ||
const formatter = Symbol('SQL Query Formatter'); | ||
const literalSeparators = new Set(['', ',', ', ', ' AND ', ' OR ', ') AND (', ') OR (', ';']); | ||
/** | ||
* The representation of a SQL query. Call `compile` to turn it into a SQL | ||
* string with value placeholders. | ||
* | ||
* This object is immutable. Instead of changing the object, new `SQLQuery` | ||
* values will be returned. | ||
* | ||
* The constructor for this class is private and may not be called. | ||
*/ | ||
class SQLQuery { | ||
// The constructor is private. Users should use the static `create` method to | ||
// make a new `SQLQuery`. | ||
constructor(items) { | ||
this._cache = new Map(); | ||
this._items = items; | ||
} | ||
static registerFormatter(constructor, format) { | ||
constructor.prototype[formatter] = format; | ||
} | ||
/** | ||
* A template string tag that interpolates literal SQL with placeholder SQL | ||
* values. | ||
*/ | ||
static query(strings, ...values) { | ||
const items = []; // Add all of the strings as raw items and values as placeholder values. | ||
for (let i = 0; i < strings.length; i++) { | ||
if (strings[i]) { | ||
items.push({ | ||
type: SQLItemType.RAW, | ||
text: strings[i] | ||
}); | ||
} | ||
if (i < values.length) { | ||
const value = values[i]; // If the value is a `SQLQuery`, add all of its items. | ||
if (value instanceof SQLQuery) { | ||
for (const item of value._items) items.push(item); | ||
} else { | ||
if (value && typeof value === 'object' && formatter in value) { | ||
const formatted = value[formatter](value); | ||
if (!(formatted instanceof SQLQuery)) { | ||
throw new Error('Formatters should always return SQLQuery objects'); | ||
} | ||
for (const item of formatted._items) items.push(item); | ||
} else if (typeof value === 'bigint') { | ||
items.push({ | ||
type: SQLItemType.VALUE, | ||
value: value.toString(10) | ||
}); | ||
} else { | ||
if (strings[i + 1] && strings[i + 1].startsWith("'") && strings[i].endsWith("'")) { | ||
throw new Error(`You do not need to wrap values in 'quotes' when using @databases. Any JavaScript string passed via \${...} syntax is already treated as a string. Please remove the quotes around this value.`); | ||
} | ||
items.push({ | ||
type: SQLItemType.VALUE, | ||
value | ||
}); | ||
} | ||
} | ||
} | ||
} | ||
return new SQLQuery(items); | ||
} | ||
/** | ||
* Joins multiple queries together and puts a separator in between if a | ||
* separator was defined. | ||
*/ | ||
static join(queries, separator) { | ||
if (typeof separator === 'string' && !literalSeparators.has(separator)) { | ||
throw new Error(`Please tag your string as an SQL query via "sql.join(..., sql\`${separator.includes('`') ? 'your_separator' : separator}\`)" or use one of the standard speparators: ${[...literalSeparators].map(s => `"${s}"`).join(', ')}`); | ||
} | ||
const items = []; | ||
const separatorItems = separator ? typeof separator === 'string' ? [{ | ||
type: SQLItemType.RAW, | ||
text: separator | ||
}] : separator._items : undefined; | ||
let addedFirst = false; // Add the items of all our queries into the `items` array, adding text | ||
// separator items as necessary. | ||
for (const query of queries) { | ||
if (!addedFirst) { | ||
addedFirst = true; | ||
} else if (separatorItems) { | ||
items.push(...separatorItems); | ||
} | ||
items.push(...query._items); | ||
} | ||
return new SQLQuery(items); | ||
} | ||
/** | ||
* Creates a new query with the raw text. | ||
*/ | ||
static __dangerous__rawValue(text) { | ||
return new SQLQuery([{ | ||
type: SQLItemType.RAW, | ||
text | ||
}]); | ||
} | ||
/** | ||
* Creates a new query from the array of `SQLItem` parts | ||
*/ | ||
static __dangerous__constructFromParts(items) { | ||
return new SQLQuery(items); | ||
} | ||
/** | ||
* Creates a new query with the value. This value will be turned into a | ||
* placeholder when the query gets compiled. | ||
*/ | ||
static value(value) { | ||
return new SQLQuery([{ | ||
type: SQLItemType.VALUE, | ||
value | ||
}]); | ||
} | ||
/** | ||
* Creates an identifier query. Each name will be escaped, and the | ||
* names will be concatenated with a period (`.`). | ||
*/ | ||
static ident(...names) { | ||
return new SQLQuery([{ | ||
type: SQLItemType.IDENTIFIER, | ||
names | ||
}]); | ||
} | ||
format(formatter) { | ||
const cached = this._cache.get(formatter); | ||
if (cached) return cached; | ||
const fresh = typeof formatter === 'function' ? formatter(this._items) : formatStandard(this._items, formatter); | ||
this._cache.set(formatter, fresh); | ||
return fresh; | ||
} | ||
} | ||
function formatStandard(items, { | ||
escapeIdentifier, | ||
formatValue | ||
}) { | ||
// Create an empty query object. | ||
let text = ''; | ||
const values = []; | ||
const localIdentifiers = new Map(); | ||
for (const item of items) { | ||
switch (item.type) { | ||
// If this is just raw text, we add it directly to the query text. | ||
case SQLItemType.RAW: | ||
{ | ||
text += item.text; | ||
break; | ||
} | ||
// If we got a value SQL item, add a placeholder and add the value to our | ||
// placeholder values array. | ||
case SQLItemType.VALUE: | ||
{ | ||
const { | ||
placeholder, | ||
value | ||
} = formatValue(item.value, values.length); | ||
text += placeholder; | ||
values.push(value); | ||
break; | ||
} | ||
// If we got an identifier type, escape the strings and get a local | ||
// identifier for non-string identifiers. | ||
case SQLItemType.IDENTIFIER: | ||
{ | ||
text += item.names.map(name => { | ||
if (typeof name === 'string') return escapeIdentifier(name); | ||
if (!localIdentifiers.has(name)) localIdentifiers.set(name, `__local_${localIdentifiers.size}__`); | ||
return escapeIdentifier(localIdentifiers.get(name)); | ||
}).join('.'); | ||
break; | ||
} | ||
} | ||
} | ||
if (text.trim()) { | ||
const lines = text.split('\n'); | ||
const min = Math.min(...lines.filter(l => l.trim() !== '').map(l => /^\s*/.exec(l)[0].length)); | ||
if (min) { | ||
text = lines.map(line => line.substr(min)).join('\n'); | ||
} | ||
} | ||
return { | ||
text: text.trim(), | ||
values | ||
}; | ||
} // tslint:disable:no-unbound-method | ||
// Create the SQL interface we export. | ||
const modifiedSQL = Object.assign((strings, ...values) => SQLQuery_1.default.query(strings, ...values), { | ||
// tslint:disable:no-unbound-method | ||
// tslint:disable-next-line:deprecation | ||
join: SQLQuery_1.default.join, | ||
__dangerous__rawValue: SQLQuery_1.default.raw, | ||
value: SQLQuery_1.default.value, | ||
ident: SQLQuery_1.default.ident, | ||
registerFormatter: SQLQuery_1.default.registerFormatter | ||
}); | ||
exports.default = modifiedSQL; | ||
module.exports = modifiedSQL; | ||
module.exports.default = modifiedSQL; | ||
module.exports.SQLQuery = SQLQuery_1.default; | ||
//# sourceMappingURL=web.js.map | ||
const sql = Object.assign(SQLQuery.query, { | ||
join: SQLQuery.join, | ||
__dangerous__rawValue: SQLQuery.__dangerous__rawValue, | ||
__dangerous__constructFromParts: SQLQuery.__dangerous__constructFromParts, | ||
value: SQLQuery.value, | ||
ident: SQLQuery.ident, | ||
registerFormatter: SQLQuery.registerFormatter | ||
}); // tslint:enable:no-unbound-method | ||
exports.default = sql; | ||
function isSqlQuery(query) { | ||
return query instanceof SQLQuery; | ||
} | ||
exports.isSqlQuery = isSqlQuery; | ||
module.exports = sql; | ||
module.exports.default = sql; | ||
module.exports.isSqlQuery = isSqlQuery; | ||
module.exports.SQLItemType = SQLItemType; |
{ | ||
"name": "@databases/sql", | ||
"version": "2.2.0", | ||
"version": "3.0.0", | ||
"description": "", | ||
"main": "./lib/index.js", | ||
"types": "./lib/index.d.ts", | ||
"dependencies": { | ||
"pg-minify": "^0.5.5" | ||
}, | ||
"dependencies": {}, | ||
"devDependencies": { | ||
@@ -11,0 +9,0 @@ "@types/node": "^13.13.4" |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
0
23183
14
411
1
- Removedpg-minify@^0.5.5
- Removedpg-minify@0.5.5(transitive)