NPM Installation
Install MatsushibaDB for Node.js applications using NPM. Perfect for web applications, APIs, and server-side development.Installation
Basic Installation
Copy
npm install matsushibadb
Global Installation (CLI Tools)
Copy
npm install -g matsushibadb
Development Dependencies
Copy
npm install --save-dev matsushibadb
Quick Start
Copy
const MatsushibaDB = require('matsushibadb');
// Create a new database
const db = new MatsushibaDB('app.db');
// Create a table
db.run(`
CREATE TABLE users (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
email TEXT UNIQUE NOT NULL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
)
`);
// Insert data
db.run('INSERT INTO users (name, email) VALUES (?, ?)',
['John Doe', '[email protected]']);
// Query data
const users = db.all('SELECT * FROM users');
console.log('Users:', users);
// Close the database
db.close();
Configuration Options
Basic Configuration
Copy
const MatsushibaDB = require('matsushibadb');
const db = new MatsushibaDB('app.db', {
// Enable WAL mode for better concurrency
enableWAL: true,
// Set cache size (in pages)
cacheSize: 2000,
// Synchronous mode
synchronous: 'NORMAL',
// Journal mode
journalMode: 'WAL',
// Temporary storage
tempStore: 'MEMORY',
// Foreign key constraints
foreignKeys: true
});
Advanced Configuration
Copy
const db = new MatsushibaDB('app.db', {
// Performance settings
performance: {
enableWAL: true,
cacheSize: 5000,
synchronous: 'NORMAL',
journalMode: 'WAL',
tempStore: 'MEMORY',
optimizeQueries: true,
preparedStatementCache: true,
preparedStatementCacheSize: 100
},
// Memory optimization
memory: {
mmapSize: 268435456, // 256MB
optimizeMemory: true,
gcThreshold: 1000
},
// I/O optimization
io: {
directIO: true,
optimizeIO: true,
bufferSize: 65536 // 64KB
},
// Security settings
security: {
enableEncryption: true,
encryptionKey: process.env.DB_ENCRYPTION_KEY,
enableAuditLogging: true
}
});
Connection Pooling
For production applications, use connection pooling:Copy
const { MatsushibaPool } = require('matsushibadb');
const pool = new MatsushibaPool({
database: 'app.db',
min: 5, // Minimum connections
max: 20, // Maximum connections
acquireTimeoutMillis: 30000,
createTimeoutMillis: 30000,
destroyTimeoutMillis: 5000,
idleTimeoutMillis: 30000,
reapIntervalMillis: 1000,
createRetryIntervalMillis: 200,
propagateCreateError: false
});
// Use the pool
async function getUsers() {
const connection = await pool.acquire();
try {
const users = connection.all('SELECT * FROM users WHERE active = 1');
return users;
} finally {
pool.release(connection);
}
}
// Transaction with pool
async function createUserWithProfile(userData, profileData) {
const connection = await pool.acquire();
try {
await connection.beginTransaction();
const userResult = connection.run(`
INSERT INTO users (name, email, password_hash)
VALUES (?, ?, ?)
`, [userData.name, userData.email, userData.passwordHash]);
const profileResult = connection.run(`
INSERT INTO profiles (user_id, bio, avatar_url)
VALUES (?, ?, ?)
`, [userResult.lastInsertRowid, profileData.bio, profileData.avatarUrl]);
await connection.commit();
return { userId: userResult.lastInsertRowid, profileId: profileResult.lastInsertRowid };
} catch (error) {
await connection.rollback();
throw error;
} finally {
pool.release(connection);
}
}
Async/Await Support
MatsushibaDB provides full async/await support:Copy
const MatsushibaDB = require('matsushibadb');
async function asyncExample() {
const db = new MatsushibaDB('async-app.db');
try {
// Async operations
await db.run(`
CREATE TABLE IF NOT EXISTS products (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
price DECIMAL(10,2),
stock INTEGER DEFAULT 0
)
`);
// Insert with async
const result = await db.run(`
INSERT INTO products (name, price, stock)
VALUES (?, ?, ?)
`, ['Laptop', 999.99, 10]);
console.log('Product created with ID:', result.lastInsertRowid);
// Query with async
const products = await db.all('SELECT * FROM products WHERE stock > 0');
console.log('Available products:', products);
// Get single record with async
const product = await db.get('SELECT * FROM products WHERE id = ?', [result.lastInsertRowid]);
console.log('Product details:', product);
} catch (error) {
console.error('Database error:', error);
} finally {
await db.close();
}
}
asyncExample();
Express.js Integration
Basic Express Setup
Copy
const express = require('express');
const MatsushibaDB = require('matsushibadb');
const cors = require('cors');
const helmet = require('helmet');
const app = express();
const db = new MatsushibaDB('express-app.db');
// Middleware
app.use(helmet());
app.use(cors());
app.use(express.json());
// Database initialization
function initializeDatabase() {
db.run(`
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
email TEXT UNIQUE NOT NULL,
password_hash TEXT NOT NULL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
)
`);
db.run(`
CREATE TABLE IF NOT EXISTS posts (
id INTEGER PRIMARY KEY,
title TEXT NOT NULL,
content TEXT,
author_id INTEGER,
published BOOLEAN DEFAULT 0,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (author_id) REFERENCES users(id)
)
`);
// Create indexes
db.run('CREATE INDEX IF NOT EXISTS idx_users_email ON users(email)');
db.run('CREATE INDEX IF NOT EXISTS idx_posts_author ON posts(author_id)');
db.run('CREATE INDEX IF NOT EXISTS idx_posts_published ON posts(published)');
}
// Routes
app.get('/api/health', (req, res) => {
res.json({
status: 'healthy',
timestamp: new Date().toISOString(),
database: 'connected'
});
});
app.post('/api/users', async (req, res) => {
try {
const { name, email, password } = req.body;
if (!name || !email || !password) {
return res.status(400).json({ error: 'Name, email, and password are required' });
}
const existingUser = db.get('SELECT * FROM users WHERE email = ?', [email]);
if (existingUser) {
return res.status(409).json({ error: 'User with this email already exists' });
}
const bcrypt = require('bcrypt');
const passwordHash = bcrypt.hashSync(password, 10);
const result = db.run(`
INSERT INTO users (name, email, password_hash)
VALUES (?, ?, ?)
`, [name, email, passwordHash]);
const user = db.get('SELECT * FROM users WHERE id = ?', [result.lastInsertRowid]);
res.status(201).json({
id: user.id,
name: user.name,
email: user.email,
createdAt: user.created_at
});
} catch (error) {
console.error('Error creating user:', error);
res.status(500).json({ error: 'Internal server error' });
}
});
app.get('/api/posts', async (req, res) => {
try {
const published = req.query.published !== 'false';
const posts = db.all(`
SELECT p.*, u.name as author_name
FROM posts p
JOIN users u ON p.author_id = u.id
WHERE p.published = ?
ORDER BY p.created_at DESC
`, [published ? 1 : 0]);
res.json(posts);
} catch (error) {
console.error('Error fetching posts:', error);
res.status(500).json({ error: 'Internal server error' });
}
});
// Start server
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
initializeDatabase();
});
Advanced Express Integration
Copy
// Advanced Express setup with middleware and error handling
const express = require('express');
const MatsushibaDB = require('matsushibadb');
const { MatsushibaPool } = require('matsushibadb');
const rateLimit = require('express-rate-limit');
const compression = require('compression');
const app = express();
// Connection pool
const pool = new MatsushibaPool({
database: 'production-app.db',
min: 5,
max: 20,
acquireTimeoutMillis: 30000
});
// Middleware
app.use(compression());
app.use(express.json({ limit: '10mb' }));
app.use(express.urlencoded({ extended: true }));
// Rate limiting
const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 1000, // limit each IP to 1000 requests per windowMs
message: 'Too many requests from this IP'
});
app.use('/api/', limiter);
// Database middleware
app.use((req, res, next) => {
req.db = pool;
next();
});
// Error handling middleware
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).json({ error: 'Something went wrong!' });
});
// Routes with connection pooling
app.get('/api/users/:id', async (req, res) => {
const connection = await req.db.acquire();
try {
const user = connection.get('SELECT * FROM users WHERE id = ?', [req.params.id]);
if (!user) {
return res.status(404).json({ error: 'User not found' });
}
res.json(user);
} catch (error) {
console.error('Error fetching user:', error);
res.status(500).json({ error: 'Internal server error' });
} finally {
req.db.release(connection);
}
});
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});
CLI Tools
MatsushibaDB includes powerful CLI tools:Copy
# Initialize a new database
matsushiba init my-database.db
# Create a table
matsushiba create-table users "id INTEGER PRIMARY KEY, name TEXT, email TEXT"
# Insert data
matsushiba insert users "name='John Doe', email='[email protected]'"
# Query data
matsushiba query "SELECT * FROM users"
# Export data
matsushiba export users --format json --output users.json
# Import data
matsushiba import users --format json --input users.json
# Backup database
matsushiba backup my-database.db --output backup.db
# Restore database
matsushiba restore backup.db --output restored.db
# Performance analysis
matsushiba analyze my-database.db
# Database statistics
matsushiba stats my-database.db
Testing
Unit Testing with Jest
Copy
const MatsushibaDB = require('matsushibadb');
describe('MatsushibaDB Tests', () => {
let db;
beforeEach(() => {
db = new MatsushibaDB(':memory:'); // In-memory database for tests
db.run(`
CREATE TABLE users (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
email TEXT UNIQUE NOT NULL
)
`);
});
afterEach(() => {
db.close();
});
test('should create a user', () => {
const result = db.run('INSERT INTO users (name, email) VALUES (?, ?)',
['John Doe', '[email protected]']);
expect(result.lastInsertRowid).toBe(1);
expect(result.changes).toBe(1);
});
test('should retrieve users', () => {
db.run('INSERT INTO users (name, email) VALUES (?, ?)',
['John Doe', '[email protected]']);
const users = db.all('SELECT * FROM users');
expect(users).toHaveLength(1);
expect(users[0].name).toBe('John Doe');
expect(users[0].email).toBe('[email protected]');
});
test('should handle unique constraints', () => {
db.run('INSERT INTO users (name, email) VALUES (?, ?)',
['John Doe', '[email protected]']);
expect(() => {
db.run('INSERT INTO users (name, email) VALUES (?, ?)',
['Jane Doe', '[email protected]']);
}).toThrow();
});
});
Integration Testing
Copy
const request = require('supertest');
const express = require('express');
const MatsushibaDB = require('matsushibadb');
describe('API Integration Tests', () => {
let app;
let db;
beforeAll(() => {
app = express();
db = new MatsushibaDB(':memory:');
// Setup routes
app.use(express.json());
app.post('/api/users', (req, res) => {
const { name, email } = req.body;
const result = db.run('INSERT INTO users (name, email) VALUES (?, ?)',
[name, email]);
res.status(201).json({ id: result.lastInsertRowid, name, email });
});
app.get('/api/users', (req, res) => {
const users = db.all('SELECT * FROM users');
res.json(users);
});
});
afterAll(() => {
db.close();
});
test('should create user via API', async () => {
const response = await request(app)
.post('/api/users')
.send({ name: 'John Doe', email: '[email protected]' })
.expect(201);
expect(response.body.name).toBe('John Doe');
expect(response.body.email).toBe('[email protected]');
});
test('should retrieve users via API', async () => {
db.run('INSERT INTO users (name, email) VALUES (?, ?)',
['John Doe', '[email protected]']);
const response = await request(app)
.get('/api/users')
.expect(200);
expect(response.body).toHaveLength(1);
expect(response.body[0].name).toBe('John Doe');
});
});
Performance Optimization
Query Optimization
Copy
// Use prepared statements for repeated queries
const getUserStmt = db.prepare('SELECT * FROM users WHERE id = ?');
const user = getUserStmt.get(1);
// Use indexes for better performance
db.run('CREATE INDEX IF NOT EXISTS idx_users_email ON users(email)');
db.run('CREATE INDEX IF NOT EXISTS idx_users_name ON users(name)');
// Batch operations
const insertUserStmt = db.prepare('INSERT INTO users (name, email) VALUES (?, ?)');
const users = [
['John Doe', '[email protected]'],
['Jane Smith', '[email protected]'],
['Bob Johnson', '[email protected]']
];
const insertMany = db.transaction((users) => {
for (const user of users) {
insertUserStmt.run(user);
}
});
insertMany(users);
Memory Management
Copy
// Use streaming for large datasets
const stmt = db.prepare('SELECT * FROM large_table');
stmt.each((row) => {
// Process each row
console.log(row);
}, () => {
// All rows processed
stmt.finalize();
});
// Clean up prepared statements
const stmt = db.prepare('SELECT * FROM users WHERE id = ?');
// ... use statement
stmt.finalize(); // Always finalize when done
Production Deployment
Environment Configuration
Copy
// config/database.js
const MatsushibaDB = require('matsushibadb');
const config = {
development: {
database: 'dev.db',
enableWAL: true,
cacheSize: 1000
},
production: {
database: process.env.DATABASE_PATH || '/data/production.db',
enableWAL: true,
cacheSize: 5000,
synchronous: 'NORMAL',
journalMode: 'WAL',
tempStore: 'MEMORY',
security: {
enableEncryption: true,
encryptionKey: process.env.DB_ENCRYPTION_KEY
}
}
};
function createDatabase(env = 'development') {
const dbConfig = config[env];
return new MatsushibaDB(dbConfig.database, dbConfig);
}
module.exports = { createDatabase };
Process Management
Copy
// Use PM2 for process management
// ecosystem.config.js
module.exports = {
apps: [{
name: 'matsushiba-app',
script: 'app.js',
instances: 'max',
exec_mode: 'cluster',
env: {
NODE_ENV: 'production',
DATABASE_PATH: '/data/production.db'
},
error_file: './logs/err.log',
out_file: './logs/out.log',
log_file: './logs/combined.log',
time: true
}]
};
Troubleshooting
Common Issues
Database Locked Error:Copy
// Handle database locked errors
try {
db.run('INSERT INTO users (name, email) VALUES (?, ?)', [name, email]);
} catch (error) {
if (error.code === 'SQLITE_BUSY') {
// Retry after a short delay
setTimeout(() => {
db.run('INSERT INTO users (name, email) VALUES (?, ?)', [name, email]);
}, 100);
} else {
throw error;
}
}
Copy
// Monitor memory usage
const used = process.memoryUsage();
console.log('Memory usage:', {
rss: Math.round(used.rss / 1024 / 1024) + ' MB',
heapTotal: Math.round(used.heapTotal / 1024 / 1024) + ' MB',
heapUsed: Math.round(used.heapUsed / 1024 / 1024) + ' MB'
});
// Force garbage collection if available
if (global.gc) {
global.gc();
}
Best Practices
1
Use Connection Pooling
Always use connection pooling for production applications to manage database connections efficiently.
2
Implement Error Handling
Wrap all database operations in try-catch blocks and handle specific error types appropriately.
3
Use Prepared Statements
Use prepared statements for repeated queries to improve performance and prevent SQL injection.
4
Optimize Queries
Create appropriate indexes and optimize queries for better performance.
5
Monitor Performance
Track query performance and database health metrics in production.
6
Regular Maintenance
Perform regular database maintenance including VACUUM and ANALYZE operations.
For production applications, always use connection pooling, implement proper error handling, and monitor database performance. Consider using environment-specific configurations and proper logging.