UNPKG

arangojs

Version:

The official ArangoDB JavaScript driver.

2,834 lines 92.3 kB
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
    if (mod && mod.__esModule) return mod;
    var result = {};
    if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
    __setModuleDefault(result, mod);
    return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Database = exports.isArangoDatabase = void 0;
const analyzers = __importStar(require("./analyzers.js"));
const aql = __importStar(require("./aql.js"));
const collections = __importStar(require("./collections.js"));
const connection = __importStar(require("./connection.js"));
const cursors = __importStar(require("./cursors.js"));
const errors = __importStar(require("./errors.js"));
const graphs = __importStar(require("./graphs.js"));
const jobs = __importStar(require("./jobs.js"));
const codes_js_1 = require("./lib/codes.js");
const util = __importStar(require("./lib/util.js"));
const routes = __importStar(require("./routes.js"));
const transactions = __importStar(require("./transactions.js"));
const views = __importStar(require("./views.js"));
//#region Database class
/**
 * Indicates whether the given value represents a {@link Database}.
 *
 * @param database - A value that might be a database.
 */
function isArangoDatabase(database) {
    return Boolean(database && database.isArangoDatabase);
}
exports.isArangoDatabase = isArangoDatabase;
/**
 * An object representing a single ArangoDB database. All arangojs collections,
 * cursors, analyzers and so on are linked to a `Database` object.
 */
class Database {
    _connection;
    _name;
    _analyzers = new Map();
    _collections = new Map();
    _graphs = new Map();
    _views = new Map();
    _trapRequest;
    constructor(configOrDatabase = {}, name) {
        if (isArangoDatabase(configOrDatabase)) {
            const connection = configOrDatabase._connection;
            const databaseName = name || configOrDatabase.name;
            this._connection = connection;
            this._name = databaseName;
            const database = connection.database(databaseName);
            if (database)
                return database;
        }
        else {
            const config = configOrDatabase;
            const { databaseName, ...options } = typeof config === "string" || Array.isArray(config)
                ? { databaseName: name, url: config }
                : config;
            this._connection = new connection.Connection(options);
            this._name = databaseName || "_system";
        }
    }
    //#region misc
    /**
     * @internal
     *
     * Indicates that this object represents an ArangoDB database.
     */
    get isArangoDatabase() {
        return true;
    }
    /**
     * Name of the ArangoDB database this instance represents.
     */
    get name() {
        return this._name;
    }
    /**
     * @deprecated Removed from ArangoDB 4.0 onwards.
     * Calling this method against ArangoDB v4 will result in a runtime exception.
     *
     * Returns a new {@link routes.Route} instance for the given path (relative to the
     * database) that can be used to perform arbitrary HTTP requests.
     *
     * @param path - The database-relative URL of the route. Defaults to the
     * database API root.
     * @param headers - Default headers that should be sent with each request to
     * the route.
     *
     * @example
     * ```js
     * const db = new Database();
     * const myFoxxService = db.route("my-foxx-service");
     * const response = await myFoxxService.post("users", {
     *   username: "admin",
     *   password: "hunter2"
     * });
     * // response.body is the result of
     * // POST /_db/_system/my-foxx-service/users
     * // with JSON request body '{"username": "admin", "password": "hunter2"}'
     * ```
     */
    route(path, headers) {
        return new routes.Route(this, path, headers);
    }
    async request({ pathname, ...opts }, transform = (res) => res.parsedBody) {
        pathname = util.joinPath("_db", encodeURIComponent(this._name), pathname);
        if (this._trapRequest) {
            const trap = this._trapRequest;
            this._trapRequest = undefined;
            return new Promise(async (resolveRequest, rejectRequest) => {
                opts.headers = new Headers(opts.headers);
                opts.headers.set("x-arango-async", "store");
                let jobRes;
                try {
                    jobRes = await this._connection.request({ pathname, ...opts });
                }
                catch (e) {
                    trap({ error: true });
                    rejectRequest(e);
                    return;
                }
                const jobId = jobRes.headers.get("x-arango-async-id");
                trap({
                    jobId,
                    onResolve: (res) => {
                        const result = transform ? transform(res) : res;
                        resolveRequest(result);
                        return result;
                    },
                    onReject: (err) => {
                        rejectRequest(err);
                        throw err;
                    },
                });
            });
        }
        return this._connection.request({ pathname, ...opts }, transform || undefined);
    }
    /**
     * Updates the URL list by requesting a list of all coordinators in the
     * cluster and adding any endpoints not initially specified in the
     * {@link configuration.ConfigOptions}.
     *
     * For long-running processes communicating with an ArangoDB cluster it is
     * recommended to run this method periodically (e.g. once per hour) to make
     * sure new coordinators are picked up correctly and can be used for
     * fail-over or load balancing.
     *
     * @param overwrite - If set to `true`, the existing host list will be
     * replaced instead of extended.
     *
     * @example
     * ```js
     * const db = new Database();
     * const interval = setInterval(
     *   () => db.acquireHostList(),
     *   5 * 60 * 1000 // every 5 minutes
     * );
     *
     * // later
     * clearInterval(interval);
     * system.close();
     * ```
     */
    async acquireHostList(overwrite = false) {
        const urls = await this.request({ pathname: "/_api/cluster/endpoints" }, (res) => res.parsedBody.endpoints.map((endpoint) => endpoint.endpoint));
        if (urls.length > 0) {
            if (overwrite)
                this._connection.setHostList(urls);
            else
                this._connection.addToHostList(urls);
        }
    }
    /**
     * Closes all active connections of this database instance.
     *
     * Can be used to clean up idling connections during longer periods of
     * inactivity.
     *
     * **Note**: This method currently has no effect in the browser version of
     * arangojs.
     *
     * @example
     * ```js
     * const db = new Database();
     * const sessions = db.collection("sessions");
     * // Clean up expired sessions once per hour
     * setInterval(async () => {
     *   await db.query(aql`
     *     FOR session IN ${sessions}
     *     FILTER session.expires < DATE_NOW()
     *     REMOVE session IN ${sessions}
     *   `);
     *   // Making sure to close the connections because they're no longer used
     *   system.close();
     * }, 1000 * 60 * 60);
     * ```
     */
    close() {
        this._connection.close();
    }
    async waitForPropagation({ pathname, ...request }, timeout) {
        await this._connection.waitForPropagation({
            ...request,
            pathname: util.joinPath("_db", encodeURIComponent(this._name), pathname),
        }, timeout);
    }
    /**
     * Methods for accessing the server-reported queue times of the mostly
     * recently received responses.
     */
    get queueTime() {
        return this._connection.queueTime;
    }
    /**
     * Sets the limit for the number of values of the most recently received
     * server-reported queue times that can be accessed using
     * {@link Database#queueTime}.
     *
     * @param responseQueueTimeSamples - Number of values to maintain.
     */
    setResponseQueueTimeSamples(responseQueueTimeSamples) {
        this._connection.setResponseQueueTimeSamples(responseQueueTimeSamples);
    }
    //#endregion
    //#region auth
    /**
     * Updates the underlying connection's `authorization` header to use Basic
     * authentication with the given `username` and `password`, then returns
     * itself.
     *
     * @param username - The username to authenticate with.
     * @param password - The password to authenticate with.
     *
     * @example
     * ```js
     * const db = new Database();
     * db.useBasicAuth("admin", "hunter2");
     * // with the username "admin" and password "hunter2".
     * ```
     */
    useBasicAuth(username = "root", password = "") {
        this._connection.setBasicAuth({ username, password });
        return this;
    }
    /**
     * Updates the underlying connection's `authorization` header to use Bearer
     * authentication with the given authentication `token`, then returns itself.
     *
     * @param token - The token to authenticate with.
     *
     * @example
     * ```js
     * const db = new Database();
     * db.useBearerAuth("keyboardcat");
     * // The database instance now uses Bearer authentication.
     * ```
     */
    useBearerAuth(token) {
        this._connection.setBearerAuth({ token });
        return this;
    }
    /**
     * Updates the underlying connection's `authorization` header to use Basic
     * authentication with the given access token, then returns itself.
     *
     * Access tokens contain embedded username information, so the username field
     * in Basic Auth can be empty. The token acts as a password replacement.
     *
     * @param token - The access token to authenticate with.
     *
     * @example
     * ```js
     * const db = new Database();
     * const tokenResult = await db.createAccessToken("appUser", {
     *   name: "CI token"
     * });
     * db.useAccessToken(tokenResult.token);
     * // The database instance now uses the access token for authentication.
     * ```
     */
    useAccessToken(token) {
        if (!token || typeof token !== "string") {
            throw new Error("Token must be a non-empty string");
        }
        // Access tokens can be used with empty username in Basic Auth
        // The token contains embedded username information
        return this.useBasicAuth("", token);
    }
    /**
     * Validates the given database credentials and exchanges them for an
     * authentication token, then uses the authentication token for future
     * requests and returns it.
     *
     * @param username - The username to authenticate with.
     * @param password - The password to authenticate with.
     *
     * @example
     * ```js
     * const db = new Database();
     * await db.login("admin", "hunter2");
     * // with an authentication token for the "admin" user.
     * ```
     */
    login(username = "root", password = "") {
        return this.request({
            method: "POST",
            pathname: "/_open/auth",
            body: { username, password },
        }, (res) => {
            this.useBearerAuth(res.parsedBody.jwt);
            return res.parsedBody.jwt;
        });
    }
    /**
     * Attempts to renew the authentication token passed to {@link Database#useBearerAuth}
     * or returned and used by {@link Database#login}. If a new authentication
     * token is issued, it will be used for future requests and returned.
     *
     * @example
     * ```js
     * const db = new Database();
     * await db.login("admin", "hunter2");
     * // ... later ...
     * const newToken = await db.renewAuthToken();
     * if (!newToken) // no new token issued
     * ```
     */
    renewAuthToken() {
        return this.request({
            method: "POST",
            pathname: "/_open/auth/renew",
        }, (res) => {
            if (!res.parsedBody.jwt)
                return null;
            this.useBearerAuth(res.parsedBody.jwt);
            return res.parsedBody.jwt;
        });
    }
    //#endregion
    //#region administration
    /**
     * Fetches version information from the ArangoDB server.
     *
     * @param details - If set to `true`, additional information about the
     * ArangoDB server will be available as the `details` property.
     *
     * @example
     * ```js
     * const db = new Database();
     * const version = await db.version();
     * // the version object contains the ArangoDB version information.
     * // license: "community" or "enterprise"
     * // version: ArangoDB version number
     * // server: description of the server
     * ```
     */
    version(details) {
        return this.request({
            method: "GET",
            pathname: "/_api/version",
            search: { details },
        });
    }
    /**
     * Fetches storage engine information from the ArangoDB server.
     *
     * @example
     * ```js
     * const db = new Database();
     * const engine = await db.engine();
     * // the engine object contains the storage engine information, e.g.
     * // name: name of the storage engine
     * ```
     */
    engine() {
        return this.request({
            method: "GET",
            pathname: "/_api/engine",
        });
    }
    /**
     * Fetches detailed storage engine performance and resource usage information
     * from the ArangoDB server.
     *
     * @example
     * ```js
     * const db = new Database();
     * const stats = await db.engineStats();
     * // the stats object contains the storage engine stats
     * ```
     */
    engineStats() {
        return this.request({
            method: "GET",
            pathname: "/_api/engine/stats",
        });
    }
    /**
     * Retrives the server's current system time in milliseconds with microsecond
     * precision.
     */
    time() {
        return this.request({
            method: "GET",
            pathname: "/_admin/time",
        }, (res) => res.parsedBody.time * 1000);
    }
    /**
     * Fetches information about the server status.
     *
     * @example
     * ```js
     * const status = await db.status();
     * // the status object contains the ArangoDB status information, e.g.
     * // version: ArangoDB version number
     * // host: host identifier of the server
     * // serverInfo: detailed information about the server
     * ```
     */
    status() {
        return this.request({
            method: "GET",
            pathname: "/_admin/status",
        });
    }
    /**
     * Fetches availability information about the server.
     *
     * @param graceful - If set to `true`, the method will always return `false`
     * instead of throwing an error; otherwise `false` will only be returned
     * when the server responds with a 503 status code or an ArangoDB error with
     * a code of 503, such as during shutdown.
     *
     * @example
     * ```js
     * const availability = await db.availability();
     * // availability is either "default", "readonly", or false
     * ```
     */
    async availability(graceful = false) {
        try {
            return this.request({
                method: "GET",
                pathname: "/_admin/server/availability",
            }, (res) => res.parsedBody.mode);
        }
        catch (e) {
            if (graceful)
                return false;
            if ((errors.isArangoError(e) || e instanceof errors.HttpError) &&
                e.code === 503) {
                return false;
            }
            throw e;
        }
    }
    /**
     * Fetches deployment information about the server for support purposes.
     *
     * Note that this API may reveal sensitive data about the deployment.
     */
    supportInfo() {
        return this.request({
            method: "GET",
            pathname: "/_admin/support-info",
        });
    }
    /**
     * Fetches the license information and status of an Enterprise Edition server.
     */
    getLicense() {
        return this.request({
            method: "GET",
            pathname: "/_admin/license",
        });
    }
    /**
     * Set a new license for an Enterprise Edition server.
     *
     * @param license - The license as a base 64 encoded string.
     * @param force - If set to `true`, the license will be changed even if it
     * expires sooner than the current license.
     */
    setLicense(license, force = false) {
        return this.request({
            method: "PUT",
            pathname: "/_admin/license",
            body: license,
            search: { force },
        }, () => undefined);
    }
    /**
     * Compacts all databases on the server.
     *
     * @param options - Options for compacting the databases.
     */
    compact(options = {}) {
        return this.request({
            method: "PUT",
            pathname: "/_admin/compact",
            body: options,
        }, () => undefined);
    }
    /**
     * Attempts to initiate a clean shutdown of the server.
     */
    shutdown() {
        return this.request({
            method: "DELETE",
            pathname: "/_admin/shutdown",
        }, () => undefined);
    }
    //#endregion
    //#region rebalancing
    /**
     * Computes the current cluster imbalance.
     *
     * @example
     * ```js
     * const db = new Database();
     * const imbalance = await db.getClusterImbalance();
     * ```
     */
    getClusterImbalance() {
        return this.request({ pathname: "/_admin/cluster/rebalance" }, (res) => res.parsedBody.result);
    }
    /**
     * Computes a set of move shard operations to rebalance the cluster.
     *
     * @example
     * ```js
     * const db = new Database();
     * const result = await db.computerClusterRebalance({
     *   moveLeaders: true,
     *   moveFollowers: true
     * });
     * if (result.moves.length) {
     *   await db.executeClusterRebalance(result.moves);
     * }
     * ```
     */
    computeClusterRebalance(options) {
        return this.request({
            method: "POST",
            pathname: "/_admin/cluster/rebalance",
            body: {
                version: 1,
                ...options,
            },
        }, (res) => res.parsedBody.result);
    }
    /**
     * Executes the given cluster move shard operations.
     *
     * @example
     * ```js
     * const db = new Database();
     * const result = await db.computerClusterRebalance({
     *   moveLeaders: true,
     *   moveFollowers: true
     * });
     * if (result.moves.length) {
     *   await db.executeClusterRebalance(result.moves);
     * }
     * ```
     */
    executeClusterRebalance(moves) {
        return this.request({
            method: "POST",
            pathname: "/_admin/cluster/rebalance/execute",
            body: {
                version: 1,
                moves,
            },
        });
    }
    /**
     * Computes a set of move shard operations to rebalance the cluster and
     * executes them.
     *
     * @param options - Options for rebalancing the cluster.
     *
     * @example
     * ```js
     * const db = new Database();
     * const result = await db.rebalanceCluster({
     *   moveLeaders: true,
     *   moveFollowers: true
     * });
     * // The cluster is now rebalanced.
     * ```
     */
    rebalanceCluster(options) {
        return this.request({
            method: "PUT",
            pathname: "/_admin/cluster/rebalance",
            body: {
                version: 1,
                ...options,
            },
        });
    }
    //#endregion
    //#region databases
    /**
     * Creates a new `Database` instance for the given `databaseName` that
     * shares this database's connection pool.
     *
     * See also {@link Database:constructor}.
     *
     * @param databaseName - Name of the database.
     *
     * @example
     * ```js
     * const systemDb = new Database();
     * const myDb = systemDb.database("my_database");
     * ```
     */
    database(databaseName) {
        return new Database(this, databaseName);
    }
    /**
     * Fetches the database description for the active database from the server.
     *
     * @example
     * ```js
     * const db = new Database();
     * const info = await db.get();
     * // the database exists
     * ```
     */
    get() {
        return this.request({ pathname: "/_api/database/current" }, (res) => res.parsedBody.result);
    }
    /**
     * Checks whether the database exists.
     *
     * @example
     * ```js
     * const db = new Database();
     * const result = await db.exists();
     * // result indicates whether the database exists
     * ```
     */
    async exists() {
        try {
            await this.get();
            return true;
        }
        catch (err) {
            if (errors.isArangoError(err) && err.errorNum === codes_js_1.DATABASE_NOT_FOUND) {
                return false;
            }
            throw err;
        }
    }
    createDatabase(databaseName, usersOrOptions = {}) {
        const { users, ...options } = Array.isArray(usersOrOptions)
            ? { users: usersOrOptions }
            : usersOrOptions;
        return this.request({
            method: "POST",
            pathname: "/_api/database",
            body: { name: databaseName, users, options },
        }, () => this.database(databaseName));
    }
    /**
     * Fetches all databases from the server and returns an array of their names.
     *
     * See also {@link Database#databases} and
     * {@link Database#listUserDatabases}.
     *
     * @example
     * ```js
     * const db = new Database();
     * const names = await db.listDatabases();
     * // databases is an array of database names
     * ```
     */
    listDatabases() {
        return this.request({ pathname: "/_api/database" }, (res) => res.parsedBody.result);
    }
    /**
     * Fetches all databases accessible to the active user from the server and
     * returns an array of their names.
     *
     * See also {@link Database#userDatabases} and
     * {@link Database#listDatabases}.
     *
     * @example
     * ```js
     * const db = new Database();
     * const names = await db.listUserDatabases();
     * // databases is an array of database names
     * ```
     */
    listUserDatabases() {
        return this.request({ pathname: "/_api/database/user" }, (res) => res.parsedBody.result);
    }
    /**
     * Fetches all databases from the server and returns an array of `Database`
     * instances for those databases.
     *
     * See also {@link Database#listDatabases} and
     * {@link Database#userDatabases}.
     *
     * @example
     * ```js
     * const db = new Database();
     * const names = await db.databases();
     * // databases is an array of databases
     * ```
     */
    databases() {
        return this.request({ pathname: "/_api/database" }, (res) => res.parsedBody.result.map((databaseName) => this.database(databaseName)));
    }
    /**
     * Fetches all databases accessible to the active user from the server and
     * returns an array of `Database` instances for those databases.
     *
     * See also {@link Database#listUserDatabases} and
     * {@link Database#databases}.
     *
     * @example
     * ```js
     * const db = new Database();
     * const names = await db.userDatabases();
     * // databases is an array of databases
     * ```
     */
    userDatabases() {
        return this.request({ pathname: "/_api/database/user" }, (res) => res.parsedBody.result.map((databaseName) => this.database(databaseName)));
    }
    /**
     * Deletes the database with the given `databaseName` from the server.
     *
     * @param databaseName - Name of the database to delete.
     *
     * @example
     * ```js
     * const db = new Database();
     * await db.dropDatabase("mydb");
     * // database "mydb" no longer exists
     * ```
     */
    dropDatabase(databaseName) {
        return this.request({
            method: "DELETE",
            pathname: `/_api/database/${encodeURIComponent(databaseName)}`,
        }, (res) => res.parsedBody.result);
    }
    //#endregion
    //#region collections
    /**
     * Returns a `Collection` instance for the given collection name.
     *
     * In TypeScript the collection implements both the
     * {@link collections.DocumentCollection} and {@link collections.EdgeCollection}
     * interfaces and can be cast to either type to enforce a stricter API.
     *
     * @param EntryResultType - Type to represent document contents returned by
     * the server (including computed properties).
     * @param EntryInputType - Type to represent document contents passed when
     * inserting or replacing documents (without computed properties).
     * @param collectionName - Name of the edge collection.
     *
     * @example
     * ```js
     * const db = new Database();
     * const collection = db.collection("potatoes");
     * ```
     *
     * @example
     * ```ts
     * interface Person {
     *   name: string;
     * }
     * const db = new Database();
     * const persons = db.collection<Person>("persons");
     * ```
     *
     * @example
     * ```ts
     * interface Person {
     *   name: string;
     * }
     * interface Friend {
     *   startDate: number;
     *   endDate?: number;
     * }
     * const db = new Database();
     * const documents = db.collection("persons") as DocumentCollection<Person>;
     * const edges = db.collection("friends") as EdgeCollection<Friend>;
     * ```
     */
    collection(collectionName) {
        collectionName = collectionName;
        if (!this._collections.has(collectionName)) {
            this._collections.set(collectionName, new collections.Collection(this, collectionName));
        }
        return this._collections.get(collectionName);
    }
    async createCollection(collectionName, options) {
        const collection = this.collection(collectionName);
        await collection.create(options);
        return collection;
    }
    /**
     * Creates a new edge collection with the given `collectionName` and
     * `options`, then returns an {@link collections.EdgeCollection} instance for the new
     * edge collection.
     *
     * This is a convenience method for calling {@link Database#createCollection}
     * with `options.type` set to `EDGE_COLLECTION`.
     *
     * @param EntryResultType - Type to represent edge document contents returned
     * by the server (including computed properties).
     * @param EntryInputType - Type to represent edge document contents passed
     * when inserting or replacing documents (without computed properties).
     * @param collectionName - Name of the new collection.
     * @param options - Options for creating the collection.
     *
     * @example
     * ```js
     * const db = new Database();
     * const edges = db.createEdgeCollection("friends");
     * ```
     *
     * @example
     * ```ts
     * interface Friend {
     *   startDate: number;
     *   endDate?: number;
     * }
     * const db = new Database();
     * const edges = db.createEdgeCollection<Friend>("friends");
     * ```
     */
    async createEdgeCollection(collectionName, options) {
        return this.createCollection(collectionName, {
            ...options,
            type: collections.CollectionType.EDGE_COLLECTION,
        });
    }
    /**
     * Renames the collection `collectionName` to `newName`.
     *
     * Additionally removes any stored `Collection` instance for
     * `collectionName` from the `Database` instance's internal cache.
     *
     * **Note**: Renaming collections may not be supported when ArangoDB is
     * running in a cluster configuration.
     *
     * @param collectionName - Current name of the collection.
     * @param newName - The new name of the collection.
     */
    async renameCollection(collectionName, newName) {
        const result = await this.request({
            method: "PUT",
            pathname: `/_api/collection/${encodeURIComponent(collectionName)}/rename`,
            body: { name: newName },
        });
        this._collections.delete(collectionName);
        return result;
    }
    /**
     * Fetches all collections from the database and returns an array of
     * collection descriptions.
     *
     * See also {@link Database#collections}.
     *
     * @param excludeSystem - Whether system collections should be excluded.
     *
     * @example
     * ```js
     * const db = new Database();
     * const collections = await db.listCollections();
     * // collections is an array of collection descriptions
     * // not including system collections
     * ```
     *
     * @example
     * ```js
     * const db = new Database();
     * const collections = await db.listCollections(false);
     * // collections is an array of collection descriptions
     * // including system collections
     * ```
     */
    listCollections(excludeSystem = true) {
        return this.request({
            pathname: "/_api/collection",
            search: { excludeSystem },
        }, (res) => res.parsedBody.result);
    }
    /**
     * Fetches all collections from the database and returns an array of
     * `Collection` instances.
     *
     * In TypeScript these instances implement both the
     * {@link collections.DocumentCollection} and {@link collections.EdgeCollection}
     * interfaces and can be cast to either type to enforce a stricter API.
     *
     * See also {@link Database#listCollections}.
     *
     * @param excludeSystem - Whether system collections should be excluded.
     *
     * @example
     * ```js
     * const db = new Database();
     * const collections = await db.collections();
     * // collections is an array of DocumentCollection and EdgeCollection
     * // instances not including system collections
     * ```
     *
     * @example
     * ```js
     * const db = new Database();
     * const collections = await db.collections(false);
     * // collections is an array of DocumentCollection and EdgeCollection
     * // instances including system collections
     * ```
     */
    async collections(excludeSystem = true) {
        const collections = await this.listCollections(excludeSystem);
        return collections.map((data) => this.collection(data.name));
    }
    //#endregion
    //#region graphs
    /**
     * Returns a {@link graphs.Graph} instance representing the graph with the given
     * `graphName`.
     *
     * @param graphName - Name of the graph.
     *
     * @example
     * ```js
     * const db = new Database();
     * const graph = db.graph("some-graph");
     * ```
     */
    graph(graphName) {
        if (!this._graphs.has(graphName)) {
            this._graphs.set(graphName, new graphs.Graph(this, graphName));
        }
        return this._graphs.get(graphName);
    }
    /**
     * Creates a graph with the given `graphName` and `edgeDefinitions`, then
     * returns a {@link graphs.Graph} instance for the new graph.
     *
     * @param graphName - Name of the graph to be created.
     * @param edgeDefinitions - An array of edge definitions.
     * @param options - An object defining the properties of the graph.
     */
    async createGraph(graphName, edgeDefinitions, options) {
        const graph = this.graph(graphName);
        await graph.create(edgeDefinitions, options);
        return graph;
    }
    /**
     * Fetches all graphs from the database and returns an array of graph
     * descriptions.
     *
     * See also {@link Database#graphs}.
     *
     * @example
     * ```js
     * const db = new Database();
     * const graphs = await db.listGraphs();
     * // graphs is an array of graph descriptions
     * ```
     */
    listGraphs() {
        return this.request({ pathname: "/_api/gharial" }, (res) => res.parsedBody.graphs);
    }
    /**
     * Fetches all graphs from the database and returns an array of {@link graphs.Graph}
     * instances for those graphs.
     *
     * See also {@link Database#listGraphs}.
     *
     * @example
     * ```js
     * const db = new Database();
     * const graphs = await db.graphs();
     * // graphs is an array of Graph instances
     * ```
     */
    async graphs() {
        const graphs = await this.listGraphs();
        return graphs.map((data) => this.graph(data._key));
    }
    //#endregion
    //#region views
    /**
     * Returns a {@link views.View} instance for the given `viewName`.
     *
     * @param viewName - Name of the ArangoSearch or SearchAlias View.
     *
     * @example
     * ```js
     * const db = new Database();
     * const view = db.view("potatoes");
     * ```
     */
    view(viewName) {
        if (!this._views.has(viewName)) {
            this._views.set(viewName, new views.View(this, viewName));
        }
        return this._views.get(viewName);
    }
    /**
     * Creates a new View with the given `viewName` and `options`, then returns a
     * {@link views.View} instance for the new View.
     *
     * @param viewName - Name of the View.
     * @param options - An object defining the properties of the View.
     *
     * @example
     * ```js
     * const db = new Database();
     * const view = await db.createView("potatoes", { type: "arangosearch" });
     * // the ArangoSearch View "potatoes" now exists
     * ```
     */
    async createView(viewName, options) {
        const view = this.view(viewName);
        await view.create(options);
        return view;
    }
    /**
     * Renames the view `viewName` to `newName`.
     *
     * Additionally removes any stored {@link views.View} instance for `viewName` from
     * the `Database` instance's internal cache.
     *
     * **Note**: Renaming views may not be supported when ArangoDB is running in
     * a cluster configuration.
     *
     * @param viewName - Current name of the view.
     * @param newName - The new name of the view.
     */
    async renameView(viewName, newName) {
        const result = await this.request({
            method: "PUT",
            pathname: `/_api/view/${encodeURIComponent(viewName)}/rename`,
            body: { name: newName },
        });
        this._views.delete(viewName);
        return result;
    }
    /**
     * Fetches all Views from the database and returns an array of View
     * descriptions.
     *
     * See also {@link Database#views}.
     *
     * @example
     * ```js
     * const db = new Database();
     *
     * const views = await db.listViews();
     * // views is an array of View descriptions
     * ```
     */
    listViews() {
        return this.request({ pathname: "/_api/view" }, (res) => res.parsedBody.result);
    }
    /**
     * Fetches all Views from the database and returns an array of
     * {@link views.View} instances
     * for the Views.
     *
     * See also {@link Database#listViews}.
     *
     * @example
     * ```js
     * const db = new Database();
     * const views = await db.views();
     * // views is an array of ArangoSearch View instances
     * ```
     */
    async views() {
        const views = await this.listViews();
        return views.map((data) => this.view(data.name));
    }
    //#endregion
    //#region analyzers
    /**
     * Returns an {@link analyzers.Analyzer} instance representing the Analyzer with the
     * given `analyzerName`.
     *
     * @example
     * ```js
     * const db = new Database();
     * const analyzer = db.analyzer("some-analyzer");
     * const info = await analyzer.get();
     * ```
     */
    analyzer(analyzerName) {
        if (!this._analyzers.has(analyzerName)) {
            this._analyzers.set(analyzerName, new analyzers.Analyzer(this, analyzerName));
        }
        return this._analyzers.get(analyzerName);
    }
    /**
     * Creates a new Analyzer with the given `analyzerName` and `options`, then
     * returns an {@link analyzers.Analyzer} instance for the new Analyzer.
     *
     * @param analyzerName - Name of the Analyzer.
     * @param options - An object defining the properties of the Analyzer.
     *
     * @example
     * ```js
     * const db = new Database();
     * const analyzer = await db.createAnalyzer("potatoes", { type: "identity" });
     * // the identity Analyzer "potatoes" now exists
     * ```
     */
    async createAnalyzer(analyzerName, options) {
        const analyzer = this.analyzer(analyzerName);
        await analyzer.create(options);
        return analyzer;
    }
    /**
     * Fetches all Analyzers visible in the database and returns an array of
     * Analyzer descriptions.
     *
     * See also {@link Database#analyzers}.
     *
     * @example
     * ```js
     * const db = new Database();
     * const analyzers = await db.listAnalyzers();
     * // analyzers is an array of Analyzer descriptions
     * ```
     */
    listAnalyzers() {
        return this.request({ pathname: "/_api/analyzer" }, (res) => res.parsedBody.result);
    }
    /**
     * Fetches all Analyzers visible in the database and returns an array of
     * {@link analyzers.Analyzer} instances for those Analyzers.
     *
     * See also {@link Database#listAnalyzers}.
     *
     * @example
     * ```js
     * const db = new Database();
     * const analyzers = await db.analyzers();
     * // analyzers is an array of Analyzer instances
     * ```
     */
    async analyzers() {
        const analyzers = await this.listAnalyzers();
        return analyzers.map((data) => this.analyzer(data.name));
    }
    //#endregion
    //#region users
    /**
     * Fetches all ArangoDB users visible to the authenticated user and returns
     * an array of user objects.
     *
     * @example
     * ```js
     * const db = new Database();
     * const users = await db.listUsers();
     * // users is an array of user objects
     * ```
     */
    listUsers() {
        return this.request({
            pathname: "/_api/user",
        }, (res) => res.parsedBody.result);
    }
    /**
     * Fetches the user data of a single ArangoDB user.
     *
     * @param username - Name of the ArangoDB user to fetch.
     *
     * @example
     * ```js
     * const db = new Database();
     * const user = await db.getUser("steve");
     * // user is the user object for the user named "steve"
     * ```
     */
    getUser(username) {
        return this.request({
            pathname: `/_api/user/${encodeURIComponent(username)}`,
        });
    }
    createUser(username, options) {
        if (typeof options === "string") {
            options = { passwd: options };
        }
        return this.request({
            method: "POST",
            pathname: "/_api/user",
            body: { user: username, ...options },
        }, (res) => res.parsedBody);
    }
    updateUser(username, options) {
        if (typeof options === "string") {
            options = { passwd: options };
        }
        return this.request({
            method: "PATCH",
            pathname: `/_api/user/${encodeURIComponent(username)}`,
            body: options,
        }, (res) => res.parsedBody);
    }
    /**
     * Replaces the ArangoDB user's option with the new options.
     *
     * @param username - Name of the ArangoDB user to modify.
     * @param options - New options to replace the user's existing options.
     *
     * @example
     * ```js
     * const db = new Database();
     * const user = await db.replaceUser("steve", { passwd: "", active: false });
     * // The user "steve" has been set to inactive with an empty password
     * ```
     */
    replaceUser(username, options) {
        if (typeof options === "string") {
            options = { passwd: options };
        }
        return this.request({
            method: "PUT",
            pathname: `/_api/user/${encodeURIComponent(username)}`,
            body: options,
        }, (res) => res.parsedBody);
    }
    /**
     * Removes the ArangoDB user with the given username from the server.
     *
     * @param username - Name of the ArangoDB user to remove.
     *
     * @example
     * ```js
     * const db = new Database();
     * await db.removeUser("steve");
     * // The user "steve" has been removed
     * ```
     */
    removeUser(username) {
        return this.request({
            method: "DELETE",
            pathname: `/_api/user/${encodeURIComponent(username)}`,
        }, () => undefined);
    }
    /**
     * Fetches the given ArangoDB user's access level for the database, or the
     * given collection in the given database.
     *
     * @param username - Name of the ArangoDB user to fetch the access level for.
     * @param options - Collection and/or database to fetch the access level for.
     *
     * @example
     * ```js
     * const db = new Database();
     * const accessLevel = await db.getUserAccessLevel("steve");
     * // The access level of the user "steve" has been fetched for the current
     * // database.
     * ```
     *
     * @example
     * ```js
     * const db = new Database();
     * const accessLevel = await db.getUserAccessLevel("steve", {
     *   database: "staging"
     * });
     * // The access level of the user "steve" has been fetched for the "staging"
     * // database.
     * ```
     *
     * @example
     * ```js
     * const db = new Database();
     * const accessLevel = await db.getUserAccessLevel("steve", {
     *   collection: "pokemons"
     * });
     * // The access level of the user "steve" has been fetched for the
     * // "pokemons" collection in the current database.
     * ```
     *
     * @example
     * ```js
     * const db = new Database();
     * const accessLevel = await db.getUserAccessLevel("steve", {
     *   database: "staging",
     *   collection: "pokemons"
     * });
     * // The access level of the user "steve" has been fetched for the
     * // "pokemons" collection in the "staging" database.
     * ```
     *
     * @example
     * ```js
     * const db = new Database();
     * const staging = db.database("staging");
     * const accessLevel = await db.getUserAccessLevel("steve", {
     *   database: staging
     * });
     * // The access level of the user "steve" has been fetched for the "staging"
     * // database.
     * ```
     *
     * @example
     * ```js
     * const db = new Database();
     * const staging = db.database("staging");
     * const accessLevel = await db.getUserAccessLevel("steve", {
     *   collection: staging.collection("pokemons")
     * });
     * // The access level of the user "steve" has been fetched for the
     * // "pokemons" collection in database "staging".
     * ```
     */
    getUserAccessLevel(username, options) {
        const { database, collection } = options;
        const databaseName = isArangoDatabase(database)
            ? database.name
            : (database ??
                (collection instanceof collections.Collection
                    ? collection.database.name
                    : this._name));
        const suffix = collection
            ? `/${encodeURIComponent(collections.isArangoCollection(collection)
                ? collection.name
                : collection)}`
            : "";
        return this.request({
            pathname: `/_api/user/${encodeURIComponent(username)}/database/${encodeURIComponent(databaseName)}${suffix}`,
        }, (res) => res.parsedBody.result);
    }
    /**
     * Sets the given ArangoDB user's access level for the database, or the
     * given collection in the given database.
     *
     * @param username - Name of the ArangoDB user to set the access level for.
     * @param options - Database and/or collection to set the access level for.
     * @param grant - Access level to set for the given user.
     *
     * @example
     * ```js
     * const db = new Database();
     * await db.setUserAccessLevel("steve", { grant: "rw" });
     * // The user "steve" now has read-write access to the current database.
     * ```
     *
     * @example
     * ```js
     * const db = new Database();
     * await db.setUserAccessLevel("steve", {
     *   database: "staging",
     *   grant: "rw"
     * });
     * // The user "steve" now has read-write access to the "staging" database.
     * ```
     *
     * @example
     * ```js
     * const db = new Database();
     * await db.setUserAccessLevel("steve", {
     *   collection: "pokemons",
     *   grant: "rw"
     * });
     * // The user "steve" now has read-write access to the "pokemons" collection
     * // in the current database.
     * ```
     *
     * @example
     * ```js
     * const db = new Database();
     * await db.setUserAccessLevel("steve", {
     *   database: "staging",
     *   collection: "pokemons",
     *   grant: "rw"
     * });
     * // The user "steve" now has read-write access to the "pokemons" collection
     * // in the "staging" database.
     * ```
     *
     * @example
     * ```js
     * const db = new Database();
     * const staging = db.database("staging");
     * await db.setUserAccessLevel("steve", {
     *   database: staging,
     *   grant: "rw"
     * });
     * // The user "steve" now has read-write access to the "staging" database.
     * ```
     *
     * @example
     * ```js
     * const db = new Database();
     * const staging = db.database("staging");
     * await db.setUserAccessLevel("steve", {
     *   collection: staging.collection("pokemons"),
     *   grant: "rw"
     * });
     * // The user "steve" now has read-write access to the "pokemons" collection
     * // in database "staging".
     * ```
     */
    setUserAccessLevel(username, options, grant) {
        const { database, collection } = options;
        const databaseName = isArangoDatabase(database)
            ? database.name
            : (database ??
                (collection instanceof collections.Collection
                    ? collection.database.name
                    : this._name));
        const suffix = collection
            ? `/${encodeURIComponent(collections.isArangoCollection(collection)
                ? collection.name
                : collection)}`
            : "";
        return this.request({
            method: "PUT",
            pathname: `/_api/user/${encodeURIComponent(username)}/database/${encodeURIComponent(databaseName)}${suffix}`,
            body: { grant },
        }, (res) => res.parsedBody);
    }
    /**
     * Clears the given ArangoDB user's access level for the database, or the
     * given collection in the given database.
     *
     * @param username - Name of the ArangoDB user to clear the access level for.
     * @param options - Database and/or collection to clear the access level for.
     *
     * @example
     * ```js
     * const db = new Database();
     * await db.clearUserAccessLevel("steve");
     * // The access level of the user "steve" has been cleared for the current
     * // database.
     * ```
     *
     * @example
     * ```js
     * const db = new Database();
     * await db.clearUserAccessLevel("steve", { database: "staging" });
     * // The access level of the user "steve" has been cleared for the "staging"
     * // database.
     * ```
     *
     * @example
     * ```js
     * const db = new Database();
     * await db.clearUserAccessLevel("steve", { collection: "pokemons" });
     * // The access level of the user "steve" has been cleared for the
     * // "pokemons" collection in the current database.
     * ```
     *
     * @example
     * ```js
     * const db = new Database();
     * await db.clearUserAccessLevel("steve", {
     *   database: "staging",
     *   collection: "pokemons"
     * });
     * // The access level of the user "steve" has been cleared for the
     * // "pokemons" collection in the "staging" database.
     * ```
     *
     * @example
     * ```js
     * const db = new Database();
     * const staging = db.database("staging");
     * await db.clearUserAccessLevel("steve", { database: staging });
     * // The access level of the user "steve" has been cleared for the "staging"
     * // database.
     * ```
     *
     * @example
     * ```js
     * const db = new Database();
     * const staging = db.database("staging");
     * await db.clearUserAccessLevel("steve", {
     *   collection: staging.collection("pokemons")
     * });
     * // The access level of the user "steve" has been cleared for the
     * // "pokemons" collection in database "staging".
     * ```
     */
    clearUserAccessLevel(username, options) {
        const { database, collection } = options;
        const databaseName = isArangoDatabase(database)
            ? database.name
            : (database ??
                (collection instanceof collections.Collection
                    ? collection.database.name
                    : this._name));
        const suffix = collection
            ? `/${encodeURIComponent(collections.isArangoCollection(collection)
                ? collection.name
                : collection)}`
            : "";
        return this.request({
            method: "DELETE",
            pathname: `/_api/user/${encodeURIComponent(username)}/database/${encodeURIComponent(databaseName)}${suffix}`,
        }, (res) => res.parsedBody);
    }
    getUserDatabases(username, full) {
        return this.request({
            pathname: `/_api/user/${encodeURIComponent(username)}/database`,
            search: { full },
        }, (res) => res.parsedBody.result);
    }
    /**
     * Creates a new access token for the given ArangoDB user.
     *
     * Access tokens can be used as password replacements for authentication.
     * The token value is only returned once in this response and cannot be
     * retrieved again. Store it securely.
     *
     * @param username - Name of the ArangoDB user to create the token for.
     * @param options - Options for creating the access token.
     *
     * @example
     * ```js
     * const db = new Database();
     * // Convert Date to Unix timestamp (seconds)
     * const expiryDate = new Date("2025-12-31");
     * const expiryTimestamp = Math.floor(expiryDate.getTime() / 1000);
     * const token = await db.createAccessToken("appUser", {
     *   name: "CI token",
     *   valid_until: expiryTimestamp
     * });
     * console.log(token.token); // Store this securely!
     * ```
     *
     * @example
     * ```js
     * const db = new Database();
     * const token = await db.createAccessToken("appUser", {
     *   name: "Production token",
     *   valid_until: Math.floor(Date.now() / 1000) + (30 * 24 * 60 * 60) // 30 days
     * });
     * ```
     */
    createAccessToken(username, options) {
        if (!username || typeof username !== "string") {
            throw new Error("Username must be a non-empty string");
        }
        if (!options || typeof options !== "object") {
            throw new Error("Options must be an object");
        }
        if (!options.name || typeof options.name !== "string") {
            throw new Error("Token name must be a non-empty string");
        }
        const body = {
            name: options.name,
        };
        if (options.valid_until !== undefined) {
            if (typeof options.valid_until !== "number") {
                throw new Error("valid_until must be a Unix timestamp (number in seconds)");
            }
            body.valid_until = options.valid_until;
        }
        return this.request({
            method: "POST",
            pathname: `/_api/token/${encodeURIComponent(username)}`,
            body,
        }, (res) => res.parsedBody);
    }
    /**
     * Fetches all access tokens for the given ArangoDB user.
     *
     * Note: Token values are not returned. Only metadata (id, name, expiry, etc.)
     * is available. Token values can only be retrieved when creating a new token.
     *
     * @param username - Name of the ArangoDB user to fetch tokens for.
     *
     * @example
     * ```js
     * const db = new Database();
     * const tokens = await db.getAccessTokens("appUser");
     * for (const token of tokens) {
     *   console.log(`${token.name}: expires ${new Date(token.valid_until * 1000)}`);
     * }
     * ```
     */
    getAccessTokens(username) {
        if (!username || typeof username !== "string") {
            throw new Error("Username must be a non-empty string");
        }
        return this.request({
            pathname: `/_api/token/${encodeURIComponent(username)}`,
        }, (res) => res.parsedBody.tokens);
    }
    /**
     * Deletes (revokes) an access token for the given ArangoDB user.
     *
     * Once deleted, the token cannot be used for authentication and cannot be recovered.
     *
     * @param username - Name of the ArangoDB user who owns the token.
     * @param tokenId - Unique identifier of the token to delete.
     *
     * @example
     * ```js
     * const db = new Database();
     * const tokens = await db.getAccessTokens("appUser");
     * for (const token of tokens) {
     *   if (token.name === "Old CI token") {
     *     await db.deleteAccessToken("appUser", token.id);
     *   }
     * }
     * ```
     */
    deleteAccessToken(username, tokenId) {
        if (!username || typeof username !== "string") {
            throw new Error("Username must be a non-empty string");
        }
        if (typeof tokenId !== "number" || !Number.isInteger(tokenId) || tokenId < 0) {
            throw new Error("Token ID must be a non-negative integer");
        }
        return this.request({
            method: "DELETE",
            pathname: `/_api/token/${encodeURIComponent(username)}/${tokenId}`,
        }, () => undefined);
    }
    executeTransaction(collections, action, options = {}) {
        const { allowDirtyRead = undefined, ...opts } = options;
        return this.request({
            method: "POST",
            pathname: "/_api/transaction",
            allowDirtyRead,
            body: {
                collections: transactions.coerceTransactionCollections(collections),
                action,
                ...opts,
            },
        }, (res) => res.parsedBody.result);
    }
    /**
     * Returns a {@link transactions.Transaction} instance for an existing streaming
     * transaction with the given `id`.
     *
     * See also {@link Database#beginTransaction}.
     *
     * @param transactionId - The `id` of an existing stream transaction.
     *
     * @example
     * ```js
     * const trx1 = await db.beginTransaction(collections);
     * const id = trx1.id;
     * // later
     * const trx2 = db.transaction(id);
     * await trx2.commit();
     * ```
     */
    transaction(transactionId) {
        return new transactions.Transaction(this, transactionId);
    }
    beginTransaction(collections, options = {}) {
        const { allowDirtyRead = undefined, ...opts } = options;
        return this.request({
            method: "POST",
            pathname: "/_api/transaction/begin",
            allowDirtyRead,
            body: {
                collections: transactions.coerceTransactionCollections(collections),
                ...opts,
            },
        }, (res) => new transactions.Transaction(this, res.parsedBody.result.id));
    }
    async withTransaction(collections, callback, options = {}) {
        const trx = await this.beginTransaction(collections, options);
        try {
            const result = await callback((fn) => trx.step(fn));
            await trx.commit();
            return result;
        }
        catch (e) {
            try {
                await trx.abort();
            }
            catch { }
            throw e;
        }
    }
    /**
     * Fetches all active transactions from the database and returns an array of
     * transaction descriptions.
     *
     * See also {@link Database#transactions}.
     *
     * @example
     * ```js
     * const db = new Database();
     * const transactions = await db.listTransactions();
     * // transactions is an array of transaction descriptions
     * ```
     */
    listTransactions() {
        return this._connection.request({ pathname: "/_api/transaction" }, (res) => res.parsedBody.transactions);
    }
    /**
     * Fetches all active transactions from the database and returns an array of
     * {@link transactions.Transaction} instances for those transactions.
     *
     * See also {@link Database#listTransactions}.
     *
     * @example
     * ```js
     * const db = new Database();
     * const transactions = await db.transactions();
     * // transactions is an array of transactions
     * ```
     */
    async transactions() {
        const transactions = await this.listTransactions();
        return transactions.map((data) => this.transaction(data.id));
    }
    query(query, bindVars, options = {}) {
        if (aql.isAqlQuery(query)) {
            options = bindVars ?? {};
            bindVars = query.bindVars;
            query = query.query;
        }
        else if (aql.isAqlLiteral(query)) {
            query = query.toAQL();
        }
        const { allowDirtyRead, retryOnConflict, count, batchSize, cache, memoryLimit, ttl, timeout, ...opts } = options;
        // Accept legacy maxPlans and new maxNumberOfPlans; always send maxNumberOfPlans
        const { maxPlans, maxNumberOfPlans, ...remainingOpts } = opts;
        const normalizedOptions = {
            ...remainingOpts,
            ...(maxNumberOfPlans !== undefined
                ? { maxNumberOfPlans }
                : maxPlans !== undefined
                    ? { maxNumberOfPlans: maxPlans }
                    : {}),
        };
        return this.request({
            method: "POST",
            pathname: "/_api/cursor",
            body: {
                query,
                bindVars,
                count,
                batchSize,
                cache,
                memoryLimit,
                ttl,
                options: normalizedOptions,
            },
            allowDirtyRead,
            retryOnConflict,
            timeout,
        }, (res) => new cursors.BatchCursor(this, res.parsedBody, res.arangojsHostUrl, allowDirtyRead).items);
    }
    explain(query, bindVars, options) {
        if (aql.isAqlQuery(query)) {
            options = bindVars;
            bindVars = query.bindVars;
            query = query.query;
        }
        else if (aql.isAqlLiteral(query)) {
            query = query.toAQL();
        }
        return this.request({
            method: "POST",
            pathname: "/_api/explain",
            body: { query, bindVars, options },
        });
    }
    /**
     * Parses the given query and returns the result.
     *
     * See the {@link aql.aql} template string handler for information about how
     * to create a query string without manually defining bind parameters nor
     * having to worry about escaping variables.
     *
     * @param query - An AQL query string or an object containing an AQL query
     * string and bind parameters, e.g. the object returned from an {@link aql.aql}
     * template string.
     *
     * @example
     * ```js
     * const db = new Database();
     * const collection = db.collection("some-collection");
     * const ast = await db.parse(aql`
     *   FOR doc IN ${collection}
     *   FILTER doc.flavor == "strawberry"
     *   RETURN doc._key
     * `);
     * ```
     aql.*/
    parse(query) {
        if (aql.isAqlQuery(query)) {
            query = query.query;
        }
        else if (aql.isAqlLiteral(query)) {
            query = query.toAQL();
        }
        return this.request({
            method: "POST",
            pathname: "/_api/query",
            body: { query },
        });
    }
    /**
     * Fetches the available optimizer rules.
     *
     * @example
     * ```js
     * const db = new Database();
     * const rules = await db.queryRules();
     * for (const rule of rules) {
     *   console.log(rule.name);
     * }
     * ```
     */
    queryRules() {
        return this.request({
            pathname: "/_api/query/rules",
        });
    }
    queryTracking(options) {
        return this.request(options
            ? {
                method: "PUT",
                pathname: "/_api/query/properties",
                body: options,
            }
            : {
                method: "GET",
                pathname: "/_api/query/properties",
            });
    }
    /**
     * Fetches a list of information for all currently running queries.
     *
     * See also {@link Database#listSlowQueries} and {@link Database#killQuery}.
     *
     * @example
     * ```js
     * const db = new Database();
     * const queries = await db.listRunningQueries();
     * ```
     */
    listRunningQueries() {
        return this.request({
            method: "GET",
            pathname: "/_api/query/current",
        });
    }
    /**
     * Fetches a list of information for all recent slow queries.
     *
     * See also {@link Database#listRunningQueries} and
     * {@link Database#clearSlowQueries}.
     *
     * @example
     * ```js
     * const db = new Database();
     * const queries = await db.listSlowQueries();
     * // Only works if slow query tracking is enabled
     * ```
     */
    listSlowQueries() {
        return this.request({
            method: "GET",
            pathname: "/_api/query/slow",
        });
    }
    /**
     * Clears the list of recent slow queries.
     *
     * See also {@link Database#listSlowQueries}.
     *
     * @example
     * ```js
     * const db = new Database();
     * await db.clearSlowQueries();
     * // Slow query list is now cleared
     * ```
     */
    clearSlowQueries() {
        return this.request({
            method: "DELETE",
            pathname: "/_api/query/slow",
        }, () => undefined);
    }
    /**
     * Kills a running query with the given `queryId`.
     *
     * See also {@link Database#listRunningQueries}.
     *
     * @param queryId - The ID of a currently running query.
     *
     * @example
     * ```js
     * const db = new Database();
     * const queries = await db.listRunningQueries();
     * await Promise.all(queries.map(
     *   async (query) => {
     *     if (query.state === "executing") {
     *       await db.killQuery(query.id);
     *     }
     *   }
     * ));
     * ```
     */
    killQuery(queryId) {
        return this.request({
            method: "DELETE",
            pathname: `/_api/query/${encodeURIComponent(queryId)}`,
        }, () => undefined);
    }
    /**
     * Fetches a list of all entries in the AQL query results cache of the
     * current database.
     *
     * @example
     * ```js
     * const db = new Database();
     * const entries = await db.listQueryCacheEntries();
     * console.log(entries);
     * ```
     */
    listQueryCacheEntries() {
        return this.request({
            pathname: "/_api/query-cache/entries",
        });
    }
    /**
     * Clears the AQL query results cache of the current database.
     *
     * @example
     * ```js
     * const db = new Database();
     * await db.clearQueryCache();
     * // Cache is now cleared
     * ```
     */
    clearQueryCache() {
        return this.request({
            method: "DELETE",
            pathname: "/_api/query-cache",
        }, () => undefined);
    }
    /**
     * Fetches the global properties for the AQL query results cache.
     *
     * @example
     * ```js
     * const db = new Database();
     * const properties = await db.getQueryCacheProperties();
     * console.log(properties);
     * ```
     */
    getQueryCacheProperties() {
        return this.request({
            pathname: "/_api/query-cache/properties",
        });
    }
    /**
     * Updates the global properties for the AQL query results cache.
     *
     * @param properties - The new properties for the AQL query results cache.
     *
     * @example
     * ```js
     * const db = new Database();
     * await db.setQueryCacheProperties({ maxResults: 9000 });
     * ```
     */
    setQueryCacheProperties(properties) {
        return this.request({
            method: "PUT",
            pathname: "/_api/query-cache/properties",
            body: properties,
        });
    }
    //#endregion
    //#region user functions
    /**
     * @deprecated Removed from ArangoDB 4.0 onwards.
     * Calling this method against ArangoDB v4 will result in a runtime exception.
     *
     * Fetches a list of all AQL user functions registered with the database.
     *
     * @example
     * ```js
     * const db = new Database();
     * const functions = await db.listUserFunctions();
     * const names = functions.map(fn => fn.name);
     * ```
     */
    listUserFunctions() {
        return this.request({ pathname: "/_api/aqlfunction" }, (res) => res.parsedBody.result);
    }
    /**
     * @deprecated Removed from ArangoDB 4.0 onwards.
     * Calling this method against ArangoDB v4 will result in a runtime exception.
     *
     * Creates an AQL user function with the given _name_ and _code_ if it does
     * not already exist or replaces it if a function with the same name already
     * existed.
     *
     * @param name - A valid AQL function name. The function name must consist
     * of at least two alphanumeric identifiers separated with double colons.
     * @param code - A string evaluating to a JavaScript function (not a
     * JavaScript function object).
     * @param isDeterministic - If set to `true`, the function is expected to
     * always return the same result for equivalent inputs. This option currently
     * has no effect but may allow for optimizations in the future.
     *
     * @example
     * ```js
     * const db = new Database();
     * await db.createUserFunction(
     *   "ACME::ACCOUNTING::CALCULATE_VAT",
     *   "(price) => price * 0.19"
     * );
     * // Use the new function in an AQL query with template handler:
     * const cursor = await db.query(aql`
     *   FOR product IN products
     *   RETURN MERGE(
     *     { vat: ACME::ACCOUNTING::CALCULATE_VAT(product.price) },
     *     product
     *   )
     * `);
     * // cursor is a cursor for the query result
     * ```
     */
    createUserFunction(name, code, isDeterministic = false) {
        return this.request({
            method: "POST",
            pathname: "/_api/aqlfunction",
            body: { name, code, isDeterministic },
        });
    }
    /**
     * @deprecated Removed from ArangoDB 4.0 onwards.
     * Calling this method against ArangoDB v4 will result in a runtime exception.
     *
     * Deletes the AQL user function with the given name from the database.
     *
     * @param name - The name of the user function to drop.
     * @param group - If set to `true`, all functions with a name starting with
     * `name` will be deleted, otherwise only the function with the exact name
     * will be deleted.
     *
     * @example
     * ```js
     * const db = new Database();
     * await db.dropUserFunction("ACME::ACCOUNTING::CALCULATE_VAT");
     * // the function no longer exists
     * ```
     */
    dropUserFunction(name, group = false) {
        return this.request({
            method: "DELETE",
            pathname: `/_api/aqlfunction/${encodeURIComponent(name)}`,
            search: { group },
        });
    }
    //#endregion
    //#region services
    /**
     * @deprecated Removed from ArangoDB 4.0 onwards.
     * Calling this method against ArangoDB v4 will result in a runtime exception.
     *
     * Fetches a list of all installed service.
     *
     * @param excludeSystem - Whether system services should be excluded.
     *
     * @example
     * ```js
     * const db = new Database();
     * const services = await db.listServices();
     * ```
     *
     * @example
     * ```js
     * const db = new Database();
     * const services = await db.listServices(false); // all services
     * ```
     */
    listServices(excludeSystem = true) {
        return this.request({
            pathname: "/_api/foxx",
            search: { excludeSystem },
        });
    }
    /**
     * @deprecated Removed from ArangoDB 4.0 onwards.
     * Calling this method against ArangoDB v4 will result in a runtime exception.
     *
     * Installs a new service.
     *
     * @param mount - The service's mount point, relative to the database.
     * @param source - The service bundle to install.
     * @param options - Options for installing the service.
     *
     * @example
     * ```js
     * const db = new Database();
     * // Using a Buffer in Node.js as source
     * const source = new Blob([await fs.readFileSync("./my-foxx-service.zip")]);
     * const info = await db.installService("/hello", source);
     * ```
     *
     * @example
     * ```js
     * const db = new Database();
     * // Using a Blob in Node.js as source
     * const source = await fs.openAsBlob("./my-foxx-service.zip");
     * const info = await db.installService("/hello", source);
     * ```
     *
     * @example
     * ```js
     * const db = new Database();
     * // Using a File from a browser file input as source
     * const element = document.getElementById("my-file-input");
     * const source = element.files[0];
     * const info = await db.installService("/hello", source);
     * ```
     */
    async installService(mount, source, options = {}) {
        const { configuration, dependencies, ...search } = options;
        const form = new FormData();
        if (configuration) {
            form.append("configuration", JSON.stringify(configuration));
        }
        if (dependencies) {
            form.append("dependencies", JSON.stringify(dependencies));
        }
        form.append("source", typeof source === "string" ? JSON.stringify(source) : source);
        return await this.request({
            body: form,
            method: "POST",
            pathname: "/_api/foxx",
            search: { ...search, mount },
        });
    }
    /**
     * @deprecated Removed from ArangoDB 4.0 onwards.
     * Calling this method against ArangoDB v4 will result in a runtime exception.
     *
     * Replaces an existing service with a new service by completely removing the
     * old service and installing a new service at the same mount point.
     *
     * @param mount - The service's mount point, relative to the database.
     * @param source - The service bundle to install.
     * @param options - Options for replacing the service.
     *
     * @example
     * ```js
     * const db = new Database();
     * // Using a Buffer in Node.js as source
     * const source = new Blob([await fs.readFileSync("./my-foxx-service.zip")]);
     * const info = await db.replaceService("/hello", source);
     * ```
     *
     * @example
     * ```js
     * const db = new Database();
     * // Using a Blob in Node.js as source
     * const source = await fs.openAsBlob("./my-foxx-service.zip");
     * const info = await db.replaceService("/hello", source);
     * ```
     *
     * @example
     * ```js
     * const db = new Database();
     * // Using a File from a browser file input as source
     * const element = document.getElementById("my-file-input");
     * const source = element.files[0];
     * const info = await db.replaceService("/hello", source);
     * ```
     */
    async replaceService(mount, source, options = {}) {
        const { configuration, dependencies, ...search } = options;
        const form = new FormData();
        if (configuration) {
            form.append("configuration", JSON.stringify(configuration));
        }
        if (dependencies) {
            form.append("dependencies", JSON.stringify(dependencies));
        }
        form.append("source", typeof source === "string" ? JSON.stringify(source) : source);
        return await this.request({
            body: form,
            method: "PUT",
            pathname: "/_api/foxx/service",
            search: { ...search, mount },
        });
    }
    /**
     * @deprecated Removed from ArangoDB 4.0 onwards.
     * Calling this method against ArangoDB v4 will result in a runtime exception.
     *
     * Replaces an existing service with a new service while retaining the old
     * service's configuration and dependencies.
     *
     * @param mount - The service's mount point, relative to the database.
     * @param source - The service bundle to install.
     * @param options - Options for upgrading the service.
     *
     * @example
     * ```js
     * const db = new Database();
     * // Using a Buffer in Node.js as source
     * const source = new Blob([await fs.readFileSync("./my-foxx-service.zip")]);
     * const info = await db.upgradeService("/hello", source);
     * ```
     *
     * @example
     * ```js
     * const db = new Database();
     * // Using a Blob in Node.js as source
     * const source = await fs.openAsBlob("./my-foxx-service.zip");
     * const info = await db.upgradeService("/hello", source);
     * ```
     *
     * @example
     * ```js
     * const db = new Database();
     * // Using a File from a browser file input as source
     * const element = document.getElementById("my-file-input");
     * const source = element.files[0];
     * const info = await db.upgradeService("/hello", source);
     * ```
     */
    async upgradeService(mount, source, options = {}) {
        const { configuration, dependencies, ...search } = options;
        const form = new FormData();
        if (configuration) {
            form.append("configuration", JSON.stringify(configuration));
        }
        if (dependencies) {
            form.append("dependencies", JSON.stringify(dependencies));
        }
        form.append("source", typeof source === "string" ? JSON.stringify(source) : source);
        return await this.request({
            body: form,
            method: "PATCH",
            pathname: "/_api/foxx/service",
            search: { ...search, mount },
        });
    }
    /**
     * @deprecated Removed from ArangoDB 4.0 onwards.
     * Calling this method against ArangoDB v4 will result in a runtime exception.
     *
     * Completely removes a service from the database.
     *
     * @param mount - The service's mount point, relative to the database.
     * @param options - Options for uninstalling the service.
     *
     * @example
     * ```js
     * const db = new Database();
     * await db.uninstallService("/my-foxx");
     * ```
     */
    uninstallService(mount, options) {
        return this.request({
            method: "DELETE",
            pathname: "/_api/foxx/service",
            search: { ...options, mount },
        }, () => undefined);
    }
    /**
     * @deprecated Removed from ArangoDB 4.0 onwards.
     * Calling this method against ArangoDB v4 will result in a runtime exception.
     *
     * Retrieves information about a mounted service.
     *
     * @param mount - The service's mount point, relative to the database.
     *
     * @example
     * ```js
     * const db = new Database();
     * const info = await db.getService("/my-service");
     * // info contains detailed information about the service
     * ```
     */
    getService(mount) {
        return this.request({
            pathname: "/_api/foxx/service",
            search: { mount },
        });
    }
    getServiceConfiguration(mount, minimal = false) {
        return this.request({
            pathname: "/_api/foxx/configuration",
            search: { mount, minimal },
        });
    }
    replaceServiceConfiguration(mount, cfg, minimal = false) {
        return this.request({
            method: "PUT",
            pathname: "/_api/foxx/configuration",
            body: cfg,
            search: { mount, minimal },
        });
    }
    updateServiceConfiguration(mount, cfg, minimal = false) {
        return this.request({
            method: "PATCH",
            pathname: "/_api/foxx/configuration",
            body: cfg,
            search: { mount, minimal },
        });
    }
    getServiceDependencies(mount, minimal = false) {
        return this.request({
            pathname: "/_api/foxx/dependencies",
            search: { mount, minimal },
        });
    }
    replaceServiceDependencies(mount, deps, minimal = false) {
        return this.request({
            method: "PUT",
            pathname: "/_api/foxx/dependencies",
            body: deps,
            search: { mount, minimal },
        });
    }
    updateServiceDependencies(mount, deps, minimal = false) {
        return this.request({
            method: "PATCH",
            pathname: "/_api/foxx/dependencies",
            body: deps,
            search: { mount, minimal },
        });
    }
    /**
     * @deprecated Removed from ArangoDB 4.0 onwards.
     * Calling this method against ArangoDB v4 will result in a runtime exception.
     *
     * Enables or disables development mode for the given service.
     *
     * @param mount - The service's mount point, relative to the database.
     * @param enabled - Whether development mode should be enabled or disabled.
     *
     * @example
     * ```js
     * const db = new Database();
     * await db.setServiceDevelopmentMode("/my-service", true);
     * // the service is now in development mode
     * await db.setServiceDevelopmentMode("/my-service", false);
     * // the service is now in production mode
     * ```
     */
    setServiceDevelopmentMode(mount, enabled = true) {
        return this.request({
            method: enabled ? "POST" : "DELETE",
            pathname: "/_api/foxx/development",
            search: { mount },
        });
    }
    /**
     * @deprecated Removed from ArangoDB 4.0 onwards.
     * Calling this method against ArangoDB v4 will result in a runtime exception.
     *
     * Retrieves an object mapping script names to their human readable
     * representations, as defined in the service manifest's "scripts" section.
     *
     * @param mount - The service's mount point, relative to the database.
     *
     * @example
     * ```js
     * const db = new Database();
     * const scripts = await db.getServiceScripts("/my-service");
     * for (const [name, title] of Object.entries(scripts)) {
     *   console.log(`${name}: ${title}`);
     * }
     * ```
     */
    getServiceScripts(mount) {
        return this.request({
            pathname: "/_api/foxx/scripts",
            search: { mount },
        });
    }
    /**
     * @deprecated Removed from ArangoDB 4.0 onwards.
     * Calling this method against ArangoDB v4 will result in a runtime exception.
     *
     * Executes a service script and retrieves its result exposed as
     * `module.exports` (if any).
     *
     * @param mount - The service's mount point, relative to the database.
     * @param name - Name of the service script to execute as defined in the
     * service manifest.
     * @param params - Arbitrary value that will be exposed to the script as
     * `argv[0]` in the service context (e.g. `module.context.argv[0]`).
     * Must be serializable to JSON.
     *
     * @example
     * ```js
     * const db = new Database();
     * const result = await db.runServiceScript(
     *   "/my-service",
     *   "create-user",
     *   {
     *     username: "service_admin",
     *     password: "hunter2"
     *   }
     * );
     * ```
     */
    runServiceScript(mount, name, params) {
        return this.request({
            method: "POST",
            pathname: `/_api/foxx/scripts/${encodeURIComponent(name)}`,
            body: params,
            search: { mount },
        });
    }
    runServiceTests(mount, options) {
        return this.request({
            method: "POST",
            pathname: "/_api/foxx/tests",
            search: {
                ...options,
                mount,
            },
        });
    }
    /**
     * @deprecated Removed from ArangoDB 4.0 onwards.
     * Calling this method against ArangoDB v4 will result in a runtime exception.
     *
     * Retrieves the text content of the service's `README` or `README.md` file.
     *
     * Returns `undefined` if no such file could be found.
     *
     * @param mount - The service's mount point, relative to the database.
     *
     * @example
     * ```js
     * const db = new Database();
     * const readme = await db.getServiceReadme("/my-service");
     * if (readme !== undefined) console.log(readme);
     * else console.warn(`No README found.`)
     * ```
     */
    getServiceReadme(mount) {
        return this.request({
            pathname: "/_api/foxx/readme",
            search: { mount },
        });
    }
    /**
     * @deprecated Removed from ArangoDB 4.0 onwards.
     * Calling this method against ArangoDB v4 will result in a runtime exception.
     *
     * Retrieves an Open API compatible Swagger API description object for the
     * service installed at the given mount point.
     *
     * @param mount - The service's mount point, relative to the database.
     *
     * @example
     * ```js
     * const db = new Database();
     * const spec = await db.getServiceDocumentation("/my-service");
     * // spec is a Swagger API description of the service
     * ```
     */
    getServiceDocumentation(mount) {
        return this.request({
            pathname: "/_api/foxx/swagger",
            search: { mount },
        });
    }
    /**
     * @deprecated Removed from ArangoDB 4.0 onwards.
     * Calling this method against ArangoDB v4 will result in a runtime exception.
     *
     * Retrieves a zip bundle containing the service files.
     *
     * Returns a `Buffer` in node.js or `Blob` in the browser.
     *
     * @param mount - The service's mount point, relative to the database.
     *
     * @example
     * ```js
     * const db = new Database();
     * const serviceBundle = await db.downloadService("/my-foxx");
     * ```
     */
    downloadService(mount) {
        return this.request({
            method: "POST",
            pathname: "/_api/foxx/download",
            search: { mount },
            expectBinary: true,
        });
    }
    /**
     * @deprecated Removed from ArangoDB 4.0 onwards.
     * Calling this method against ArangoDB v4 will result in a runtime exception.
     *
     * Writes all locally available services to the database and updates any
     * service bundles missing in the database.
     *
     * @param replace - If set to `true`, outdated services will also be
     * committed. This can be used to solve some consistency problems when
     * service bundles are missing in the database or were deleted manually.
     *
     * @example
     * ```js
     * await db.commitLocalServiceState();
     * // all services available on the coordinator have been written to the db
     * ```
     *
     * @example
     * ```js
     * await db.commitLocalServiceState(true);
     * // all service conflicts have been resolved in favor of this coordinator
     * ```
     */
    commitLocalServiceState(replace = false) {
        return this.request({
            method: "POST",
            pathname: "/_api/foxx/commit",
            search: { replace },
        }, () => undefined);
    }
    //#endregion
    //#region hot backups
    /**
     * (Enterprise Edition only.) Creates a hot backup of the entire ArangoDB
     * deployment including all databases, collections, etc.
     *
     * Returns an object describing the backup result.
     *
     * @param options - Options for creating the backup.
     *
     * @example
     * ```js
     * const info = await db.createHotBackup();
     * // a hot backup has been created
     * ```
     */
    createHotBackup(options = {}) {
        return this.request({
            method: "POST",
            pathname: "/_admin/backup/create",
            body: options,
        }, (res) => res.parsedBody.result);
    }
    /**
     * (Enterprise Edition only.) Retrieves a list of all locally found hot
     * backups.
     *
     * @param id - If specified, only the backup with the given ID will be
     * returned.
     *
     * @example
     * ```js
     * const backups = await db.getHotBackups();
     * for (const backup of backups.list) {
     *   console.log(backup.id);
     * }
     * ```
     */
    getHotBackups(id) {
        return this.request({
            method: "POST",
            pathname: "/_admin/backup/list",
            body: id ? { id } : undefined,
        }, (res) => res.parsedBody.result);
    }
    /**
     * (Enteprise Edition only.) Restores a consistent local hot backup.
     *
     * Returns the directory path of the restored backup.
     *
     * @param id - The ID of the backup to restore.
     *
     * @example
     * ```js
     * await db.restoreHotBackup("2023-09-19T15.38.21Z_example");
     * // the backup has been restored
     * ```
     */
    restoreHotBackup(id) {
        return this.request({
            method: "POST",
            pathname: "/_admin/backup/restore",
            body: { id },
        }, (res) => res.parsedBody.result.previous);
    }
    /**
     * (Enterprise Edition only.) Deletes a local hot backup.
     *
     * @param id - The ID of the backup to delete.
     *
     * @example
     * ```js
     * await db.deleteHotBackup("2023-09-19T15.38.21Z_example");
     * // the backup has been deleted
     * ```
     */
    deleteHotBackup(id) {
        return this.request({
            method: "POST",
            pathname: "/_admin/backup/delete",
            body: { id },
        }, () => undefined);
    }
    //#endregion
    //#region logs
    /**
     * Retrieves the log messages from the server's global log.
     *
     * @param options - Options for retrieving the log entries.
     *
     * @example
     * ```js
     * const log = await db.getLogEntries();
     * for (let i = 0; i < log.totalAmount; i++) {
     *   console.log(`${
     *     new Date(log.timestamp[i] * 1000).toISOString()
     *   } - [${LogLevel[log.level[i]]}] ${log.text[i]} (#${log.lid[i]})`);
     * }
     * ```
     */
    getLogEntries(options) {
        return this.request({
            pathname: "/_admin/log/entries",
            search: options,
        }, (res) => res.parsedBody);
    }
    /**
     * Retrieves the log messages from the server's global log.
     *
     * @param options - Options for retrieving the log entries.
     *
     * @deprecated This endpoint has been deprecated in ArangoDB 3.8.
     * Use {@link Database#getLogEntries} instead.
     *
     * @example
     * ```js
     * const messages = await db.listLogMessages();
     * for (const m of messages) {
     *   console.log(`${m.date} - [${m.level}] ${m.message} (#${m.id})`);
     * }
     * ```
     */
    listLogMessages(options) {
        return this.request({
            pathname: "/_admin/log",
            search: options,
        }, (res) => res.parsedBody.messages);
    }
    /**
     * Retrieves the server's current log level for each topic.
     *
     * @example
     * ```js
     * const levels = await db.getLogLevel();
     * console.log(levels.request); // log level for incoming requests
     * ```
     */
    getLogLevel() {
        return this.request({
            pathname: "/_admin/log/level",
        });
    }
    /**
     * Sets the server's log level for each of the given topics to the given level.
     *
     * Any omitted topics will be left unchanged.
     *
     * @param levels - An object mapping topic names to log levels.
     *
     * @example
     * ```js
     * await db.setLogLevel({ request: "debug" });
     * // Debug information will now be logged for each request
     * ```
     */
    setLogLevel(levels) {
        return this.request({
            method: "PUT",
            pathname: "/_admin/log/level",
            body: levels,
        });
    }
    //#endregion
    //#region async jobs
    /**
     * Creates an async job by executing the given callback function. The first
     * database request performed by the callback will be marked for asynchronous
     * execution and its result will be made available as an async job.
     *
     * Returns a {@link jobs.Job} instance that can be used to retrieve the result
     * of the callback function once the request has been executed.
     *
     * @param callback - Callback function to execute as an async job.
     *
     * @example
     * ```js
     * const db = new Database();
     * const job = await db.createJob(() => db.collections());
     * while (!job.isLoaded) {
     *  await timeout(1000);
     *  await job.load();
     * }
     * // job.result is a list of Collection instances
     * ```
     */
    async createJob(callback) {
        const trap = new Promise((resolveTrap) => {
            this._trapRequest = (trapped) => resolveTrap(trapped);
        });
        const eventualResult = callback();
        const trapped = await trap;
        if (trapped.error)
            return eventualResult;
        const { jobId, onResolve, onReject } = trapped;
        return new jobs.Job(this, jobId, (res) => {
            onResolve(res);
            return eventualResult;
        }, (e) => {
            onReject(e);
            return eventualResult;
        });
    }
    /**
     * Returns a {@link jobs.Job} instance for the given `jobId`.
     *
     * @param jobId - ID of the async job.
     *
     * @example
     * ```js
     * const db = new Database();
     * const job = db.job("12345");
     * ```
     */
    job(jobId) {
        return new jobs.Job(this, jobId);
    }
    /**
     * Returns a list of the IDs of all currently pending async jobs.
     *
     * @example
     * ```js
     * const db = new Database();
     * const pendingJobs = await db.listPendingJobs();
     * console.log(pendingJobs); // e.g. ["12345", "67890"]
     * ```
     */
    listPendingJobs() {
        return this.request({
            pathname: "/_api/job/pending",
        }, (res) => res.parsedBody);
    }
    /**
     * Returns a list of the IDs of all currently available completed async jobs.
     *
     * @example
     * ```js
     * const db = new Database();
     * const completedJobs = await db.listCompletedJobs();
     * console.log(completedJobs); // e.g. ["12345", "67890"]
     * ```
     */
    listCompletedJobs() {
        return this.request({
            pathname: "/_api/job/done",
        }, (res) => res.parsedBody);
    }
    /**
     * Deletes the results of all completed async jobs created before the given
     * threshold.
     *
     * @param threshold - The expiration timestamp in milliseconds.
     *
     * @example
     * ```js
     * const db = new Database();
     * const ONE_WEEK = 7 * 24 * 60 * 60 * 1000;
     * await db.deleteExpiredJobResults(Date.now() - ONE_WEEK);
     * // all job results older than a week have been deleted
     * ```
     */
    deleteExpiredJobResults(threshold) {
        return this.request({
            method: "DELETE",
            pathname: `/_api/job/expired`,
            search: { stamp: threshold / 1000 },
        }, () => undefined);
    }
    /**
     * Deletes the results of all completed async jobs.
     */
    deleteAllJobResults() {
        return this.request({
            method: "DELETE",
            pathname: `/_api/job/all`,
        }, () => undefined);
    }
}
exports.Database = Database;
//#endregion
//# sourceMappingURL=databases.js.map