←Back to Documentation
JavaScript/TypeScript SDK
Official Node.js and browser client for entropyDB
Installation
# npm npm install @entropydb/client # yarn yarn add @entropydb/client # pnpm pnpm add @entropydb/client
Quick Start
import { EntropyClient } from '@entropydb/client';
// Connect to entropyDB
const client = new EntropyClient({
host: 'localhost',
port: 5432,
database: 'mydb',
user: 'admin',
password: 'password',
});
await client.connect();
// Execute a query
const result = await client.query(
'SELECT * FROM users WHERE id = $1',
[123]
);
console.log(result.rows);
// Close connection
await client.close();Connection Management
Connection Pooling
import { Pool } from '@entropydb/client';
const pool = new Pool({
host: 'localhost',
port: 5432,
database: 'mydb',
user: 'admin',
password: 'password',
max: 20, // Maximum pool size
idleTimeoutMillis: 30000,
connectionTimeoutMillis: 2000,
});
// Automatic connection management
const result = await pool.query('SELECT NOW()');
// Get a client from pool for transactions
const client = await pool.connect();
try {
await client.query('BEGIN');
await client.query('INSERT INTO users...');
await client.query('COMMIT');
} catch (e) {
await client.query('ROLLBACK');
throw e;
} finally {
client.release();
}
// Shutdown pool
await pool.end();Environment Variables
// .env file
ENTROPYDB_HOST=localhost
ENTROPYDB_PORT=5432
ENTROPYDB_DATABASE=mydb
ENTROPYDB_USER=admin
ENTROPYDB_PASSWORD=secret
// Use in code
import { EntropyClient } from '@entropydb/client';
const client = new EntropyClient({
connectionString: process.env.DATABASE_URL,
// or individual vars
host: process.env.ENTROPYDB_HOST,
port: parseInt(process.env.ENTROPYDB_PORT),
// ...
});Query Execution
Parameterized Queries
// Always use parameterized queries to prevent SQL injection
const result = await client.query(
'SELECT * FROM users WHERE email = $1 AND active = $2',
['user@example.com', true]
);
// Access results
console.log(result.rows); // Array of rows
console.log(result.rowCount); // Number of rows
console.log(result.fields); // Column metadata
// Iterate over rows
for (const row of result.rows) {
console.log(row.name, row.email);
}Named Parameters
// Use named parameters for clarity
const result = await client.query({
text: 'SELECT * FROM users WHERE email = $email AND status = $status',
values: {
email: 'user@example.com',
status: 'active'
}
});Prepared Statements
// Create prepared statement const prepared = await client.prepare( 'get_user', 'SELECT * FROM users WHERE id = $1' ); // Execute multiple times const result1 = await prepared.execute([123]); const result2 = await prepared.execute([456]); // Deallocate when done await prepared.deallocate();
Transactions
// Manual transaction control
await client.query('BEGIN');
try {
await client.query('UPDATE accounts SET balance = balance - $1 WHERE id = $2', [100, 1]);
await client.query('UPDATE accounts SET balance = balance + $1 WHERE id = $2', [100, 2]);
await client.query('COMMIT');
} catch (error) {
await client.query('ROLLBACK');
throw error;
}
// Helper method
await client.transaction(async (tx) => {
await tx.query('UPDATE accounts SET balance = balance - $1 WHERE id = $2', [100, 1]);
await tx.query('UPDATE accounts SET balance = balance + $1 WHERE id = $2', [100, 2]);
// Auto-commits on success, rolls back on error
});
// Savepoints
await client.transaction(async (tx) => {
await tx.query('INSERT INTO logs...');
const savepoint = await tx.savepoint('sp1');
try {
await tx.query('INSERT INTO orders...');
} catch (error) {
await savepoint.rollback();
}
await savepoint.release();
});JSON and Document Queries
// Insert JSON data
await client.query(
'INSERT INTO users (name, profile) VALUES ($1, $2)',
['John Doe', { age: 30, city: 'NYC', preferences: { theme: 'dark' } }]
);
// Query JSON fields
const result = await client.query(`
SELECT
name,
profile->>'city' as city,
profile->'preferences'->>'theme' as theme
FROM users
WHERE profile @> $1
`, [{ city: 'NYC' }]);
// Update nested JSON
await client.query(`
UPDATE users
SET profile = jsonb_set(profile, '{preferences,theme}', $1)
WHERE id = $2
`, ['"light"', 123]);
// Type-safe JSON handling
interface UserProfile {
age: number;
city: string;
preferences: {
theme: 'light' | 'dark';
notifications: boolean;
};
}
const result = await client.query<{ name: string; profile: UserProfile }>(
'SELECT name, profile FROM users WHERE id = $1',
[123]
);
const profile: UserProfile = result.rows[0].profile;Vector Operations
// Insert vectors
await client.query(
'INSERT INTO documents (title, embedding) VALUES ($1, $2)',
['My Document', [0.1, 0.2, 0.3, /* ... */]]
);
// Similarity search
const queryEmbedding = [0.15, 0.25, 0.35, /* ... */];
const results = await client.query(`
SELECT
id,
title,
1 - (embedding <=> $1::vector) as similarity
FROM documents
ORDER BY embedding <=> $1::vector
LIMIT 10
`, [queryEmbedding]);
// Hybrid search (vector + text)
const results = await client.query(`
SELECT
id,
title,
(0.7 * (1 - (embedding <=> $1::vector))) +
(0.3 * ts_rank(search_vector, to_tsquery($2))) as score
FROM documents
WHERE search_vector @@ to_tsquery($2)
ORDER BY score DESC
LIMIT 20
`, [queryEmbedding, 'database & performance']);Streaming Large Result Sets
// Stream results for memory efficiency
const stream = client.stream('SELECT * FROM large_table');
stream.on('data', (row) => {
console.log(row);
// Process one row at a time
});
stream.on('end', () => {
console.log('Finished streaming');
});
stream.on('error', (error) => {
console.error('Stream error:', error);
});
// Async iterator support
for await (const row of client.stream('SELECT * FROM large_table')) {
console.log(row);
// Process rows as they arrive
}TypeScript Support
// Define your schema types
interface User {
id: number;
name: string;
email: string;
created_at: Date;
profile: {
age: number;
city: string;
};
}
// Type-safe queries
const result = await client.query<User>(
'SELECT * FROM users WHERE id = $1',
[123]
);
// TypeScript knows the shape
const user: User = result.rows[0];
console.log(user.name); // ✓ Type-safe
console.log(user.profile.city); // ✓ Type-safe
// Query builder with types
import { QueryBuilder } from '@entropydb/client';
const qb = new QueryBuilder<User>('users');
const query = qb
.select(['id', 'name', 'email'])
.where('active', '=', true)
.orderBy('created_at', 'DESC')
.limit(10)
.build();
const result = await client.query<Pick<User, 'id' | 'name' | 'email'>>(
query.text,
query.values
);Error Handling
import {
DatabaseError,
ConnectionError,
QueryError
} from '@entropydb/client';
try {
await client.query('SELECT * FROM users WHERE id = $1', [123]);
} catch (error) {
if (error instanceof ConnectionError) {
console.error('Connection failed:', error.message);
// Retry logic
} else if (error instanceof QueryError) {
console.error('Query failed:', error.message);
console.error('Query:', error.query);
console.error('SQL State:', error.code);
} else if (error instanceof DatabaseError) {
console.error('Database error:', error.message);
}
}
// Specific error codes
try {
await client.query('INSERT INTO users (email) VALUES ($1)', ['duplicate@example.com']);
} catch (error) {
if (error.code === '23505') { // Unique violation
console.error('Email already exists');
}
}Best Practices
1. Use Connection Pooling
Always use a connection pool in production for better performance and resource management.
2. Parameterize All Queries
Never use string concatenation for query values. Always use $1, $2, etc.
3. Handle Errors Gracefully
Always wrap queries in try-catch blocks and handle specific error types.
4. Close Connections
Release pooled connections after use and close pools on shutdown.
5. Use TypeScript
Leverage TypeScript for type safety and better IDE support.