1010 *
1111 * @packageDocumentation
1212 */
13+ import { isArangoAnalyzer } from "./analyzer" ;
1314import { ArangoCollection , isArangoCollection } from "./collection" ;
1415import { Graph , isArangoGraph } from "./graph" ;
1516import { isArangoView , View } from "./view" ;
@@ -51,7 +52,7 @@ export interface GeneratedAqlQuery extends AqlQuery {
5152 * when used in an AQL template or passed to AQL helper functions.
5253 *
5354 * Arbitrary values can be converted to trusted AQL literals by passing them
54- * to the {@link aql. literal} helper function.
55+ * to the {@link literal} helper function.
5556 */
5657export interface AqlLiteral {
5758 /**
@@ -244,7 +245,8 @@ export function aql(
244245 if (
245246 isArangoCollection ( rawValue ) ||
246247 isArangoGraph ( rawValue ) ||
247- isArangoView ( rawValue )
248+ isArangoView ( rawValue ) ||
249+ isArangoAnalyzer ( rawValue )
248250 ) {
249251 name = `@${ name } ` ;
250252 value = rawValue . name ;
@@ -262,153 +264,144 @@ export function aql(
262264 } ;
263265}
264266
265- // eslint-disable-next-line @typescript-eslint/no-namespace
266- export namespace aql {
267- /**
268- * Marks an arbitrary scalar value (i.e. a string, number or boolean) as
269- * safe for being inlined directly into AQL queries when used in an `aql`
270- * template string, rather than being converted into a bind parameter.
271- *
272- * **Note**: Nesting `aql` template strings is a much safer alternative for
273- * most use cases. This low-level helper function only exists to help with
274- * rare edge cases where a trusted AQL query fragment must be read from a
275- * string (e.g. when reading query fragments from JSON) and should only be
276- * used as a last resort.
277- *
278- * @example
279- * ```js
280- * // BAD! DO NOT DO THIS!
281- * const sortDirection = aql.literal('ASC');
282- *
283- * // GOOD! DO THIS INSTEAD!
284- * const sortDirection = aql`ASC`;
285- * ```
286- *
287- * @example
288- * ```js
289- * // BAD! DO NOT DO THIS!
290- * const filterColor = aql.literal('FILTER d.color == "green"');
291- * const result = await db.query(aql`
292- * FOR d IN some-collection
293- * ${filterColor}
294- * RETURN d
295- * `);
296- *
297- * // GOOD! DO THIS INSTEAD!
298- * const color = "green";
299- * const filterColor = aql`FILTER d.color === ${color}`;
300- * const result = await db.query(aql`
301- * FOR d IN some-collection
302- * ${filterColor}
303- * RETURN d
304- * `);
305- * ```
306- *
307- * @example
308- * ```js
309- * // WARNING: We explicitly trust the environment variable to be safe!
310- * const filter = aql.literal(process.env.FILTER_STATEMENT);
311- * const users = await db.query(aql`
312- * FOR user IN users
313- * ${filter}
314- * RETURN user
315- * `);
316- * ```
317- */
318- export function literal (
319- value : string | number | boolean | AqlLiteral | null | undefined
320- ) : AqlLiteral {
321- if ( isAqlLiteral ( value ) ) {
322- return value ;
323- }
324- return {
325- toAQL ( ) {
326- if ( value === undefined ) {
327- return "" ;
328- }
329- return String ( value ) ;
330- } ,
331- } ;
267+ /**
268+ * Marks an arbitrary scalar value (i.e. a string, number or boolean) as
269+ * safe for being inlined directly into AQL queries when used in an `aql`
270+ * template string, rather than being converted into a bind parameter.
271+ *
272+ * **Note**: Nesting `aql` template strings is a much safer alternative for
273+ * most use cases. This low-level helper function only exists to help with
274+ * rare edge cases where a trusted AQL query fragment must be read from a
275+ * string (e.g. when reading query fragments from JSON) and should only be
276+ * used as a last resort.
277+ *
278+ * @example
279+ * ```js
280+ * // BAD! DO NOT DO THIS!
281+ * const sortDirection = literal('ASC');
282+ *
283+ * // GOOD! DO THIS INSTEAD!
284+ * const sortDirection = aql`ASC`;
285+ * ```
286+ *
287+ * @example
288+ * ```js
289+ * // BAD! DO NOT DO THIS!
290+ * const filterColor = literal('FILTER d.color == "green"');
291+ * const result = await db.query(aql`
292+ * FOR d IN some-collection
293+ * ${filterColor}
294+ * RETURN d
295+ * `);
296+ *
297+ * // GOOD! DO THIS INSTEAD!
298+ * const color = "green";
299+ * const filterColor = aql`FILTER d.color === ${color}`;
300+ * const result = await db.query(aql`
301+ * FOR d IN some-collection
302+ * ${filterColor}
303+ * RETURN d
304+ * `);
305+ * ```
306+ *
307+ * @example
308+ * ```js
309+ * // WARNING: We explicitly trust the environment variable to be safe!
310+ * const filter = literal(process.env.FILTER_STATEMENT);
311+ * const users = await db.query(aql`
312+ * FOR user IN users
313+ * ${filter}
314+ * RETURN user
315+ * `);
316+ * ```
317+ */
318+ export function literal (
319+ value : string | number | boolean | AqlLiteral | null | undefined
320+ ) : AqlLiteral {
321+ if ( isAqlLiteral ( value ) ) {
322+ return value ;
332323 }
324+ return {
325+ toAQL ( ) {
326+ if ( value === undefined ) {
327+ return "" ;
328+ }
329+ return String ( value ) ;
330+ } ,
331+ } ;
332+ }
333333
334- /**
335- * Constructs {@link AqlQuery} objects from an array of arbitrary values.
336- *
337- * **Note**: Nesting `aql` template strings is a much safer alternative
338- * for most use cases. This low-level helper function only exists to
339- * complement the `aql` tag when constructing complex queries from dynamic
340- * arrays of query fragments.
341- *
342- * @param values - Array of values to join. These values will behave exactly
343- * like values interpolated in an `aql` template string.
344- * @param sep - Seperator to insert between values. This value will behave
345- * exactly like a value passed to {@link literal}, i.e. it will be
346- * inlined as-is, rather than being converted into a bind parameter.
347- *
348- * @example
349- * ```js
350- * const users = db.collection("users");
351- * const filters = [];
352- * if (adminsOnly) filters.push(aql`FILTER user.admin`);
353- * if (activeOnly) filters.push(aql`FILTER user.active`);
354- * const result = await db.query(aql`
355- * FOR user IN ${users}
356- * ${aql.join(filters)}
357- * RETURN user
358- * `);
359- * ```
360- *
361- * @example
362- * ```js
363- * const users = db.collection("users");
364- * const keys = ["jreyes", "ghermann"];
365- *
366- * // BAD! NEEDLESSLY COMPLEX!
367- * const docs = keys.map(key => aql`DOCUMENT(${users}, ${key}`));
368- * const result = await db.query(aql`
369- * FOR user IN [
370- * ${aql.join(docs, ", ")}
371- * ]
372- * RETURN user
373- * `);
374- * // Query:
375- * // FOR user IN [
376- * // DOCUMENT(@@value0, @value1), DOCUMENT(@@value0, @value2)
377- * // ]
378- * // RETURN user
379- * // Bind parameters:
380- * // @value 0 -> "users"
381- * // value1 -> "jreyes"
382- * // value2 -> "ghermann"
383- *
384- * // GOOD! MUCH SIMPLER!
385- * const result = await db.query(aql`
386- * FOR key IN ${keys}
387- * LET user = DOCUMENT(${users}, key)
388- * RETURN user
389- * `);
390- * // Query:
391- * // FOR user IN @value 0
392- * // LET user = DOCUMENT(@@value1, key)
393- * // RETURN user
394- * // Bind parameters:
395- * // value0 -> ["jreyes", "ghermann"]
396- * // @value 1 -> "users"
397- * ```
398- */
399- export function join (
400- values : AqlValue [ ] ,
401- sep : string = " "
402- ) : GeneratedAqlQuery {
403- if ( ! values . length ) {
404- return aql `` ;
405- }
406- if ( values . length === 1 ) {
407- return aql `${ values [ 0 ] } ` ;
408- }
409- return aql (
410- [ "" , ...Array ( values . length - 1 ) . fill ( sep ) , "" ] as any ,
411- ...values
412- ) ;
334+ /**
335+ * Constructs {@link AqlQuery} objects from an array of arbitrary values.
336+ *
337+ * **Note**: Nesting `aql` template strings is a much safer alternative
338+ * for most use cases. This low-level helper function only exists to
339+ * complement the `aql` tag when constructing complex queries from dynamic
340+ * arrays of query fragments.
341+ *
342+ * @param values - Array of values to join. These values will behave exactly
343+ * like values interpolated in an `aql` template string.
344+ * @param sep - Seperator to insert between values. This value will behave
345+ * exactly like a value passed to {@link literal}, i.e. it will be
346+ * inlined as-is, rather than being converted into a bind parameter.
347+ *
348+ * @example
349+ * ```js
350+ * const users = db.collection("users");
351+ * const filters = [];
352+ * if (adminsOnly) filters.push(aql`FILTER user.admin`);
353+ * if (activeOnly) filters.push(aql`FILTER user.active`);
354+ * const result = await db.query(aql`
355+ * FOR user IN ${users}
356+ * ${join(filters)}
357+ * RETURN user
358+ * `);
359+ * ```
360+ *
361+ * @example
362+ * ```js
363+ * const users = db.collection("users");
364+ * const keys = ["jreyes", "ghermann"];
365+ *
366+ * // BAD! NEEDLESSLY COMPLEX!
367+ * const docs = keys.map(key => aql`DOCUMENT(${users}, ${key}`));
368+ * const result = await db.query(aql`
369+ * FOR user IN [
370+ * ${join(docs, ", ")}
371+ * ]
372+ * RETURN user
373+ * `);
374+ * // Query:
375+ * // FOR user IN [
376+ * // DOCUMENT(@@value0, @value1), DOCUMENT(@@value0, @value2)
377+ * // ]
378+ * // RETURN user
379+ * // Bind parameters:
380+ * // @value 0 -> "users"
381+ * // value1 -> "jreyes"
382+ * // value2 -> "ghermann"
383+ *
384+ * // GOOD! MUCH SIMPLER!
385+ * const result = await db.query(aql`
386+ * FOR key IN ${keys}
387+ * LET user = DOCUMENT(${users}, key)
388+ * RETURN user
389+ * `);
390+ * // Query:
391+ * // FOR user IN @value 0
392+ * // LET user = DOCUMENT(@@value1, key)
393+ * // RETURN user
394+ * // Bind parameters:
395+ * // value0 -> ["jreyes", "ghermann"]
396+ * // @value 1 -> "users"
397+ * ```
398+ */
399+ export function join ( values : AqlValue [ ] , sep : string = " " ) : GeneratedAqlQuery {
400+ if ( ! values . length ) {
401+ return aql `` ;
402+ }
403+ if ( values . length === 1 ) {
404+ return aql `${ values [ 0 ] } ` ;
413405 }
406+ return aql ( [ "" , ...Array ( values . length - 1 ) . fill ( sep ) , "" ] as any , ...values ) ;
414407}
0 commit comments