Direct Queries
Direct queries provide full access to all database operations through the SDK. Use this guide to understand the complete API available for database operations.
Connection Context
Establish a connection once and all subsequent operations inherit the context:
- TypeScript
- Java
- Go
- .NET
// Connect once
await ductape.database.connect({
database: 'main-db',
});
// All queries inherit context - no need to specify env/product/database
await ductape.database.query({ table: 'users' });
await ductape.database.insert({ table: 'users', data: {...} });
await ductape.database.aggregate({ table: 'orders', operations: {...} });
// Connect once
ductape.database.connect(Map.of(
"database", "main-db"
));
// All queries inherit context - no need to specify env/product/database
ductape.database.query(Map.of( "table", "users" ));
ductape.database.insert(Map.of( "table", "users", data: Map.of(...) ));
ductape.database.aggregate(Map.of( "table", "orders", operations: Map.of(...) ));
// Connect once
client.database.connect({
"database": "main-db",
});
// All queries inherit context - no need to specify env/product/database
client.database.query({ "table": "users" });
client.database.insert({ "table": "users", data: {...} });
client.database.aggregate({ "table": "orders", operations: {...} });
// Connect once
await ductape.database.connect({
["database"] = "main-db",
});
// All queries inherit context - no need to specify env/product/database
await ductape.database.query({ ["table"] = "users" });
await ductape.database.insert({ ["table"] = "users", data: {...} });
await ductape.database.aggregate({ ["table"] = "orders", operations: {...} });
Or specify connection parameters explicitly on each call:
- TypeScript
- Java
- Go
- .NET
await ductape.database.query({
database: 'main-db',
table: 'users',
});
ductape.database.query(Map.of(
"database", "main-db",
"table", "users"
));
client.database.query({
"database": "main-db",
"table": "users",
});
await ductape.database.query({
["database"] = "main-db",
["table"] = "users",
});
Available Methods
The database service provides these methods:
| Method | Description | See Guide |
|---|---|---|
query() | Read data with filters, sorting, pagination | Querying |
insert() | Insert single or multiple records | Writing Data |
update() | Update matching records | Writing Data |
delete() | Delete matching records | Writing Data |
upsert() | Insert or update on conflict | Writing Data |
raw() | Execute raw SQL/queries | Querying |
count() | Count records | Aggregations |
sum() | Sum column values | Aggregations |
avg() | Average column values | Aggregations |
min() / max() | Min/max values | Aggregations |
groupBy() | Group and aggregate | Aggregations |
aggregate() | Multiple aggregations | Aggregations |
transaction() | Transaction wrapper | Transactions |
beginTransaction() | Manual transaction | Transactions |
createTable() | Create new table | Below |
alterTable() | Modify table structure | Below |
dropTable() | Delete table | Below |
createIndex() | Create index | Migrations |
dropIndex() | Delete index | Migrations |
listIndexes() | List table indexes | Migrations |
runMigration() | Run migration | Migrations |
Schema Management
Create Table
- TypeScript
- Java
- Go
- .NET
import { SchemaHelpers } from '@ductape/sdk';
await ductape.database.createTable(
{ database: 'main-db' },
{
name: 'products',
columns: [
SchemaHelpers.id(),
SchemaHelpers.string('name', 255, false),
SchemaHelpers.decimal('price', 10, 2),
SchemaHelpers.boolean('is_active', true),
...SchemaHelpers.timestamps(),
],
},
{ ifNotExists: true }
);
import Map.of( SchemaHelpers ) from '@ductape/sdk';
ductape.database.createTable(
Map.of( "database", "main-db" ),
Map.of(
"name", "products",
columns: [
SchemaHelpers.id(),
SchemaHelpers.string('name', 255, false),
SchemaHelpers.decimal('price', 10, 2),
SchemaHelpers.boolean('is_active', true),
...SchemaHelpers.timestamps(),
]
),
Map.of( "ifNotExists", true )
);
import { SchemaHelpers } from '@ductape/sdk';
client.database.createTable(
{ "database": "main-db" },
{
"name": "products",
columns: [
SchemaHelpers.id(),
SchemaHelpers.string('name', 255, false),
SchemaHelpers.decimal('price', 10, 2),
SchemaHelpers.boolean('is_active', true),
...SchemaHelpers.timestamps(),
],
},
{ "ifNotExists": true }
);
import { SchemaHelpers } from '@ductape/sdk';
await ductape.database.createTable(
{ ["database"] = "main-db" },
{
["name"] = "products",
columns: [
SchemaHelpers.id(),
SchemaHelpers.string('name', 255, false),
SchemaHelpers.decimal('price', 10, 2),
SchemaHelpers.boolean('is_active', true),
...SchemaHelpers.timestamps(),
],
},
{ ["ifNotExists"] = true }
);
Schema Helpers
Pre-configured column definitions:
- TypeScript
- Java
- Go
- .NET
import { SchemaHelpers } from '@ductape/sdk';
SchemaHelpers.id() // Auto-increment primary key
SchemaHelpers.uuid() // UUID primary key
SchemaHelpers.string('name', 255, false) // String (length, nullable)
SchemaHelpers.text('bio') // Text field
SchemaHelpers.integer('age') // Integer
SchemaHelpers.bigint('views') // Big integer
SchemaHelpers.decimal('price', 10, 2) // Decimal (precision, scale)
SchemaHelpers.boolean('active', true) // Boolean with default
SchemaHelpers.date('birth_date') // Date
SchemaHelpers.datetime('scheduled_at') // Datetime
SchemaHelpers.timestamp('logged_at') // Timestamp
SchemaHelpers.json('settings') // JSON
SchemaHelpers.jsonb('metadata') // JSONB (PostgreSQL)
SchemaHelpers.foreignKey('user_id', 'users') // Foreign key
SchemaHelpers.timestamps() // created_at, updated_at
SchemaHelpers.softDelete() // deleted_at
import Map.of( SchemaHelpers ) from '@ductape/sdk';
SchemaHelpers.id() // Auto-increment primary key
SchemaHelpers.uuid() // UUID primary key
SchemaHelpers.string('name', 255, false) // String (length, nullable)
SchemaHelpers.text('bio') // Text field
SchemaHelpers.integer('age') // Integer
SchemaHelpers.bigint('views') // Big integer
SchemaHelpers.decimal('price', 10, 2) // Decimal (precision, scale)
SchemaHelpers.boolean('active', true) // Boolean with default
SchemaHelpers.date('birth_date') // Date
SchemaHelpers.datetime('scheduled_at') // Datetime
SchemaHelpers.timestamp('logged_at') // Timestamp
SchemaHelpers.json('settings') // JSON
SchemaHelpers.jsonb('metadata') // JSONB (PostgreSQL)
SchemaHelpers.foreignKey('user_id', 'users') // Foreign key
SchemaHelpers.timestamps() // created_at, updated_at
SchemaHelpers.softDelete() // deleted_at
import { SchemaHelpers } from '@ductape/sdk';
SchemaHelpers.id() // Auto-increment primary key
SchemaHelpers.uuid() // UUID primary key
SchemaHelpers.string('name', 255, false) // String (length, nullable)
SchemaHelpers.text('bio') // Text field
SchemaHelpers.integer('age') // Integer
SchemaHelpers.bigint('views') // Big integer
SchemaHelpers.decimal('price', 10, 2) // Decimal (precision, scale)
SchemaHelpers.boolean('active', true) // Boolean with default
SchemaHelpers.date('birth_date') // Date
SchemaHelpers.datetime('scheduled_at') // Datetime
SchemaHelpers.timestamp('logged_at') // Timestamp
SchemaHelpers.json('settings') // JSON
SchemaHelpers.jsonb('metadata') // JSONB (PostgreSQL)
SchemaHelpers.foreignKey('user_id', 'users') // Foreign key
SchemaHelpers.timestamps() // created_at, updated_at
SchemaHelpers.softDelete() // deleted_at
import { SchemaHelpers } from '@ductape/sdk';
SchemaHelpers.id() // Auto-increment primary key
SchemaHelpers.uuid() // UUID primary key
SchemaHelpers.string('name', 255, false) // String (length, nullable)
SchemaHelpers.text('bio') // Text field
SchemaHelpers.integer('age') // Integer
SchemaHelpers.bigint('views') // Big integer
SchemaHelpers.decimal('price', 10, 2) // Decimal (precision, scale)
SchemaHelpers.boolean('active', true) // Boolean with default
SchemaHelpers.date('birth_date') // Date
SchemaHelpers.datetime('scheduled_at') // Datetime
SchemaHelpers.timestamp('logged_at') // Timestamp
SchemaHelpers.json('settings') // JSON
SchemaHelpers.jsonb('metadata') // JSONB (PostgreSQL)
SchemaHelpers.foreignKey('user_id', 'users') // Foreign key
SchemaHelpers.timestamps() // created_at, updated_at
SchemaHelpers.softDelete() // deleted_at
Alter Table
- TypeScript
- Java
- Go
- .NET
import { ColumnAlterationType, ColumnType } from '@ductape/sdk';
// Add column
await ductape.database.alterTable(
{ database: 'main-db' },
'products',
[
{
type: ColumnAlterationType.ADD,
column: { name: 'sku', type: ColumnType.STRING, length: 50 },
},
]
);
// Drop column
await ductape.database.alterTable(
{ database: 'main-db' },
'products',
[
{ type: ColumnAlterationType.DROP, columnName: 'old_field' },
]
);
// Rename column
await ductape.database.alterTable(
{ database: 'main-db' },
'products',
[
{
type: ColumnAlterationType.RENAME,
oldName: 'old_name',
newName: 'new_name',
},
]
);
import Map.of( ColumnAlterationType, ColumnType ) from '@ductape/sdk';
// Add column
ductape.database.alterTable(
Map.of( "database", "main-db" ),
'products',
[
Map.of(
type: ColumnAlterationType.ADD,
column: Map.of( "name", "sku", type: ColumnType.STRING, "length", 50 )
),
]
);
// Drop column
ductape.database.alterTable(
Map.of( "database", "main-db" ),
'products',
[
Map.of( type: ColumnAlterationType.DROP, "columnName", "old_field" ),
]
);
// Rename column
ductape.database.alterTable(
Map.of( "database", "main-db" ),
'products',
[
Map.of(
type: ColumnAlterationType.RENAME,
"oldName", "old_name",
"newName", "new_name"
),
]
);
import { ColumnAlterationType, ColumnType } from '@ductape/sdk';
// Add column
client.database.alterTable(
{ "database": "main-db" },
'products',
[
{
type: ColumnAlterationType.ADD,
column: { "name": "sku", type: ColumnType.STRING, "length": 50 },
},
]
);
// Drop column
client.database.alterTable(
{ "database": "main-db" },
'products',
[
{ type: ColumnAlterationType.DROP, "columnName": "old_field" },
]
);
// Rename column
client.database.alterTable(
{ "database": "main-db" },
'products',
[
{
type: ColumnAlterationType.RENAME,
"oldName": "old_name",
"newName": "new_name",
},
]
);
import { ColumnAlterationType, ColumnType } from '@ductape/sdk';
// Add column
await ductape.database.alterTable(
{ ["database"] = "main-db" },
'products',
[
{
type: ColumnAlterationType.ADD,
column: { ["name"] = "sku", type: ColumnType.STRING, ["length"] = 50 },
},
]
);
// Drop column
await ductape.database.alterTable(
{ ["database"] = "main-db" },
'products',
[
{ type: ColumnAlterationType.DROP, ["columnName"] = "old_field" },
]
);
// Rename column
await ductape.database.alterTable(
{ ["database"] = "main-db" },
'products',
[
{
type: ColumnAlterationType.RENAME,
["oldName"] = "old_name",
["newName"] = "new_name",
},
]
);
Drop Table
- TypeScript
- Java
- Go
- .NET
await ductape.database.dropTable(
{ database: 'main-db' },
'old_table'
);
ductape.database.dropTable(
Map.of( "database", "main-db" ),
'old_table'
);
client.database.dropTable(
{ "database": "main-db" },
'old_table'
);
await ductape.database.dropTable(
{ ["database"] = "main-db" },
'old_table'
);
Get Schema Information
- TypeScript
- Java
- Go
- .NET
// List all tables
const tables = await ductape.database.listTables({
database: 'main-db',
});
// Get table schema
const schema = await ductape.database.getTableSchema(
{ database: 'main-db' },
'users'
);
console.log('Table:', schema.name);
console.log('Columns:', schema.columns);
console.log('Indexes:', schema.indexes);
// Check if table exists
const exists = await ductape.database.tableExists(
{ database: 'main-db' },
'users'
);
// List all tables
Map<String, Object> tables = ductape.database.listTables(Map.of(
"database", "main-db"
));
// Get table schema
Map<String, Object> schema = ductape.database.getTableSchema(
Map.of( "database", "main-db" ),
'users'
);
System.out.println('"Table", ", schema.name);
System.out.println(""Columns", ", schema.columns);
System.out.println(""Indexes", ", schema.indexes);
// Check if table exists
Map<String, Object> exists = ductape.database.tableExists(
Map.of( database: "main-db' ),
'users'
);
// List all tables
tables := client.database.listTables({
"database": "main-db",
});
// Get table schema
schema := client.database.getTableSchema(
{ "database": "main-db" },
'users'
);
fmt.Println('"Table": ", schema.name);
fmt.Println(""Columns": ", schema.columns);
fmt.Println(""Indexes": ", schema.indexes);
// Check if table exists
exists := client.database.tableExists(
{ database: "main-db' },
'users'
);
// List all tables
var tables = await ductape.database.listTables({
["database"] = "main-db",
});
// Get table schema
var schema = await ductape.database.getTableSchema(
{ ["database"] = "main-db" },
'users'
);
Console.WriteLine('["Table"] = ", schema.name);
Console.WriteLine("["Columns"] = ", schema.columns);
Console.WriteLine("["Indexes"] = ", schema.indexes);
// Check if table exists
var exists = await ductape.database.tableExists(
{ database: "main-db' },
'users'
);
Building Dynamic Queries
Conditional Filters
- TypeScript
- Java
- Go
- .NET
function searchProducts(filters: {
category?: string;
minPrice?: number;
maxPrice?: number;
inStock?: boolean;
}) {
const where: any = {};
if (filters.category) {
where.category = filters.category;
}
if (filters.minPrice !== undefined || filters.maxPrice !== undefined) {
where.price = {};
if (filters.minPrice !== undefined) where.price.$GTE = filters.minPrice;
if (filters.maxPrice !== undefined) where.price.$LTE = filters.maxPrice;
}
if (filters.inStock) {
where.stock = { $GT: 0 };
}
return ductape.database.query({
table: 'products',
where: Object.keys(where).length > 0 ? where : undefined,
});
}
function searchProducts(filters: Map.of(
category?: string;
minPrice?: number;
maxPrice?: number;
inStock?: boolean;
)) Map.of(
Map<String, Object> where: any = Map.of();
if (filters.category) Map.of(
where.category = filters.category;
)
if (filters.minPrice !== undefined || filters.maxPrice !== undefined) Map.of(
where.price = Map.of();
if (filters.minPrice !== undefined) where.price.$GTE = filters.minPrice;
if (filters.maxPrice !== undefined) where.price.$LTE = filters.maxPrice;
)
if (filters.inStock) Map.of(
where.stock = Map.of( $"GT", 0 );
)
return ductape.database.query(Map.of(
"table", "products",
where: Object.keys(where).length > 0 ? where : undefined
));
)
function searchProducts(filters: {
category?: string;
minPrice?: number;
maxPrice?: number;
inStock?: boolean;
}) {
const where: any = {};
if (filters.category) {
where.category = filters.category;
}
if (filters.minPrice !== undefined || filters.maxPrice !== undefined) {
where.price = {};
if (filters.minPrice !== undefined) where.price.$GTE = filters.minPrice;
if (filters.maxPrice !== undefined) where.price.$LTE = filters.maxPrice;
}
if (filters.inStock) {
where.stock = { $"GT": 0 };
}
return client.database.query({
"table": "products",
where: Object.keys(where).length > 0 ? where : undefined,
});
}
function searchProducts(filters: {
category?: string;
minPrice?: number;
maxPrice?: number;
inStock?: boolean;
}) {
var where: any = {};
if (filters.category) {
where.category = filters.category;
}
if (filters.minPrice !== undefined || filters.maxPrice !== undefined) {
where.price = {};
if (filters.minPrice !== undefined) where.price.$GTE = filters.minPrice;
if (filters.maxPrice !== undefined) where.price.$LTE = filters.maxPrice;
}
if (filters.inStock) {
where.stock = { $["GT"] = 0 };
}
return ductape.database.query({
["table"] = "products",
where: Object.keys(where).length > 0 ? where : undefined,
});
}
Paginated Results Helper
- TypeScript
- Java
- Go
- .NET
async function getPaginatedResults<T>(
table: string,
page: number,
pageSize: number,
where?: object
): Promise<{
data: T[];
total: number;
page: number;
totalPages: number;
}> {
const result = await ductape.database.query({
table,
where,
limit: pageSize,
offset: (page - 1) * pageSize,
});
return {
data: result.data as T[],
total: result.count,
page,
totalPages: Math.ceil(result.count / pageSize),
};
}
async function getPaginatedResults<T>(
table: string,
page: number,
pageSize: number,
where?: object
): Promise<Map.of(
data: T[];
total: number;
page: number;
totalPages: number;
)> Map.of(
Map<String, Object> result = ductape.database.query(Map.of(
table,
where,
limit: pageSize,
offset: (page - 1) * pageSize
));
return Map.of(
data: result.data as T[],
total: result.count,
page,
totalPages: Math.ceil(result.count / pageSize)
);
)
async function getPaginatedResults<T>(
table: string,
page: number,
pageSize: number,
where?: object
): Promise<{
data: T[];
total: number;
page: number;
totalPages: number;
}> {
result := client.database.query({
table,
where,
limit: pageSize,
offset: (page - 1) * pageSize,
});
return {
data: result.data as T[],
total: result.count,
page,
totalPages: Math.ceil(result.count / pageSize),
};
}
async function getPaginatedResults<T>(
table: string,
page: number,
pageSize: number,
where?: object
): Promise<{
data: T[];
total: number;
page: number;
totalPages: number;
}> {
var result = await ductape.database.query({
table,
where,
limit: pageSize,
offset: (page - 1) * pageSize,
});
return {
data: result.data as T[],
total: result.count,
page,
totalPages: Math.ceil(result.count / pageSize),
};
}
Error Handling
- TypeScript
- Java
- Go
- .NET
import { DatabaseError, DatabaseErrorType } from '@ductape/sdk';
try {
await ductape.database.insert({
table: 'users',
data: { email: 'test@example.com' },
});
} catch (error) {
if (error instanceof DatabaseError) {
switch (error.type) {
case DatabaseErrorType.CONNECTION_ERROR:
console.error('Cannot connect to database');
break;
case DatabaseErrorType.QUERY_ERROR:
console.error('Query failed:', error.message);
break;
case DatabaseErrorType.UNIQUE_VIOLATION:
console.error('Duplicate key');
break;
case DatabaseErrorType.FOREIGN_KEY_VIOLATION:
console.error('Invalid reference');
break;
default:
throw error;
}
}
}
import Map.of( DatabaseError, DatabaseErrorType ) from '@ductape/sdk';
try Map.of(
ductape.database.insert(Map.of(
"table", "users",
data: Map.of( "email", "test@example.com" )
));
) catch (error) Map.of(
if (error instanceof DatabaseError) Map.of(
switch (error.type) Map.of(
case DatabaseErrorType.CONNECTION_ERROR:
console.error('Cannot connect to database');
break;
case DatabaseErrorType.QUERY_ERROR:
console.error('Query "failed", ", error.message);
break;
case DatabaseErrorType.UNIQUE_VIOLATION:
console.error("Duplicate key');
break;
case DatabaseErrorType.FOREIGN_KEY_VIOLATION:
console.error('Invalid reference');
break;
default:
throw error;
)
)
)
import { DatabaseError, DatabaseErrorType } from '@ductape/sdk';
try {
client.database.insert({
"table": "users",
data: { "email": "test@example.com" },
});
} catch (error) {
if (error instanceof DatabaseError) {
switch (error.type) {
case DatabaseErrorType.CONNECTION_ERROR:
console.error('Cannot connect to database');
break;
case DatabaseErrorType.QUERY_ERROR:
console.error('Query "failed": ", error.message);
break;
case DatabaseErrorType.UNIQUE_VIOLATION:
console.error("Duplicate key');
break;
case DatabaseErrorType.FOREIGN_KEY_VIOLATION:
console.error('Invalid reference');
break;
default:
throw error;
}
}
}
import { DatabaseError, DatabaseErrorType } from '@ductape/sdk';
try {
await ductape.database.insert({
["table"] = "users",
data: { ["email"] = "test@example.com" },
});
} catch (error) {
if (error instanceof DatabaseError) {
switch (error.type) {
case DatabaseErrorType.CONNECTION_ERROR:
console.error('Cannot connect to database');
break;
case DatabaseErrorType.QUERY_ERROR:
console.error('Query ["failed"] = ", error.message);
break;
case DatabaseErrorType.UNIQUE_VIOLATION:
console.error("Duplicate key');
break;
case DatabaseErrorType.FOREIGN_KEY_VIOLATION:
console.error('Invalid reference');
break;
default:
throw error;
}
}
}
Next Steps
- Querying Data - Read operations in detail
- Writing Data - Insert, update, delete operations
- Aggregations - COUNT, SUM, GROUP BY operations
- Transactions - Atomic operations
- Migrations - Schema versioning