permas-database-adapter
v0.1.5
Published
A flexible and universal database adapter library for MongoDB, DynamoDB, Azure CosmosDB, and Supabase
Downloads
16
Maintainers
Readme
Permas Database Adapter
A flexible database adapter library that provides a unified interface for working with different database providers.
Supported Database Providers
The library supports the following database providers:
- MongoDB - Standard MongoDB database
- Azure Cosmos DB with MongoDB API - Azure Cosmos DB using the MongoDB API
- Azure Cosmos DB - Native Azure Cosmos DB using the Cosmos SDK
- AWS DynamoDB - Amazon DynamoDB
- Supabase - Supabase database
Features
- Unified API for multiple database types
- Type-safe with full TypeScript support
- Validation using Zod schemas
- Multi-database federation for distributing collections across different databases
- Feature detection to check database capabilities
- Browser compatible with appropriate security measures
- Error handling with standardized error types
Installation
npm install permas-database-adapterUsage
Basic Usage
const { createDatabaseAdapter, DatabaseProvider } = require('permas-database-adapter');
// Create a database adapter for MongoDB
const adapter = createDatabaseAdapter(DatabaseProvider.MONGODB, {
uri: 'mongodb://localhost:27017/mydb',
databaseName: 'mydb',
options: {
useNewUrlParser: true,
useUnifiedTopology: true
}
});
// Connect to the database
await adapter.connect();
// Create a document
const document = await adapter.create('users', {
name: 'John Doe',
email: '[email protected]'
});
// Find documents
const users = await adapter.find('users', {
filter: { name: 'John Doe' }
});
// Disconnect
await adapter.disconnect();Azure Cosmos DB with MongoDB API
This library provides a specialized adapter for Azure Cosmos DB with MongoDB API that handles the specific requirements and limitations of Cosmos DB:
const { createDatabaseAdapter, DatabaseProvider } = require('permas-database-adapter');
// Method 1: Using the factory function with COSMOS_MONGODB provider
const adapter = createDatabaseAdapter(DatabaseProvider.COSMOS_MONGODB, {
uri: 'mongodb://username:[email protected]:10255/?ssl=true&replicaSet=globaldb&retrywrites=false&maxIdleTimeMS=120000&appName=@account@',
options: {
useNewUrlParser: true,
useUnifiedTopology: true,
retryWrites: false,
ssl: true
}
});
// Method 2: Using the dedicated factory function
const { createCosmosMongoDBAdapter } = require('permas-database-adapter');
const adapter = createCosmosMongoDBAdapter({
uri: 'mongodb://username:[email protected]:10255/?ssl=true&replicaSet=globaldb&retrywrites=false&maxIdleTimeMS=120000&appName=@account@',
options: {
useNewUrlParser: true,
useUnifiedTopology: true,
retryWrites: false,
ssl: true
}
});Key features of the Cosmos MongoDB adapter:
- Automatically uses the
admindatabase as recommended by Microsoft - Sanitizes collection names for Cosmos DB compatibility
- Intelligently handles MongoDB ObjectIds and string IDs
- Optimizes queries for Cosmos DB's limitations
- Safely handles complex update operations that might otherwise fail in Cosmos DB
Enhanced Array Update Operations
The adapter provides specialized methods to handle array operations that are commonly challenging with Cosmos DB:
// Update a specific array element using a compatible approach
await adapter.updateArrayField(
'events',
eventId,
'sessions', // array field name
{ title: 'Session X' }, // item identifier
{ duration: 90, room: 'A101' } // update data
);
// Update all array elements in one operation
await adapter.updateAllArrayItems(
'events',
eventId,
'sessions',
{ status: 'confirmed', lastUpdated: new Date() }
);Smart Array Filter Alternative
For operations that would normally require array filters (which aren't supported in Cosmos DB), the adapter uses a fetch-modify-update pattern automatically:
// This operation would normally require array filters in MongoDB,
// but will work seamlessly with our adapter on Cosmos DB
await adapter.updateById('events', eventId, {
complexNestedData: { ... },
deeplyNestedArray: [ ... ],
'deeply.nested.property': 'value'
});Cosmos DB Limitations Handled
The adapter intelligently handles these Cosmos DB limitations:
- No support for
arrayFiltersin updates - Complex update operators may cause conflicts
- Limited transaction support
- Specific requirements for indexing
- Automatic detection and routing of complex operations through safer patterns
Azure Cosmos DB Native
For using the native Azure Cosmos DB SDK:
const { createDatabaseAdapter, DatabaseProvider } = require('permas-database-adapter');
const adapter = createDatabaseAdapter(DatabaseProvider.COSMOSDB, {
endpoint: 'https://your-account.documents.azure.com:443/',
key: 'your-primary-key',
databaseId: 'mydb',
partitionKey: '/id'
});AWS DynamoDB
const { createDatabaseAdapter, DatabaseProvider } = require('permas-database-adapter');
const adapter = createDatabaseAdapter(DatabaseProvider.DYNAMODB, {
region: 'us-east-1',
tableName: 'my-table',
credentials: {
accessKeyId: 'your-access-key',
secretAccessKey: 'your-secret-key'
}
});Supabase
const { createDatabaseAdapter, DatabaseProvider } = require('permas-database-adapter');
const adapter = createDatabaseAdapter(DatabaseProvider.SUPABASE, {
url: 'https://your-project.supabase.co',
apiKey: 'your-api-key',
schema: 'public'
});Multi-Database Federation
You can distribute collections across different databases:
import { createMultiDatabaseAdapter } from 'permas-database-adapter';
const db = createMultiDatabaseAdapter({
// Primary database for all collections not explicitly mapped
primary: {
provider: 'mongodb',
config: { uri: 'mongodb://localhost:27017/primary' }
},
// Collection-specific database mappings
collections: {
'users': {
provider: 'mongodb',
config: { uri: 'mongodb://localhost:27017/users' }
},
'logs': {
provider: 'dynamodb',
config: {
region: 'us-east-1',
credentials: {
accessKeyId: 'YOUR_ACCESS_KEY',
secretAccessKey: 'YOUR_SECRET_KEY'
}
}
}
}
});Validation
The library uses Zod for validation of configuration and data:
import { mongodbConfigSchema, validateSchema } from 'permas-database-adapter';
// This will throw a detailed error if invalid
const validConfig = validateSchema(
mongodbConfigSchema,
{
uri: 'mongodb://localhost:27017/mydb',
options: { useNewUrlParser: true }
},
'Invalid MongoDB configuration'
);Error Handling
All errors are standardized:
import { DatabaseAdapterError, DatabaseErrorType } from 'permas-database-adapter';
try {
await db.findById('users', 'invalid-id');
} catch (error) {
if (error instanceof DatabaseAdapterError) {
console.log(error.type); // e.g., DatabaseErrorType.NOT_FOUND
console.log(error.message); // Descriptive error message
// Handle different error types
switch (error.type) {
case DatabaseErrorType.CONNECTION:
// Handle connection errors
break;
case DatabaseErrorType.VALIDATION:
// Handle validation errors
break;
// etc.
}
}
}Browser Usage
For security reasons, direct database access from browsers is not recommended. However, you can use the library's types and validation utilities:
import { DatabaseAdapter } from 'permas-database-adapter';
// Define your API client that implements the DatabaseAdapter interface
class ApiClient implements DatabaseAdapter {
// ...implement the methods by calling your backend API
}Supported Database Features
Check if a specific feature is supported:
if (db.supportsFeature('transactions')) {
// Use transactions
}API Reference
DatabaseAdapter Interface
All database adapters implement the following interface:
interface DatabaseAdapter {
// Connect to the database
connect(): Promise<void>;
// Disconnect from the database
disconnect(): Promise<void>;
// Check if connected to the database
isConnected(): boolean;
// Create a new item
create<T>(collection: string, data: Partial<T>): Promise<T>;
// Find items with optional filters and pagination
find<T>(collection: string, options?: FindOptions): Promise<PaginatedResult<T>>;
// Find a single item by ID
findById<T>(collection: string, id: string): Promise<T | null>;
// Find a single item by custom filter
findOne<T>(collection: string, filter: Record<string, any>): Promise<T | null>;
// Update an item by ID
updateById<T>(collection: string, id: string, data: Partial<T>): Promise<T | null>;
// Delete an item by ID
deleteById(collection: string, id: string): Promise<boolean>;
// Count documents matching a filter
count(collection: string, filter?: Record<string, any>): Promise<number>;
// Get the native client/driver for direct operations
getNativeClient(): any;
}Extended Methods in CosmosMongoDBAdapter
The CosmosMongoDBAdapter implements additional methods specifically for working with Azure Cosmos DB:
interface CosmosMongoDBAdapter extends DatabaseAdapter {
// Update a specific element within an array field
updateArrayField<T>(
collection: string,
id: string,
arrayField: string,
arrayItemFilter: Record<string, unknown>,
updateData: Record<string, unknown>
): Promise<T | null>;
// Update all items in an array field
updateAllArrayItems<T>(
collection: string,
id: string,
arrayField: string,
updateData: Record<string, unknown>
): Promise<T | null>;
// Get the MongoDB collection object for direct operations
getCollection(collection: string): Collection;
}Adapters
createDatabaseAdapter(provider, config)- Create a database adaptercreateMultiDatabaseAdapter(config)- Create a multi-database adaptercreateCosmosMongoDBAdapter(config)- Create an Azure Cosmos DB with MongoDB API adapter
Database Providers
DatabaseProvider.MONGODB- MongoDB adapterDatabaseProvider.COSMOS_MONGODB- Azure Cosmos DB with MongoDB API adapterDatabaseProvider.COSMOSDB- Azure CosmosDB native adapterDatabaseProvider.DYNAMODB- AWS DynamoDB adapterDatabaseProvider.SUPABASE- Supabase adapter
Core Methods
connect()- Connect to the databasedisconnect()- Disconnect from the databaseisConnected()- Check if connected to the databasecreate(collection, data)- Create a documentfind(collection, options)- Find documentsfindById(collection, id)- Find a document by IDfindOne(collection, filter)- Find a document by filterupdateById(collection, id, data)- Update a document by IDdeleteById(collection, id)- Delete a document by IDcount(collection, filter)- Count documentsgetNativeClient()- Get the native database clientsupportsFeature(feature)- Check if a feature is supported
License
MIT
