UNPKG

@dataql/node

Version:

DataQL core SDK for unified data management with MongoDB and GraphQL - Production Multi-Cloud Ready

265 lines (264 loc) 10.5 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.DocumentScope = exports.SubdocumentCollection = void 0; exports.createDocumentScope = createDocumentScope; const utils_js_1 = require("./utils.js"); class SubdocumentCollection { constructor(collectionName, parentFilter, subdocumentPath, schema, fetchFunction, appToken, ensureSession) { this.collectionName = collectionName; this.parentFilter = parentFilter; this.subdocumentPath = subdocumentPath; this.schema = schema; this.fetchFunction = fetchFunction; this.appToken = appToken; this.ensureSession = ensureSession; } getWorkerUrl() { return "https://edge.dataql.com"; } async create(data) { const sessionId = await this.ensureSession(); const url = `${this.getWorkerUrl()}/data/${this.collectionName}/subdocument/${this.subdocumentPath}/create`; const res = await this.fetchFunction(url, { method: "POST", headers: { "content-type": "application/json", "x-app-token": this.appToken, }, body: JSON.stringify({ sessionId, schema: { [this.collectionName]: this.schema }, parentFilter: this.parentFilter, data, }), }); const result = await res.json(); if (result.error) throw new Error(result.error); return result; } async createUnique(data) { // First, get the subdocument schema for this path const pathParts = this.subdocumentPath.split("."); let currentSchema = this.schema; for (const part of pathParts) { if (currentSchema[part]) { currentSchema = Array.isArray(currentSchema[part]) ? currentSchema[part][0] : currentSchema[part]; } } // Extract comparable fields from the new data const comparableFields = (0, utils_js_1.extractComparableFields)(data, currentSchema); // Find existing subdocuments const existingDocs = await this.find(); // Check if any existing subdocument matches the comparable fields for (const existingDoc of existingDocs) { const existingComparableFields = (0, utils_js_1.extractComparableFields)(existingDoc, currentSchema); if ((0, utils_js_1.areFieldsMatching)(comparableFields, existingComparableFields)) { // Found a matching subdocument, return it return { result: existingDoc, isExisting: true, }; } } // No matching subdocument found, create a new one const createResult = await this.create(data); return { result: createResult, isExisting: false, }; } async find(filter = {}) { const sessionId = await this.ensureSession(); const url = `${this.getWorkerUrl()}/data/${this.collectionName}/subdocument/${this.subdocumentPath}/find`; const res = await this.fetchFunction(url, { method: "POST", headers: { "content-type": "application/json", "x-app-token": this.appToken, }, body: JSON.stringify({ sessionId, schema: { [this.collectionName]: this.schema }, parentFilter: this.parentFilter, filter, }), }); const result = await res.json(); if (result.error) throw new Error(result.error); return Array.isArray(result) ? result : [result]; } async update(filter, update) { const sessionId = await this.ensureSession(); const url = `${this.getWorkerUrl()}/data/${this.collectionName}/subdocument/${this.subdocumentPath}/update`; const res = await this.fetchFunction(url, { method: "POST", headers: { "content-type": "application/json", "x-app-token": this.appToken, }, body: JSON.stringify({ sessionId, schema: { [this.collectionName]: this.schema }, parentFilter: this.parentFilter, filter, update, }), }); const result = await res.json(); if (result.error) throw new Error(result.error); return result; } async delete(filter) { const sessionId = await this.ensureSession(); const url = `${this.getWorkerUrl()}/data/${this.collectionName}/subdocument/${this.subdocumentPath}/delete`; const res = await this.fetchFunction(url, { method: "POST", headers: { "content-type": "application/json", "x-app-token": this.appToken, }, body: JSON.stringify({ sessionId, schema: { [this.collectionName]: this.schema }, parentFilter: this.parentFilter, filter, }), }); const result = await res.json(); if (result.error) throw new Error(result.error); return result; } async updateMany(filter, update) { const sessionId = await this.ensureSession(); const url = `${this.getWorkerUrl()}/data/${this.collectionName}/subdocument/${this.subdocumentPath}/updateMany`; const res = await this.fetchFunction(url, { method: "POST", headers: { "content-type": "application/json", "x-app-token": this.appToken, }, body: JSON.stringify({ sessionId, schema: { [this.collectionName]: this.schema }, parentFilter: this.parentFilter, filter, update, }), }); const result = await res.json(); if (result.error) throw new Error(result.error); return result; } async deleteMany(filter) { const sessionId = await this.ensureSession(); const url = `${this.getWorkerUrl()}/data/${this.collectionName}/subdocument/${this.subdocumentPath}/deleteMany`; const res = await this.fetchFunction(url, { method: "POST", headers: { "content-type": "application/json", "x-app-token": this.appToken, }, body: JSON.stringify({ sessionId, schema: { [this.collectionName]: this.schema }, parentFilter: this.parentFilter, filter, }), }); const result = await res.json(); if (result.error) throw new Error(result.error); return result; } } exports.SubdocumentCollection = SubdocumentCollection; class DocumentScope { constructor(collectionName, parentFilter, schema, fetchFunction, appToken, ensureSession) { this.collectionName = collectionName; this.parentFilter = parentFilter; this.schema = schema; this.fetchFunction = fetchFunction; this.appToken = appToken; this.ensureSession = ensureSession; this.subdocuments = {}; this.initializeSubdocuments(); } initializeSubdocuments() { this.analyzeSchemaForSubdocuments(this.schema, ""); } analyzeSchemaForSubdocuments(schemaObj, path) { for (const [key, field] of Object.entries(schemaObj)) { const currentPath = path ? `${path}.${key}` : key; if (this.isSubdocumentArray(field)) { // Create subdocument collection for arrays this.subdocuments[key] = new SubdocumentCollection(this.collectionName, this.parentFilter, currentPath, this.schema, this.fetchFunction, this.appToken, this.ensureSession); } else if (this.isNestedObject(field)) { // For nested objects, create a proxy that allows further nesting this.createNestedProxy(key, field, currentPath); } } } isSubdocumentArray(field) { return (Array.isArray(field) && field.length > 0 && typeof field[0] === "object"); } isNestedObject(field) { return (typeof field === "object" && field !== null && !Array.isArray(field) && !field.type && !field.enum); } createNestedProxy(key, field, path) { const nestedScope = { update: async (updateData) => { const sessionId = await this.ensureSession(); const url = `${this.getWorkerUrl()}/data/${this.collectionName}/subdocument/${path}/update`; const res = await this.fetchFunction(url, { method: "POST", headers: { "content-type": "application/json", "x-app-token": this.appToken, }, body: JSON.stringify({ sessionId, schema: { [this.collectionName]: this.schema }, parentFilter: this.parentFilter, update: updateData, }), }); const result = await res.json(); if (result.error) throw new Error(result.error); return result; }, }; // Add nested subdocuments this.analyzeSchemaForSubdocuments(field, path); // Assign the nested scope to this object this[key] = nestedScope; } getWorkerUrl() { return "https://edge.dataql.com"; } } exports.DocumentScope = DocumentScope; // Create a Proxy to enable dynamic property access function createDocumentScope(collectionName, parentFilter, schema, fetchFunction, appToken, ensureSession) { const scope = new DocumentScope(collectionName, parentFilter, schema, fetchFunction, appToken, ensureSession); return new Proxy(scope, { get(target, prop) { if (typeof prop === "string" && prop in target.subdocuments) { return target.subdocuments[prop]; } return target[prop]; }, }); }