documentdb-typescript
Version:
TypeScript API for Microsoft Azure DocumentDB
139 lines (138 loc) • 6.79 kB
JavaScript
"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;