UNPKG

8.81 kBTypeScriptView Raw
1import { ArangoCollection } from "./collection";
2import { Graph } from "./graph";
3import { View } from "./view";
4declare const type: unique symbol;
5/**
6 * Generic AQL query object consisting of an AQL query string and its bind
7 * parameters.
8 */
9export interface AqlQuery<T = any> {
10 [type]?: T | any;
11 /**
12 * An AQL query string.
13 */
14 query: string;
15 /**
16 * An object mapping AQL bind parameter names to their respective values.
17 *
18 * Names of parameters representing collections are prefixed with an
19 * at-symbol.
20 */
21 bindVars: Record<string, any>;
22}
23/**
24 * Derived type representing AQL query objects generated by the AQL helper
25 * functions and the AQL template string handler. These objects can be fed
26 * back into these helper functions to be inlined or merged in complex queries.
27 *
28 * @internal
29 */
30export interface GeneratedAqlQuery<T = any> extends AqlQuery<T> {
31 /**
32 * @internal
33 */
34 _source: () => {
35 strings: string[];
36 args: AqlValue[];
37 };
38}
39/**
40 * An object representing a trusted AQL literal that will be inlined directly
41 * when used in an AQL template or passed to AQL helper functions.
42 *
43 * Arbitrary values can be converted to trusted AQL literals by passing them
44 * to the {@link literal} helper function.
45 */
46export interface AqlLiteral {
47 /**
48 * @internal
49 *
50 * Returns a string representation of this AQL literal that can be inlined
51 * in an AQL template.
52 */
53 toAQL: () => string;
54}
55/**
56 * A value that can be used in an AQL template string or passed to an AQL
57 * helper function.
58 */
59export type AqlValue = ArangoCollection | View | Graph | GeneratedAqlQuery | AqlLiteral | string | number | boolean | null | undefined | Record<string, any> | any[];
60/**
61 * Indicates whether the given value is an {@link AqlQuery}.
62 *
63 * @param query - A value that might be an `AqlQuery`.
64 */
65export declare function isAqlQuery(query: any): query is AqlQuery;
66/**
67 * Indicates whether the given value is a {@link GeneratedAqlQuery}.
68 *
69 * @param query - A value that might be a `GeneratedAqlQuery`.
70 *
71 * @internal
72 */
73export declare function isGeneratedAqlQuery(query: any): query is GeneratedAqlQuery;
74/**
75 * Indicates whether the given value is an {@link AqlLiteral}.
76 *
77 * @param literal - A value that might be an `AqlLiteral`.
78 */
79export declare function isAqlLiteral(literal: any): literal is AqlLiteral;
80/**
81 * Template string handler (template tag) for AQL queries.
82 *
83 * The `aql` tag can be used to write complex AQL queries as multi-line strings
84 * without having to worry about `bindVars` and the distinction between
85 * collections and regular parameters.
86 *
87 * Tagged template strings will return an {@link AqlQuery} object with
88 * `query` and `bindVars` attributes reflecting any interpolated values.
89 *
90 * Any {@link collection.ArangoCollection} instance used in a query string will
91 * be recognized as a collection reference and generate an AQL collection bind
92 * parameter instead of a regular AQL value bind parameter.
93 *
94 * **Note**: you should always use the `aql` template tag when writing
95 * dynamic AQL queries instead of using untagged (normal) template strings.
96 * Untagged template strings will inline any interpolated values and return
97 * a plain string as result. The `aql` template tag will only inline references
98 * to the interpolated values and produce an AQL query object containing both
99 * the query and the values. This prevents most injection attacks when using
100 * untrusted values in dynamic queries.
101 *
102 * @example
103 * ```js
104 * // Some user-supplied string that may be malicious
105 * const untrustedValue = req.body.email;
106 *
107 * // Without aql tag: BAD! DO NOT DO THIS!
108 * const badQuery = `
109 * FOR user IN users
110 * FILTER user.email == "${untrustedValue}"
111 * RETURN user
112 * `;
113 * // e.g. if untrustedValue is '" || user.admin == true || "':
114 * // Query:
115 * // FOR user IN users
116 * // FILTER user.email == "" || user.admin == true || ""
117 * // RETURN user
118 *
119 * // With the aql tag: GOOD! MUCH SAFER!
120 * const betterQuery = aql`
121 * FOR user IN users
122 * FILTER user.email == ${untrustedValue}
123 * RETURN user
124 * `;
125 * // Query:
126 * // FOR user IN users
127 * // FILTER user.email == @value0
128 * // RETURN user
129 * // Bind parameters:
130 * // value0 -> untrustedValue
131 * ```
132 *
133 * @example
134 * ```js
135 * const collection = db.collection("some-collection");
136 * const minValue = 23;
137 * const result = await db.query(aql`
138 * FOR d IN ${collection}
139 * FILTER d.num > ${minValue}
140 * RETURN d
141 * `);
142 *
143 * // Equivalent raw query object
144 * const result2 = await db.query({
145 * query: `
146 * FOR d IN @@collection
147 * FILTER d.num > @minValue
148 * RETURN d
149 * `,
150 * bindVars: {
151 * "@collection": collection.name,
152 * minValue: minValue
153 * }
154 * });
155 * ```
156 *
157 * @example
158 * ```js
159 * const collection = db.collection("some-collection");
160 * const color = "green";
161 * const filter = aql`FILTER d.color == ${color}'`;
162 * const result = await db.query(aql`
163 * FOR d IN ${collection}
164 * ${filter}
165 * RETURN d
166 * `);
167 * ```
168 */
169export declare function aql<T = any>(templateStrings: TemplateStringsArray, ...args: AqlValue[]): GeneratedAqlQuery<T>;
170/**
171 * Marks an arbitrary scalar value (i.e. a string, number or boolean) as
172 * safe for being inlined directly into AQL queries when used in an `aql`
173 * template string, rather than being converted into a bind parameter.
174 *
175 * **Note**: Nesting `aql` template strings is a much safer alternative for
176 * most use cases. This low-level helper function only exists to help with
177 * rare edge cases where a trusted AQL query fragment must be read from a
178 * string (e.g. when reading query fragments from JSON) and should only be
179 * used as a last resort.
180 *
181 * @example
182 * ```js
183 * // BAD! DO NOT DO THIS!
184 * const sortDirection = literal('ASC');
185 *
186 * // GOOD! DO THIS INSTEAD!
187 * const sortDirection = aql`ASC`;
188 * ```
189 *
190 * @example
191 * ```js
192 * // BAD! DO NOT DO THIS!
193 * const filterColor = literal('FILTER d.color == "green"');
194 * const result = await db.query(aql`
195 * FOR d IN some-collection
196 * ${filterColor}
197 * RETURN d
198 * `);
199 *
200 * // GOOD! DO THIS INSTEAD!
201 * const color = "green";
202 * const filterColor = aql`FILTER d.color === ${color}`;
203 * const result = await db.query(aql`
204 * FOR d IN some-collection
205 * ${filterColor}
206 * RETURN d
207 * `);
208 * ```
209 *
210 * @example
211 * ```js
212 * // WARNING: We explicitly trust the environment variable to be safe!
213 * const filter = literal(process.env.FILTER_STATEMENT);
214 * const users = await db.query(aql`
215 * FOR user IN users
216 * ${filter}
217 * RETURN user
218 * `);
219 * ```
220 */
221export declare function literal(value: string | number | boolean | AqlLiteral | null | undefined): AqlLiteral;
222/**
223 * Constructs {@link AqlQuery} objects from an array of arbitrary values.
224 *
225 * **Note**: Nesting `aql` template strings is a much safer alternative
226 * for most use cases. This low-level helper function only exists to
227 * complement the `aql` tag when constructing complex queries from dynamic
228 * arrays of query fragments.
229 *
230 * @param values - Array of values to join. These values will behave exactly
231 * like values interpolated in an `aql` template string.
232 * @param sep - Seperator to insert between values. This value will behave
233 * exactly like a value passed to {@link literal}, i.e. it will be
234 * inlined as-is, rather than being converted into a bind parameter.
235 *
236 * @example
237 * ```js
238 * const users = db.collection("users");
239 * const filters = [];
240 * if (adminsOnly) filters.push(aql`FILTER user.admin`);
241 * if (activeOnly) filters.push(aql`FILTER user.active`);
242 * const result = await db.query(aql`
243 * FOR user IN ${users}
244 * ${join(filters)}
245 * RETURN user
246 * `);
247 * ```
248 *
249 * @example
250 * ```js
251 * const users = db.collection("users");
252 * const keys = ["jreyes", "ghermann"];
253 *
254 * // BAD! NEEDLESSLY COMPLEX!
255 * const docs = keys.map(key => aql`DOCUMENT(${users}, ${key}`));
256 * const result = await db.query(aql`
257 * FOR user IN [
258 * ${join(docs, ", ")}
259 * ]
260 * RETURN user
261 * `);
262 * // Query:
263 * // FOR user IN [
264 * // DOCUMENT(@@value0, @value1), DOCUMENT(@@value0, @value2)
265 * // ]
266 * // RETURN user
267 * // Bind parameters:
268 * // @value0 -> "users"
269 * // value1 -> "jreyes"
270 * // value2 -> "ghermann"
271 *
272 * // GOOD! MUCH SIMPLER!
273 * const result = await db.query(aql`
274 * FOR key IN ${keys}
275 * LET user = DOCUMENT(${users}, key)
276 * RETURN user
277 * `);
278 * // Query:
279 * // FOR user IN @value0
280 * // LET user = DOCUMENT(@@value1, key)
281 * // RETURN user
282 * // Bind parameters:
283 * // value0 -> ["jreyes", "ghermann"]
284 * // @value1 -> "users"
285 * ```
286 */
287export declare function join(values: AqlValue[], sep?: string): GeneratedAqlQuery;
288export {};
289//# sourceMappingURL=aql.d.ts.map
\No newline at end of file