@seawingai/wingdb
v1.0.0
Published
A json, csv, file, folder based database for fast MVP & SaaS development
Maintainers
Readme
WingDb
A lightweight, file-based database library for fast MVP and SaaS development. WingDb provides multiple storage providers (JSON, CSV, files, folders) with a simple, unified API for rapid prototyping and small to medium-scale applications.
Features
- 📁 Multiple Storage Providers: JSON, CSV, files, and folder-based storage
- ⚡ Lightweight & Fast: No external database dependencies
- 🔧 TypeScript Support: Full type definitions and IntelliSense
- 🎯 Simple API: Easy-to-use interface for common database operations
- 🧪 Comprehensive Testing: Well-tested with Jest
- 📊 Flexible Data Models: Support for structured and unstructured data
- 🔄 Auto-backup: Built-in backup functionality
- 📝 Logging: Integrated logging with WingLog
Installation
npm install @seawingai/wingdb
# or
pnpm add @seawingai/wingdb
# or
yarn add @seawingai/wingdbQuick Start
import { WingDb, JsonTable, FileTable } from '@seawingai/wingdb';
// Create a custom database class
class MyDatabase extends WingDb {
get tables() {
return {
users: { ctor: JsonTable, file: 'users.json' },
config: { ctor: FileTable, file: 'config' }
};
}
}
// Initialize database
const db = new MyDatabase('./data');
// Load all tables
await db.load();
// Save user data
await db.setItem('users', 'user1', JSON.stringify({
id: 'user1',
name: 'John Doe',
email: '[email protected]'
}));
// Get user data
const userData = await db.get('users');
console.log(userData);Storage Providers
1. JsonTable - JSON-based Storage
Perfect for structured data with IDs.
import { JsonTable } from '@seawingai/wingdb';
// Define your data type
interface User {
id: string;
name: string;
email: string;
age?: number;
}
// Create table instance
const usersTable = new JsonTable<User>(db, 'users.json');
// Load data
await usersTable.load();
// Add user
usersTable.set({
id: 'user1',
name: 'John Doe',
email: '[email protected]',
age: 30
});
// Get user by ID
const user = usersTable.get('user1');
// Filter users
const youngUsers = usersTable.filter({ age: 30 });
// Save to file
await usersTable.save();2. DelimitedTable - CSV-based Storage
Ideal for tabular data and spreadsheet-like operations.
import { DelimitedTable } from '@seawingai/wingdb';
// Create CSV table
const csvTable = new DelimitedTable('./data/employees.csv', ',', [
'id', 'name', 'department', 'salary'
]);
// Load CSV data
await csvTable.load();
// Add employee
csvTable.set({
id: 'emp1',
name: 'Jane Smith',
department: 'Engineering',
salary: '75000'
});
// Save as CSV
await csvTable.save();3. FileTable - File-based Storage
Store individual files with metadata.
import { FileTable } from '@seawingai/wingdb';
// Create file table for text files
const textFiles = new FileTable(db, 'documents', '.txt');
// Load all .txt files
await textFiles.load();
// Set file content
textFiles.set('readme', 'This is the README content');
// Get file content
const content = textFiles.get('readme');
// Save all files
await textFiles.save();4. FolderTable - Folder-based Storage
Manage folder structures and paths.
import { FolderTable } from '@seawingai/wingdb';
// Create folder table
const projects = new FolderTable(db, 'projects');
// Load folder structure
await projects.load();
// Add project folder
projects.set('project1', '/path/to/project1');
// Get project path
const projectPath = projects.get('project1');
// Save folder structure
await projects.save();Advanced Usage
Custom Database Implementation
import { WingDb, JsonTable, FileTable } from '@seawingai/wingdb';
class BlogDatabase extends WingDb {
get tables() {
return {
posts: { ctor: JsonTable, file: 'posts.json' },
users: { ctor: JsonTable, file: 'users.json' },
assets: { ctor: FileTable, file: 'assets' },
uploads: { ctor: FolderTable, file: 'uploads' }
};
}
// Custom methods
async getPost(id: string) {
const postsTable = this.getJsonTable('posts');
await postsTable.load();
return postsTable.get(id);
}
async createPost(post: any) {
const postsTable = this.getJsonTable('posts');
await postsTable.load();
postsTable.set(post);
await postsTable.save();
}
async getPostsByAuthor(authorId: string) {
const postsTable = this.getJsonTable('posts');
await postsTable.load();
return postsTable.filter({ authorId });
}
}
// Usage
const blogDb = new BlogDatabase('./blog-data');
await blogDb.load();
// Create post
await blogDb.createPost({
id: 'post1',
title: 'My First Post',
content: 'Hello World!',
authorId: 'user1',
createdAt: new Date().toISOString()
});
// Get post
const post = await blogDb.getPost('post1');Data Filtering and Queries
// Filter by multiple criteria
const activeUsers = usersTable.filter({
status: 'active',
age: 25
});
// Get all items
const allUsers = usersTable.filter({});
// Complex filtering (custom implementation)
const premiumUsers = Array.from(usersTable).filter(user =>
user.subscription === 'premium' && user.lastLogin > '2024-01-01'
);Backup and Recovery
// Automatic backup on save
await usersTable.save(true);
// Manual backup
await usersTable.backup('./backups/users-backup.json');
// Load from backup
const backupTable = new JsonTable(db, 'backup-users.json');
await backupTable.load();Error Handling
try {
await db.load();
await db.setItem('users', 'user1', userData);
} catch (error) {
console.error('Database operation failed:', error);
// Handle error appropriately
}API Reference
WingDb (Abstract Base Class)
Constructor
constructor(dbPath: string)Methods
load(): Promise<void>- Load all tablesloadTable(tableName: string): Promise<void>- Load specific tableget(tableName: string): Promise<any>- Get table data as JSONset(tableName: string, json: string): Promise<void>- Set table data from JSONsetItem(tableName: string, id: string, json: string): Promise<void>- Set individual item
Protected Methods
getTable(tableName: string): any- Get table instancegetJsonTable<T>(tableName: string): JsonTable<T>- Get JSON tablegetFileTable(tableName: string): FileTable- Get file table
JsonTable
Methods
load(create?: boolean): Promise<T[]>- Load data from filesave(backup?: boolean): Promise<void>- Save data to fileget(id: string): T | undefined- Get item by IDset(row: T, unique?: boolean): boolean- Set itemfilter(filters: Record<string, any>): T[]- Filter itemsclear(): Promise<void>- Clear all databackup(path: string): Promise<void>- Create backup
DelimitedTable
Methods
load(create?: boolean): Promise<T[]>- Load CSV datasave(): Promise<void>- Save as CSVset(row: T, unique?: boolean): boolean- Add rowget(id: string): T | undefined- Get row by ID
FileTable
Methods
load(): Promise<void>- Load filessave(): Promise<void>- Save filesget(key: string): string | undefined- Get file contentset(key: string, value: string): void- Set file contenttoJson(): Promise<string>- Export as JSON
FolderTable
Methods
load(create?: boolean): Promise<void>- Load folder structuresave(): Promise<void>- Save folder structureget(id: string): T | undefined- Get folder pathset(key: string, value: string): void- Set folder pathtoJson(): Promise<string>- Export as JSON
Examples
E-commerce Application
class EcommerceDB extends WingDb {
get tables() {
return {
products: { ctor: JsonTable, file: 'products.json' },
orders: { ctor: JsonTable, file: 'orders.json' },
customers: { ctor: JsonTable, file: 'customers.json' },
images: { ctor: FileTable, file: 'images' }
};
}
async addProduct(product: any) {
const productsTable = this.getJsonTable('products');
await productsTable.load();
productsTable.set(product);
await productsTable.save();
}
async getProductsByCategory(category: string) {
const productsTable = this.getJsonTable('products');
await productsTable.load();
return productsTable.filter({ category });
}
}Task Management System
class TaskDB extends WingDb {
get tables() {
return {
tasks: { ctor: JsonTable, file: 'tasks.json' },
projects: { ctor: JsonTable, file: 'projects.json' },
attachments: { ctor: FileTable, file: 'attachments' }
};
}
async getTasksByStatus(status: string) {
const tasksTable = this.getJsonTable('tasks');
await tasksTable.load();
return tasksTable.filter({ status });
}
async addTaskAttachment(taskId: string, filename: string, content: string) {
const attachmentsTable = this.getFileTable('attachments');
attachmentsTable.set(`${taskId}_${filename}`, content);
await attachmentsTable.save();
}
}Best Practices
- Always load tables before use: Call
load()orloadTable()before accessing data - Handle errors gracefully: Wrap database operations in try-catch blocks
- Use TypeScript interfaces: Define proper types for your data structures
- Regular backups: Enable automatic backups for critical data
- Organize your data: Use meaningful table names and file structures
- Monitor performance: For large datasets, consider data pagination
Limitations
- Not suitable for high-concurrency: File-based storage has limitations for concurrent writes
- No ACID transactions: No built-in transaction support
- Limited scalability: Best for small to medium datasets
- No built-in indexing: Complex queries may be slower
Contributing
We welcome contributions! Please see our Contributing Guide for details.
License
This project is licensed under the Apache License 2.0 - see the LICENSE file for details.
Support
Made with ❤️ by SeaWingAI
