@decaf-ts/for-couchdb
Version:
decaf-ts couchdb wrappers
201 lines • 8.39 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.reAuth = reAuth;
exports.wrapDocumentScope = wrapDocumentScope;
exports.testReservedAttributes = testReservedAttributes;
exports.generateIndexName = generateIndexName;
exports.generateIndexDoc = generateIndexDoc;
const core_1 = require("@decaf-ts/core");
const constants_js_1 = require("./constants.cjs");
const db_decorators_1 = require("@decaf-ts/db-decorators");
const constants_js_2 = require("./query/constants.cjs");
/**
* @description Re-authenticates a connection to CouchDB
* @summary Refreshes the authentication for a CouchDB connection using the provided credentials
* @param {any} con - The CouchDB connection object
* @param {string} user - The username for authentication
* @param {string} pass - The password for authentication
* @return {Promise<any>} A promise that resolves to the authentication result
* @function reAuth
* @memberOf module:for-couchdb
*/
async function reAuth(con, couchUser, couchPassword) {
return con.auth(couchUser, couchPassword);
}
/**
* @description Wraps a CouchDB database connection with automatic re-authentication
* @summary Creates a proxy around a CouchDB database connection that automatically re-authenticates before each operation
* @param {any} con - The CouchDB connection object
* @param {string} dbName - The name of the database to use
* @param {string} user - The username for authentication
* @param {string} pass - The password for authentication
* @return {any} The wrapped database connection object
* @function wrapDocumentScope
* @memberOf module:for-couchdb
* @mermaid
* sequenceDiagram
* participant Client
* participant wrapDocumentScope
* participant DB
* participant reAuth
*
* Client->>wrapDocumentScope: con, dbName, user, pass
* wrapDocumentScope->>DB: con.use(dbName)
* Note over wrapDocumentScope: Wrap DB methods with re-auth
*
* loop For each method (insert, get, put, destroy, find)
* wrapDocumentScope->>wrapDocumentScope: Store original method
* wrapDocumentScope->>wrapDocumentScope: Define new method with re-auth
* end
*
* wrapDocumentScope->>wrapDocumentScope: Add NATIVE property with con value
* wrapDocumentScope-->>Client: Return wrapped DB
*
* Note over Client: Later when client uses DB methods
* Client->>DB: Any wrapped method call
* DB->>reAuth: Authenticate before operation
* reAuth-->>DB: Authentication complete
* DB->>DB: Call original method
* DB-->>Client: Return result
*/
function wrapDocumentScope(con, dbName, couchUser, couchPassword) {
const db = con.use ? con.use(dbName) : con;
[
"insert",
"bulk",
"fetch",
"createIndex",
"get",
"put",
"destroy",
"find",
"view",
].forEach((k) => {
const original = db[k];
// Not every CouchDB client exposes the same surface (e.g. nano has no
// `put`, it uses `insert` for both create and update). Skip methods that
// are not available on the underlying scope instead of failing hard, so
// the wrapper stays usable across adapters while still re-authing every
// method that does exist.
if (typeof original !== "function")
return;
Object.defineProperty(db, k, {
enumerable: false,
configurable: true,
value: async (...args) => {
await reAuth(con, couchUser, couchPassword);
return original.call(db, ...args);
},
});
});
Object.defineProperty(db, constants_js_1.CouchDBKeys.NATIVE, {
enumerable: false,
configurable: false,
writable: false,
value: con,
});
return db;
}
/**
* @description Tests if an attribute name is reserved in CouchDB
* @summary Checks if an attribute name starts with an underscore, which indicates it's a reserved attribute in CouchDB
* @param {string} attr - The attribute name to test
* @return {RegExpMatchArray|null} The match result or null if no match
* @function testReservedAttributes
* @memberOf module:for-couchdb
*/
function testReservedAttributes(attr) {
const regexp = /^_.*$/g;
return attr.match(regexp);
}
/**
* @description Generates a name for a CouchDB index
* @summary Creates a standardized name for a CouchDB index based on the table, attribute, compositions, and order
* @param {string} attribute - The primary attribute for the index
* @param {string} tableName - The name of the table
* @param {string[]} [compositions] - Optional additional attributes to include in the index
* @param {OrderDirection} [order] - Optional sort order for the index
* @param {string} [separator=DefaultSeparator] - The separator to use between parts of the index name
* @return {string} The generated index name
* @function generateIndexName
* @memberOf module:for-couchdb
*/
function generateIndexName(attribute, tableName, compositions, order, separator = db_decorators_1.DefaultSeparator) {
const attr = [core_1.PersistenceKeys.INDEX, tableName, attribute];
if (compositions)
attr.push(...compositions);
if (order)
attr.push(order);
return attr.join(separator);
}
/**
* @description Generates a CouchDB index configuration
* @summary Creates a complete CreateIndexRequest object for defining a CouchDB index based on specified parameters
* @param {string} attribute - The primary attribute for the index
* @param {string} tableName - The name of the table
* @param {string[]} [compositions] - Optional additional attributes to include in the index
* @param {OrderDirection} [order] - Optional sort order for the index
* @param {string} [separator=DefaultSeparator] - The separator to use between parts of the index name
* @return {CreateIndexRequest} The complete index configuration object
* @function generateIndexDoc
* @memberOf module:for-couchdb
* @mermaid
* sequenceDiagram
* participant Caller
* participant generateIndexDoc
* participant generateIndexName
*
* Caller->>generateIndexDoc: attribute, tableName, compositions, order, separator
*
* Note over generateIndexDoc: Create partial filter selector
* generateIndexDoc->>generateIndexDoc: Set up filter for tableName
*
* alt order is specified
* Note over generateIndexDoc: Create ordered fields array
* generateIndexDoc->>generateIndexDoc: Create orderProp for attribute
* generateIndexDoc->>generateIndexDoc: Map compositions to ordered props
* generateIndexDoc->>generateIndexDoc: Create sortedTable for table field
* generateIndexDoc->>generateIndexDoc: Combine all ordered fields
* else
* Note over generateIndexDoc: Create simple fields array
* generateIndexDoc->>generateIndexDoc: Use attribute, compositions, and table as strings
* end
*
* generateIndexDoc->>generateIndexName: Generate index name
* generateIndexName-->>generateIndexDoc: Return name
*
* Note over generateIndexDoc: Create final index request
* generateIndexDoc-->>Caller: Return CreateIndexRequest
*/
function generateIndexDoc(attribute, tableName, compositions, order, separator = db_decorators_1.DefaultSeparator) {
const partialFilterSelector = {};
partialFilterSelector[constants_js_1.CouchDBKeys.TABLE] = {};
partialFilterSelector[constants_js_1.CouchDBKeys.TABLE][constants_js_2.CouchDBOperator.EQUAL] = tableName;
let fields;
if (order) {
const orderProp = {};
orderProp[attribute] = order;
const sortedCompositions = (compositions || []).map((c) => {
const r = {};
r[c] = order;
return r;
});
const sortedTable = {};
sortedTable[constants_js_1.CouchDBKeys.TABLE] = order;
fields = [orderProp, ...sortedCompositions, sortedTable];
}
else {
fields = [attribute, ...(compositions || []), constants_js_1.CouchDBKeys.TABLE];
}
const name = generateIndexName(attribute, tableName, compositions, order, separator);
return {
index: {
fields: fields,
// partial_filter_selector: partialFilterSelector,
},
ddoc: [name, constants_js_1.CouchDBKeys.DDOC].join(separator),
name: name,
};
}
//# sourceMappingURL=utils.js.map
//# sourceMappingURL=utils.cjs.map