UNPKG

cosmos-orm

Version:
197 lines (196 loc) 6.64 kB
// src/base-model.ts import { input } from "@azure/functions"; import { ulid } from "ulidx"; var BaseModel = class { constructor(options) { this.options = options; if (options.connectionStringSetting) { this.connectionStringSetting = options.connectionStringSetting; } if (typeof this.options === "boolean" && !this.options) { this.fields = { id: false, timestamp: false }; } if (typeof this.options === "object") { this.fields = { ...this.fields, // Don't know why this won't remove the bool type ...this.options.fields }; } this.client = options.client.database(options.database).container(options.container); } client; connectionStringSetting = "COSMOS_CONNECTION_STRING"; fields = { id: true, timestamp: true }; /** * Create an Azure Function app input binding to find a specific document by an input variable. * You can also provide a type (matching `Record<string, any>`) as the first type generic, * and it will validate the variable to be one of the types keys. * * @example * ```ts * const shopInput = orm.shops.createFindBinding(`shop`) * ``` * @example * An example with a type to check the variable: * ```ts * interface ActivityInput { * shop: string * // ... * } * * const shopDocument = orm.shops.createFindBinding<ActivityInput>('shop') // ✅ * const shopDocument2 = orm.shops.createFindBinding<ActivityInput>('id') // ❌ * ``` */ createFindBinding(variable) { const binding = `{${variable}}`; return input.cosmosDB({ databaseName: this.options.database, containerName: this.options.container, connection: this.connectionStringSetting, id: binding, partitionKey: binding }); } /** Create an Azure Function app input binding to fetch all documents from this container. */ createAllBinding() { return input.cosmosDB({ databaseName: this.options.database, containerName: this.options.container, connection: this.connectionStringSetting }); } /** * Create an Azure Function app input binding with a custom SQL query. * @example * ```ts * const inputDoc = orm.posts.createSQLBinding(`SELECT * FROM c WHERE c.deleted_at IS NULL`) * ``` */ createSQLBinding(sqlQuery) { return input.cosmosDB({ databaseName: this.options.database, containerName: this.options.container, connection: this.connectionStringSetting, sqlQuery }); } /** Fetch all resources in a container */ async all() { const { resources } = await this.client.items.readAll().fetchAll(); return resources; } /** Fetch a specific resource by its ID */ async find(id) { const { resource } = await this.client.item(id, id).read(); return resource; } /** Fetch multiple resources using their ID's */ async findMany(ids) { const { resources } = await this.client.items.query({ query: "SELECT * FROM C WHERE ARRAY_CONTAINS(@ids, C.id)", parameters: [{ name: "@ids", value: ids }] }).fetchAll(); return resources; } /** Find a resource by a specific key */ async findBy(key, value) { const { resources } = await this.client.items.query({ query: "SELECT * FROM C WHERE C[@key] = @value OFFSET 0 LIMIT 1", parameters: [ { name: "@key", value: String(key) }, { name: "@value", value } ] }).fetchAll(); const [resource] = resources; return resource; } /** Find multiple resources by a specific key */ async findManyBy(key, value) { const { resources } = await this.client.items.query({ query: "SELECT * FROM C WHERE C[@key] = @value", parameters: [ { name: "@key", value: String(key) }, { name: "@value", value } ] }).fetchAll(); const [resource] = resources; return resource; } /** Create a resource */ async create(input2) { const merged = { ...input2, id: this.fields.id ? ulid() : input2.id, createdAt: this.fields.timestamp ? (/* @__PURE__ */ new Date()).toISOString() : input2.createdAt, updatedAt: this.fields.timestamp ? (/* @__PURE__ */ new Date()).toISOString() : input2.updatedAt }; const { resource } = await this.client.items.create(merged); return resource; } /** Either update or create a resource */ async upsert(input2) { const { resource } = await this.client.items.upsert(input2); return resource; } /** Update a resource - replaces the whole resource, so make sure to provide a full input */ async replace(id, input2) { const merged = { ...input2, updatedAt: this.fields.timestamp ? (/* @__PURE__ */ new Date()).toISOString() : input2.updatedAt }; const { resource } = await this.client.item(id, id).replace(merged); return resource; } /** Delete a resource */ async delete(id) { const { resource } = await this.client.item(id, id).delete(); return resource; } /** * Run a query, and fetch all results * * This function accepts a generic, so you can pass in the type of the response if * you are running a custom select query - for example: * * `.query<{ id: string }>('SELECT c.id FROM c') // returns { id: string }[]` * * `.query<number>('SELECT VALUE count(c.id) FROM c') // returns [number]` * * This is just a wrapper of the `.client.items.query()` function, so you can use that * instead if you need access to the request metrics for example. */ // biome-ignore lint/suspicious/noExplicitAny: <explanation> async query(query, options) { const { resources } = await this.client.items.query(query, options).fetchAll(); return resources; } }; // src/config.ts import { CosmosClient } from "@azure/cosmos"; function createClient(options) { const connectionStringSetting = options.connectionStringSetting || "COSMOS_CONNECTION_STRING"; const connectionString = options.connectionString ?? process.env[connectionStringSetting]; if (typeof connectionString !== "string") { if (options.connectionString) throw new Error("Missing connection string value (from `options.connectionString`)"); throw new Error(`Missing connection string for ${connectionStringSetting}`); } const client = new CosmosClient(connectionString); const builder = { createModel: (container, config = {}) => new BaseModel({ client, container, ...options, ...config }) }; const models = options.models(builder); return { client, ...models }; } export { BaseModel, createClient }; //# sourceMappingURL=index.mjs.map