From dd3d36a24041d8f237732dea41822674807479dc Mon Sep 17 00:00:00 2001 From: Aneurin Barker Snook Date: Wed, 9 Nov 2022 14:56:23 +0000 Subject: [PATCH] build dist --- dist/lib/index.d.ts | 46 +++++++++++++++++++++++++++++++++++++++------ dist/lib/index.js | 22 ++++++++++++++-------- 2 files changed, 54 insertions(+), 14 deletions(-) diff --git a/dist/lib/index.d.ts b/dist/lib/index.d.ts index d0c25f0..6cf70e4 100644 --- a/dist/lib/index.d.ts +++ b/dist/lib/index.d.ts @@ -1,13 +1,13 @@ import { Document } from 'arangojs/documents'; import { DocumentCollection } from 'arangojs/collection'; -import { GeneratedAqlQuery } from 'arangojs/aql'; +import { AqlLiteral, GeneratedAqlQuery } from 'arangojs/aql'; import { Database } from 'arangojs'; /** * A `CountFn` function returns the number of documents in a single collection matching search `terms` given. * * `count()` provides the standard implementation. */ -export declare type CountFn = (terms?: Terms>>) => Promise; +export declare type CountFn = (terms?: Terms>>, inject?: Inject) => Promise; /** * Recursively renders all of a complex object's properties required, non-null, and non-undefined. * @@ -48,7 +48,26 @@ export declare type Filter = { * * `find()` provides the standard implementation. */ -export declare type FindFn = (terms?: Terms>>, sort?: Sort>[] | Sort>) => Promise | undefined>; +export declare type FindFn = (terms?: Terms>>, sort?: Sort>[] | Sort>, inject?: Inject) => Promise | undefined>; +/** + * An `Inject` object allows modifying a search query with user-defined AQL literal expressions. + * This can be useful for complex requirements, such as joining data or setting additional variables with `LET`. + * + * All injected strings are implicitly converted to AQL literals in the query, so should be manually escaped as needed. + * + * Note that while `CountFn` and `FindFn` do not use all the same parameters as `SearchFn`, all injections are still + * supported so a single injection provider can be used for all query types. + */ +export declare type Inject = { + /** Injected before FILTER statements. */ + beforeFilter?: string; + /** Injected after FILTER statements, before SORT statements. */ + beforeSort?: string; + /** Injected after SORT statements, before LIMIT statement. */ + beforeLimit?: string; + /** Injected after all other statements. */ + after?: string; +}; /** * Query limit. * Always a tuple, but the second value can be omitted. @@ -69,8 +88,18 @@ export declare type Terms = { /** * A `SearchFn` function matches documents in a single collection and returns a `SearchResult` based on the given * `terms`, `limit`, and `sort`. + * + * A fourth `inject` argument can be given to add user-defined sections to the query, allowing complex requirements + * to be added around the core query pattern. */ -export declare type SearchFn = (terms?: Terms>>, limit?: Limit, sort?: Sort>[] | Sort>) => Promise>; +export declare type SearchFn = (terms?: Terms>>, limit?: Limit, sort?: Sort>[] | Sort>, inject?: Inject) => Promise>; +/** + * A `SimpleSearchFn` function matches documents in a single collection and returns a `SearchResult` based on the given + * `terms`, `limit`, and `sort`. + * + * This type can be implemented by user code as an alternative to `SearchFn` to prevent further injections. + */ +export declare type SimpleSearchFn = (terms?: Terms>>, limit?: Limit, sort?: Sort>[] | Sort>) => Promise>; /** * Search results are a tuple of three values: * 1. The **total** number of matching documents in the searched collection, ignoring limit @@ -78,8 +107,13 @@ export declare type SearchFn = ( * 3. The AQL query object for the latter (for debugging purposes) */ export declare type SearchResult = [number, Document[], GeneratedAqlQuery]; -/** Query sort order. */ -export declare type Sort = [keyof T, Direction]; +/** + * Query sort order as a tuple of key and direction. + * + * The sort key can be specified as an AQL literal, in which case it will be used exactly as given. + * This can be useful in conjunction with query injections. + */ +export declare type Sort = [AqlLiteral | keyof T, Direction]; /** Format scalar or scalar array data for use in AQL. */ export declare const formatData: (data: T | T[]) => string; /** Format scalar data for use in AQL. */ diff --git a/dist/lib/index.js b/dist/lib/index.js index fa15405..09d7384 100644 --- a/dist/lib/index.js +++ b/dist/lib/index.js @@ -109,7 +109,7 @@ var parseFilterOps = function (search) { */ var parseSort = function (s, parent) { if (s[0] instanceof Array) - return s.map(function (ss) { return "".concat(parent, ".").concat(String(ss[0]), " ").concat(ss[1]); }); + return s.map(function (ss) { return "".concat(renderSortKey(ss, parent), " ").concat(ss[1]); }); return ["".concat(parent, ".").concat(String(s[0]), " ").concat(s[1])]; }; exports.parseSort = parseSort; @@ -133,6 +133,12 @@ var parseTerms = function (s, parent) { return Object.keys(s) return filters; }, []); }; exports.parseTerms = parseTerms; +var renderSortKey = function (_a, parent) { + var key = _a[0]; + if (key instanceof Object) + return key.toAQL(); + return "".concat(parent, ".").concat(String(key)); +}; /** * Build and execute a count query that matches documents in a single collection. * Returns the total number of matches. @@ -146,7 +152,7 @@ exports.parseTerms = parseTerms; var count = function (db, c, i, n) { if (i === void 0) { i = 'i'; } if (n === void 0) { n = 'n'; } - return function (terms) { return __awaiter(void 0, void 0, void 0, function () { + return function (terms, inject) { return __awaiter(void 0, void 0, void 0, function () { var filters, filterStr, l, countQuery; return __generator(this, function (_a) { switch (_a.label) { @@ -154,7 +160,7 @@ var count = function (db, c, i, n) { filters = terms && (0, exports.parseTerms)(terms, i); filterStr = arangojs_1.aql.literal(filters ? filters.map(function (f) { return "FILTER ".concat(f); }).join(' ') : ''); l = { i: arangojs_1.aql.literal(i), n: arangojs_1.aql.literal(n) }; - countQuery = (0, arangojs_1.aql)(templateObject_1 || (templateObject_1 = __makeTemplateObject(["\n FOR ", " IN ", "\n ", "\n COLLECT WITH COUNT INTO ", "\n RETURN ", "\n "], ["\n FOR ", " IN ", "\n ", "\n COLLECT WITH COUNT INTO ", "\n RETURN ", "\n "])), l.i, c, filterStr, l.n, l.n); + countQuery = (0, arangojs_1.aql)(templateObject_1 || (templateObject_1 = __makeTemplateObject(["\n FOR ", " IN ", "\n ", "\n ", "\n ", "\n ", "\n ", "\n COLLECT WITH COUNT INTO ", "\n RETURN ", "\n "], ["\n FOR ", " IN ", "\n ", "\n ", "\n ", "\n ", "\n ", "\n COLLECT WITH COUNT INTO ", "\n RETURN ", "\n "])), l.i, c, (inject === null || inject === void 0 ? void 0 : inject.beforeFilter) && arangojs_1.aql.literal(inject.beforeFilter), filterStr, (inject === null || inject === void 0 ? void 0 : inject.beforeSort) && arangojs_1.aql.literal(inject.beforeSort), (inject === null || inject === void 0 ? void 0 : inject.beforeLimit) && arangojs_1.aql.literal(inject.beforeLimit), (inject === null || inject === void 0 ? void 0 : inject.after) && arangojs_1.aql.literal(inject.after), l.n, l.n); return [4 /*yield*/, db.query(countQuery)]; case 1: return [4 /*yield*/, (_a.sent()).next()]; case 2: return [2 /*return*/, _a.sent()]; @@ -174,7 +180,7 @@ exports.count = count; */ var find = function (db, c, i) { if (i === void 0) { i = 'i'; } - return function (terms, sort) { + return function (terms, sort, inject) { if (sort === void 0) { sort = ['_key', 'ASC']; } return __awaiter(void 0, void 0, void 0, function () { var filters, filterStr, sortStr, l, query, data; @@ -185,7 +191,7 @@ var find = function (db, c, i) { filterStr = arangojs_1.aql.literal(filters ? filters.map(function (f) { return "FILTER ".concat(f); }).join(' ') : ''); sortStr = arangojs_1.aql.literal(sort ? "SORT ".concat((0, exports.parseSort)(sort, 'i').join(', ')) : ''); l = { i: arangojs_1.aql.literal(i) }; - query = (0, arangojs_1.aql)(templateObject_2 || (templateObject_2 = __makeTemplateObject(["\n FOR ", " IN ", "\n ", "\n ", "\n LIMIT 1\n RETURN ", "\n "], ["\n FOR ", " IN ", "\n ", "\n ", "\n LIMIT 1\n RETURN ", "\n "])), l.i, c, filterStr, sortStr, l.i); + query = (0, arangojs_1.aql)(templateObject_2 || (templateObject_2 = __makeTemplateObject(["\n FOR ", " IN ", "\n ", "\n ", "\n ", "\n ", "\n ", "\n ", "\n LIMIT 1\n RETURN ", "\n "], ["\n FOR ", " IN ", "\n ", "\n ", "\n ", "\n ", "\n ", "\n ", "\n LIMIT 1\n RETURN ", "\n "])), l.i, c, (inject === null || inject === void 0 ? void 0 : inject.beforeFilter) && arangojs_1.aql.literal(inject.beforeFilter), filterStr, (inject === null || inject === void 0 ? void 0 : inject.beforeSort) && arangojs_1.aql.literal(inject.beforeSort), sortStr, (inject === null || inject === void 0 ? void 0 : inject.beforeLimit) && arangojs_1.aql.literal(inject.beforeLimit), (inject === null || inject === void 0 ? void 0 : inject.after) && arangojs_1.aql.literal(inject.after), l.i); return [4 /*yield*/, db.query(query)]; case 1: return [4 /*yield*/, (_a.sent()).next()]; case 2: @@ -211,7 +217,7 @@ exports.find = find; var search = function (db, c, i, n) { if (i === void 0) { i = 'i'; } if (n === void 0) { n = 'n'; } - return function (terms, limit, sort) { + return function (terms, limit, sort, inject) { if (sort === void 0) { sort = ['_rev', 'ASC']; } return __awaiter(void 0, void 0, void 0, function () { var filters, filterStr, limitStr, sortStr, l, count, countQuery, query, data; @@ -225,14 +231,14 @@ var search = function (db, c, i, n) { l = { i: arangojs_1.aql.literal(i), n: arangojs_1.aql.literal(n) }; count = 0; if (!limit) return [3 /*break*/, 3]; - countQuery = (0, arangojs_1.aql)(templateObject_3 || (templateObject_3 = __makeTemplateObject(["\n FOR ", " IN ", "\n ", "\n COLLECT WITH COUNT INTO ", "\n RETURN ", "\n "], ["\n FOR ", " IN ", "\n ", "\n COLLECT WITH COUNT INTO ", "\n RETURN ", "\n "])), l.i, c, filterStr, l.n, l.n); + countQuery = (0, arangojs_1.aql)(templateObject_3 || (templateObject_3 = __makeTemplateObject(["\n FOR ", " IN ", "\n ", "\n ", "\n ", "\n ", "\n ", "\n COLLECT WITH COUNT INTO ", "\n RETURN ", "\n "], ["\n FOR ", " IN ", "\n ", "\n ", "\n ", "\n ", "\n ", "\n COLLECT WITH COUNT INTO ", "\n RETURN ", "\n "])), l.i, c, (inject === null || inject === void 0 ? void 0 : inject.beforeFilter) && arangojs_1.aql.literal(inject.beforeFilter), filterStr, (inject === null || inject === void 0 ? void 0 : inject.beforeSort) && arangojs_1.aql.literal(inject.beforeSort), (inject === null || inject === void 0 ? void 0 : inject.beforeLimit) && arangojs_1.aql.literal(inject.beforeLimit), (inject === null || inject === void 0 ? void 0 : inject.after) && arangojs_1.aql.literal(inject.after), l.n, l.n); return [4 /*yield*/, db.query(countQuery)]; case 1: return [4 /*yield*/, (_a.sent()).next()]; case 2: count = _a.sent(); _a.label = 3; case 3: - query = (0, arangojs_1.aql)(templateObject_4 || (templateObject_4 = __makeTemplateObject(["\n FOR ", " IN ", "\n ", "\n ", "\n ", "\n RETURN ", "\n "], ["\n FOR ", " IN ", "\n ", "\n ", "\n ", "\n RETURN ", "\n "])), l.i, c, filterStr, sortStr, limitStr, l.i); + query = (0, arangojs_1.aql)(templateObject_4 || (templateObject_4 = __makeTemplateObject(["\n FOR ", " IN ", "\n ", "\n ", "\n ", "\n ", "\n ", "\n ", "\n ", "\n RETURN ", "\n "], ["\n FOR ", " IN ", "\n ", "\n ", "\n ", "\n ", "\n ", "\n ", "\n ", "\n RETURN ", "\n "])), l.i, c, (inject === null || inject === void 0 ? void 0 : inject.beforeFilter) && arangojs_1.aql.literal(inject.beforeFilter), filterStr, (inject === null || inject === void 0 ? void 0 : inject.beforeSort) && arangojs_1.aql.literal(inject.beforeSort), sortStr, (inject === null || inject === void 0 ? void 0 : inject.beforeLimit) && arangojs_1.aql.literal(inject.beforeLimit), limitStr, (inject === null || inject === void 0 ? void 0 : inject.after) && arangojs_1.aql.literal(inject.after), l.i); return [4 /*yield*/, db.query(query)]; case 4: return [4 /*yield*/, (_a.sent()).all()]; case 5: