UNPKG

magically-sdk

Version:

Official SDK for Magically - Build mobile apps with AI

308 lines (307 loc) 11.4 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.MagicallyData = void 0; const APIClient_1 = require("./APIClient"); const utils_1 = require("./utils"); class MagicallyData { constructor(config, auth) { this.config = config; this.auth = auth; this.apiClient = new APIClient_1.APIClient(config, 'MagicallyData'); } /** * Check if a query is public (doesn't require authentication) */ isPublicQuery(filter) { return filter?.isPublic === true; } /** * Check if an aggregate pipeline is public (doesn't require authentication) */ isPublicAggregate(pipeline) { return pipeline?.[0]?.$match?.isPublic === true; } /** * Check if a raw operation is public (read-only with isPublic filter) */ isPublicRawOperation(operation, query) { const readOperations = ['find', 'findOne', 'count', 'countDocuments', 'distinct']; return readOperations.includes(operation) && query?.isPublic === true; } /** * Query data from a collection with type safety * @param collection - Collection name * @param filter - MongoDB filter object (optional) * @param options - Query options (sort, limit, skip) */ async query(collection, filter, options) { try { const token = await (0, utils_1.getAuthToken)(this.apiClient, this.auth); const result = await this.apiClient.request(`/api/project/${this.config.projectId}/data/query`, { method: 'POST', body: { collection, filter: filter || {}, sort: options?.sort || {}, limit: options?.limit || 100, skip: options?.skip || 0, populate: options?.populate || [], }, operation: `query:${collection}` }, token); return { data: result.data || [], total: result.total || 0 }; } catch (error) { throw error; } } /** * Insert data into a collection with type safety */ async insert(collection, data, options = {}) { try { const token = await (0, utils_1.getAuthToken)(this.apiClient, this.auth); const result = await this.apiClient.request(`/api/project/${this.config.projectId}/data/insert`, { method: 'POST', body: { collection, data, upsert: options.upsert || false, }, operation: `insert:${collection}` }, token); return result.data; } catch (error) { throw error; } } /** * Update existing data in a collection (fails if not found) */ async update(collection, filter, update) { try { const token = await (0, utils_1.getAuthToken)(this.apiClient, this.auth); // Check if it's already a MongoDB update object const isMongoUpdate = update.$set || update.$inc || update.$push || update.$pull || update.$unset || update.$addToSet || update.$rename || update.$min || update.$max || update.$mul || update.$currentDate; // If plain data, wrap in $set. Otherwise use as-is const updateObj = isMongoUpdate ? update : { $set: update }; const result = await this.apiClient.request(`/api/project/${this.config.projectId}/data/update`, { method: 'POST', body: { collection, filter, update: updateObj }, operation: `update:${collection}` }, token); if (!result.result?.value) { throw new Error('Document not found for update'); } return result.result.value; } catch (error) { throw error; } } /** * Upsert data in a collection (update if exists, insert if not) * @param collection - Collection name * @param filter - Filter to find existing document * @param data - Data to insert or update * @returns The upserted document and whether it was inserted */ async upsert(collection, filter, data) { try { const token = await (0, utils_1.getAuthToken)(this.apiClient, this.auth); const result = await this.apiClient.request(`/api/project/${this.config.projectId}/data/upsert`, { method: 'POST', body: { collection, filter, data }, operation: `upsert:${collection}` }, token); return { data: result.data, upserted: result.upserted || false }; } catch (error) { throw error; } } /** * Update multiple documents in a collection * @param collection - Collection name * @param filter - MongoDB filter to find documents to update * @param update - Update data or MongoDB update object * @returns Number of matched and modified documents */ async updateMany(collection, filter, update) { try { const token = await (0, utils_1.getAuthToken)(this.apiClient, this.auth); // Check if it's already a MongoDB update object const isMongoUpdate = update.$set || update.$inc || update.$push || update.$pull || update.$unset || update.$addToSet || update.$rename || update.$min || update.$max || update.$mul || update.$currentDate; // If plain data, wrap in $set. Otherwise use as-is const updateObj = isMongoUpdate ? update : { $set: update }; const result = await this.apiClient.request(`/api/project/${this.config.projectId}/data/update`, { method: 'POST', body: { collection, filter, update: updateObj, options: { multi: true } }, operation: `updateMany:${collection}` }, token); return { matchedCount: result.matchedCount || 0, modifiedCount: result.modifiedCount || 0 }; } catch (error) { throw error; } } /** * Count documents in a collection * @param collection - Collection name * @param filter - Optional MongoDB filter * @returns Count of matching documents */ async count(collection, filter) { try { const token = await (0, utils_1.getAuthToken)(this.apiClient, this.auth); const result = await this.apiClient.request(`/api/project/${this.config.projectId}/data/raw`, { method: 'POST', body: { collection, operation: 'countDocuments', query: filter || {} }, operation: `count:${collection}` }, token); return { count: result.result || 0 }; } catch (error) { throw error; } } /** * Delete data from a collection (deletes multiple documents) */ async delete(collection, filter) { try { const token = await (0, utils_1.getAuthToken)(this.apiClient, this.auth); const result = await this.apiClient.request(`/api/project/${this.config.projectId}/data/delete`, { method: 'POST', body: { collection, filter, options: { deleteMany: true } }, operation: `delete:${collection}` }, token); return { deletedCount: result.result.deletedCount || 0 }; } catch (error) { throw error; } } /** * Delete a single document from a collection * @param collection - Collection name * @param filter - MongoDB filter to find the document to delete * @returns Number of deleted documents (0 or 1) */ async deleteOne(collection, filter) { try { const token = await (0, utils_1.getAuthToken)(this.apiClient, this.auth); const result = await this.apiClient.request(`/api/project/${this.config.projectId}/data/delete`, { method: 'POST', body: { collection, filter, options: { deleteMany: false } // deleteOne }, operation: `deleteOne:${collection}` }, token); return { deletedCount: result.result.deletedCount || 0 }; } catch (error) { throw error; } } /** * Delete multiple documents from a collection (alias for delete) * @param collection - Collection name * @param filter - MongoDB filter to find documents to delete * @returns Number of deleted documents */ async deleteMany(collection, filter) { return this.delete(collection, filter); } /** * Run aggregation query with type safety */ async aggregate(collection, pipeline) { try { const token = await (0, utils_1.getAuthToken)(this.apiClient, this.auth); const result = await this.apiClient.request(`/api/project/${this.config.projectId}/data/aggregate`, { method: 'POST', body: { collection, pipeline, allowDiskUse: false }, operation: `aggregate:${collection}` }, token); return result.data; } catch (error) { throw error; } } /** * Run raw MongoDB operations with type safety and validation */ async raw(collection, operation, options = {}) { // Validate allowed operations for security const allowedOperations = [ 'find', 'findOne', 'count', 'countDocuments', 'distinct', 'aggregate', 'findOneAndUpdate', 'updateOne', 'updateMany', 'deleteOne', 'deleteMany', 'insertOne', 'insertMany' ]; if (!allowedOperations.includes(operation)) { throw new Error(`Operation '${operation}' is not allowed. Allowed operations: ${allowedOperations.join(', ')}`); } try { const token = await (0, utils_1.getAuthToken)(this.apiClient, this.auth); const result = await this.apiClient.request(`/api/project/${this.config.projectId}/data/raw`, { method: 'POST', body: { collection, operation, ...options }, operation: `raw:${operation}:${collection}` }, token); return result.result; } catch (error) { throw error; } } } exports.MagicallyData = MagicallyData;