UNPKG

documentdb-typescript

Version:
139 lines (138 loc) 6.79 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); const _DocumentDB = require("./_DocumentDB"); const Util_1 = require("./Util"); const Database_1 = require("./Database"); /** List of opened/opening clients for specific endpoint/key combinations */ var _openClients = new Map(); /** Next UID */ var _uid = 1; /** Represents a DocumentDB endpoint */ class Client { constructor(url, masterKey = "<no_key>") { /** Set to true to log all requests to the console */ this.enableConsoleLog = false; /** Timeout (ms) used for all requests (defaults to 40s) */ this.timeout = 40000; /** @internal List of databases found in the account, resolved if and when opened */ this._databaseResources = new Promise(resolve => { this._resolve_databases = resolve; }); /** @internal */ this._uid = _uid++; this.url = url || ""; this.authenticationOptions = { masterKey }; } /** The native DocumentClient instance; throws an error if this client is currently not connected (check using .isOpen, or await .openAsync() first) */ get documentClient() { if (this._closed) throw new Error("Client already closed"); if (!this._client) throw new Error("Document DB client is not connected"); return this._client; } /** Returns true if this client is currently connected through a native DocumentClient instance */ get isOpen() { return !!this._client && !this._closed; } /** Connect to the endpoint represented by this client and validate the connection, unless already connected */ openAsync(maxRetries = 3) { if (this._closed) throw new Error("Client already closed"); if (this._open) return this._open; // check if another instance is already connected/-ing var key = this.url + ":" + JSON.stringify(this.authenticationOptions) + ":" + JSON.stringify(this.connectionPolicy) + ":" + this.consistencyLevel; if (_openClients.has(key)) { var other = _openClients.get(key); this._client = other._client; this._databaseResources = other._databaseResources; return this._open = other._open; } _openClients.set(key, this); // create a new DocumentClient instance this._client = new _DocumentDB.DocumentClient(this.url, this.authenticationOptions, this.connectionPolicy, this.consistencyLevel); // return a promise that resolves when databases are read return this._open = new Promise(resolve => { let tryConnect = (callback) => this.log("Connecting to " + this.url) && this._client.readDatabases({ maxItemCount: 1000 }) .toArray(callback); resolve(Util_1.curryPromise(tryConnect, this.timeout, maxRetries)() .then(dbs => { this._resolve_databases(dbs); })); }); } /** Get a (cached) list of Database instances for all databases in this account */ listDatabasesAsync(forceReload, maxRetries) { return __awaiter(this, void 0, void 0, function* () { if (!this._open) yield this.openAsync(maxRetries); if (forceReload) { // create new promise for list of DB resources this._databaseResources = new Promise(resolve => { this._resolve_databases = resolve; }); // read all databases again and resolve promise let tryReadDBs = (callback) => this.log("Reading list of databases") && this._client.readDatabases({ maxItemCount: 1000 }) .toArray(callback); this._resolve_databases(yield Util_1.curryPromise(tryReadDBs, this.timeout, maxRetries)()); } var databaseResources = yield this._databaseResources; return databaseResources.map(r => new Database_1.Database(r.id, this, r._self)); }); } /** @internal Create a database (and add it to the list returned by listDatabasesAsync) */ createDatabaseAsync(id, maxRetries, options) { return __awaiter(this, void 0, void 0, function* () { yield this.openAsync(); let tryCreateDB = (callback) => this.log("Creating database: " + id) && this._client.createDatabase({ id }, options, callback); yield Util_1.curryPromise(tryCreateDB, this.timeout, maxRetries)(); // reload all database resources until the created DB appears // (this is to allow for consistency less than session consistency) var times = Math.ceil(this.timeout / 100); while (times-- > 0) { var dbs = yield this.listDatabasesAsync(true); if (dbs.some(db => db.id === id)) return; yield Util_1.sleepAsync(100); } throw new Error("Timeout"); }); } /** Get account information */ getAccountInfoAsync() { return __awaiter(this, void 0, void 0, function* () { let tryGetInfo = (callback) => this.log("Getting account info") && this._client.getDatabaseAccount(callback); return yield Util_1.curryPromise(tryGetInfo, this.timeout)(); }); } /** Remove the current connection; an attempt to open the same endpoint again in another instance will open and validate the connection again, but the current instance cannot be re-opened */ close() { this._closed = true; _openClients.forEach((client, key) => { if (client === this) _openClients.delete(key); }); } /** @internal Log a message; always returns true */ log(message) { if (this.enableConsoleLog) console.log(`[${process.pid}]{${this._uid}} ${Date.now()} ${message}`); return true; } } /** Global concurrency limit for all server requests */ Client.concurrencyLimit = 25; exports.Client = Client;