Data - SQL Database
Managed PostgreSQL databases with full SQL support, transactions, and automatic backups for relational data storage.
Overview
Data provides managed PostgreSQL databases optimized for AI applications:
- Full SQL support with transactions
- Automatic daily backups
- Connection pooling
- Schema management
- Batch query execution
Quick Start
import { Tenzro } from '@tenzro/cloud';const client = new Tenzro({apiKey: process.env.TENZRO_API_KEY,projectId: 'your-project-id',});// Get database by nameconst db = await client.data.db('my-app');// Create a table (SQL or raw queries)await db.execute(`CREATE TABLE IF NOT EXISTS users (id SERIAL PRIMARY KEY,email VARCHAR(255) UNIQUE NOT NULL,name VARCHAR(255),created_at TIMESTAMP DEFAULT NOW())`);// Insert data (ORM-style)await db.insert('users', {email: 'john@example.com',name: 'John Doe',});// Query data (ORM-style)const users = await db.findMany('users', {where: { email: 'john@example.com' },});console.log(users[0]); // { id: 1, email: 'john@example.com', ... }
SDK Reference
Get Database
// Get existing database by nameconst db = await client.data.db('my-app');
ORM-Style Operations
Find Many
const users = await db.findMany<User>('users', {where: { isActive: true },orderBy: { column: 'createdAt', direction: 'DESC' },limit: 10,offset: 0,});
Find One
const user = await db.findOne<User>('users', {where: { id: '123' }});
Insert
const newUser = await db.insert('users', {email: 'alice@example.com',name: 'Alice',});
Update
const updated = await db.update('users',{ isActive: false }, // Data to update{ id: '123' } // Where clause);
Delete
const deleted = await db.deleteRows('users', { id: '123' });
Count
const count = await db.count('users');const activeCount = await db.count('users', { isActive: true });
Raw SQL Execution
Execute Query
const result = await db.execute('SELECT * FROM users WHERE age > $1',[18]);// Result type:interface QueryResult {rows: any[];rowCount: number;fields: { name: string; dataType: string }[];executionTimeMs: number;}
Column Types
| Type | Description | Example |
|---|---|---|
SERIAL | Auto-incrementing integer | Primary keys |
INTEGER | 32-bit integer | Counts, IDs |
BIGINT | 64-bit integer | Large numbers |
DECIMAL(p,s) | Exact decimal | Money, prices |
VARCHAR(n) | Variable string | Names, emails |
TEXT | Unlimited string | Descriptions |
BOOLEAN | True/false | Flags |
TIMESTAMP | Date and time | Created/updated |
JSONB | Binary JSON | Flexible data |
UUID | Unique identifier | External IDs |
Transactions
Execute multiple queries atomically:
// Using batch with implicit transactionconst results = await tenzro.data.batch(dataDbId, [{ sql: 'BEGIN' },{ sql: 'INSERT INTO orders (user_id, total) VALUES ($1, $2)', params: [1, 99.99] },{ sql: 'UPDATE inventory SET quantity = quantity - 1 WHERE product_id = $1', params: [1] },{ sql: 'COMMIT' },]);// Or using single query with transaction flagawait tenzro.data.query(dataDbId, `INSERT INTO orders (user_id, total) VALUES ($1, $2);UPDATE inventory SET quantity = quantity - 1 WHERE product_id = $3;`, [1, 99.99, 1], true);
Examples
User Management
// Create users tableawait tenzro.data.createTable(dataDbId, 'users', [{ name: 'id', type: 'UUID', primaryKey: true, default: 'gen_random_uuid()' },{ name: 'email', type: 'VARCHAR(255)', unique: true, nullable: false },{ name: 'password_hash', type: 'VARCHAR(255)', nullable: false },{ name: 'name', type: 'VARCHAR(255)' },{ name: 'metadata', type: 'JSONB', default: "'{}'" },{ name: 'created_at', type: 'TIMESTAMP', default: 'NOW()' },{ name: 'updated_at', type: 'TIMESTAMP', default: 'NOW()' },]);// Register userasync function registerUser(email: string, passwordHash: string, name: string) {const { rows } = await tenzro.data.query(dataDbId, `INSERT INTO users (email, password_hash, name)VALUES ($1, $2, $3)RETURNING id, email, name, created_at`, [email, passwordHash, name]);return rows[0];}// Find user by emailasync function findUserByEmail(email: string) {const { rows } = await tenzro.data.query(dataDbId, `SELECT * FROM users WHERE email = $1`, [email]);return rows[0] || null;}
Agent Memory Storage
// Create conversation tableawait tenzro.data.createTable(dataDbId, 'conversations', [{ name: 'id', type: 'UUID', primaryKey: true, default: 'gen_random_uuid()' },{ name: 'agent_id', type: 'VARCHAR(255)', nullable: false },{ name: 'user_id', type: 'VARCHAR(255)', nullable: false },{ name: 'created_at', type: 'TIMESTAMP', default: 'NOW()' },]);await tenzro.data.createTable(dataDbId, 'messages', [{ name: 'id', type: 'UUID', primaryKey: true, default: 'gen_random_uuid()' },{ name: 'conversation_id', type: 'UUID', references: { table: 'conversations', column: 'id' } },{ name: 'role', type: 'VARCHAR(20)', nullable: false },{ name: 'content', type: 'TEXT', nullable: false },{ name: 'metadata', type: 'JSONB', default: "'{}'" },{ name: 'created_at', type: 'TIMESTAMP', default: 'NOW()' },]);// Get conversation historyasync function getConversationHistory(conversationId: string, limit = 50) {const { rows } = await tenzro.data.query(dataDbId, `SELECT role, content, metadata, created_atFROM messagesWHERE conversation_id = $1ORDER BY created_at DESCLIMIT $2`, [conversationId, limit]);return rows.reverse();}
Best Practices
- Use parameterized queries: Always use
$1, $2placeholders to prevent SQL injection - Index frequently queried columns: Create indexes for columns in WHERE clauses
- Use JSONB for flexible data: Store variable metadata in JSONB columns
- Connection pooling: Set appropriate
maxConnectionsfor your workload - Batch operations: Use batch queries for multiple related operations
Limits
| Resource | Limit |
|---|---|
| Max connections per database | 100 |
| Max query result size | 100 MB |
| Max queries per batch | 100 |
| Query timeout | 30 seconds |
| Max database size | 100 GB |