Getting Started with Warehouse
The Ductape Warehouse provides a unified interface for querying and writing data across databases, graphs, and vector stores using a single JSON-based query language. It enables cross-database joins, semantic similarity searches, and distributed transactions.
Overview
Traditional applications often use multiple data stores:
- Databases (PostgreSQL, MySQL, MongoDB) for structured data
- Graph databases (Neo4j, Neptune) for relationship-heavy data
- Vector stores (Pinecone, Qdrant) for embeddings and similarity search
The Warehouse unifies these into a single query interface, allowing you to:
- Query across different data source types
- Join data between databases, graphs, and vectors
- Execute distributed transactions with automatic rollback
- Use semantic (vector-based) joins for AI applications
All your product's databases, graphs, and vectors are automatically available - no registration required.
Prerequisites
Before using the Warehouse, ensure you have:
- A Ductape account and workspace
- At least one data source configured (database, graph, or vector store)
- The Ductape SDK installed
- TypeScript
- Java
- Go
- .NET
npm install @ductape/sdk@0.1.8
<dependency>
<groupId>app.ductape</groupId>
<artifactId>sdk</artifactId>
<version>0.1.8</version>
</dependency>
go get github.com/ductape/ductape/sdk/go@v0.1.8
dotnet add package Ductape.Sdk --version 0.1.8
Quick Start
Step 1: Initialize the SDK
- TypeScript
- Java
- Go
- .NET
import Ductape from '@ductape/sdk';
const ductape = new Ductape({
accessKey: 'your-access-key',
});
import app.ductape.sdk.Ductape;
import app.ductape.sdk.core.EnvType;
import app.ductape.sdk.core.RequestContext;
RequestContext auth = new RequestContext(null, null, null, null, 'your-access-key');
Ductape ductape = new Ductape(EnvType.PRODUCTION, auth);
import (
"context"
"github.com/ductape/ductape/sdk/go/core"
ductapesdk "github.com/ductape/ductape/sdk/go/ductape"
)
auth := core.NewRequestContext("", "", "", "", 'your-access-key')
client, err := ductapesdk.New(core.EnvProduction, auth)
if err != nil {
return err
}
using Ductape.Sdk;
using Ductape.Sdk.Core;
var auth = new RequestContext(null, null, null, null, 'your-access-key', null);
var ductape = new Ductape(EnvType.Production, auth);
Step 2: Execute a Query
All your product's databases, graphs, and vectors are automatically available:
- TypeScript
- Java
- Go
- .NET
// Query from a database
const result = await ductape.warehouse.query({
query: {
operation: 'select',
from: {
type: 'database',
tag: 'users-postgres',
entity: 'users',
alias: 'u'
},
fields: ['u.id', 'u.name', 'u.email'],
where: { 'u.status': { $eq: 'active' } },
limit: 100
}
});
console.log(result.data); // Array of user records
console.log(result.metadata.executionTime); // Query execution time in ms
// Query from a database
Map<String, Object> result = ductape.warehouse.query(Map.of(
query: Map.of(
"operation", "select",
from: Map.of(
"type", "database",
"tag", "users-postgres",
"entity", "users",
"alias", "u"
),
fields: ['u.id', 'u.name', 'u.email'],
where: Map.of( 'u.status': Map.of( $"eq", "active" ) ),
"limit", 100
)
));
System.out.println(result.data); // Array of user records
System.out.println(result.metadata.executionTime); // Query execution time in ms
// Query from a database
result := client.warehouse.query({
query: {
"operation": "select",
from: {
"type": "database",
"tag": "users-postgres",
"entity": "users",
"alias": "u"
},
fields: ['u.id', 'u.name', 'u.email'],
where: { 'u.status': { $"eq": "active" } },
"limit": 100
}
});
fmt.Println(result.data); // Array of user records
fmt.Println(result.metadata.executionTime); // Query execution time in ms
// Query from a database
var result = await ductape.warehouse.query({
query: {
["operation"] = "select",
from: {
["type"] = "database",
["tag"] = "users-postgres",
["entity"] = "users",
["alias"] = "u"
},
fields: ['u.id', 'u.name', 'u.email'],
where: { 'u.status': { $["eq"] = "active" } },
["limit"] = 100
}
});
Console.WriteLine(result.data); // Array of user records
Console.WriteLine(result.metadata.executionTime); // Query execution time in ms
Step 3: Cross-Database Join
Join data from different sources seamlessly:
- TypeScript
- Java
- Go
- .NET
const result = await ductape.warehouse.query({
query: {
operation: 'select',
from: {
type: 'database',
tag: 'users-postgres',
entity: 'users',
alias: 'u'
},
fields: ['u.name', 'u.email', 'friends.name as friend_name'],
join: [{
type: 'left',
source: {
type: 'graph',
tag: 'social-neo4j',
entity: 'Person',
alias: 'friends'
},
graph: {
relationship: 'FRIENDS_WITH',
direction: 'both'
},
on: { left: 'u.id', right: 'friends.userId' }
}],
where: { 'u.status': { $eq: 'active' } },
limit: 100
}
});
Map<String, Object> result = ductape.warehouse.query(Map.of(
query: Map.of(
"operation", "select",
from: Map.of(
"type", "database",
"tag", "users-postgres",
"entity", "users",
"alias", "u"
),
fields: ['u.name', 'u.email', 'friends.name as friend_name'],
join: [Map.of(
"type", "left",
source: Map.of(
"type", "graph",
"tag", "social-neo4j",
"entity", "Person",
"alias", "friends"
),
graph: Map.of(
"relationship", "FRIENDS_WITH",
"direction", "both"
),
on: Map.of( "left", "u.id", "right", "friends.userId" )
)],
where: Map.of( 'u.status': Map.of( $"eq", "active" ) ),
"limit", 100
)
));
result := client.warehouse.query({
query: {
"operation": "select",
from: {
"type": "database",
"tag": "users-postgres",
"entity": "users",
"alias": "u"
},
fields: ['u.name', 'u.email', 'friends.name as friend_name'],
join: [{
"type": "left",
source: {
"type": "graph",
"tag": "social-neo4j",
"entity": "Person",
"alias": "friends"
},
graph: {
"relationship": "FRIENDS_WITH",
"direction": "both"
},
on: { "left": "u.id", "right": "friends.userId" }
}],
where: { 'u.status': { $"eq": "active" } },
"limit": 100
}
});
var result = await ductape.warehouse.query({
query: {
["operation"] = "select",
from: {
["type"] = "database",
["tag"] = "users-postgres",
["entity"] = "users",
["alias"] = "u"
},
fields: ['u.name', 'u.email', 'friends.name as friend_name'],
join: [{
["type"] = "left",
source: {
["type"] = "graph",
["tag"] = "social-neo4j",
["entity"] = "Person",
["alias"] = "friends"
},
graph: {
["relationship"] = "FRIENDS_WITH",
["direction"] = "both"
},
on: { ["left"] = "u.id", ["right"] = "friends.userId" }
}],
where: { 'u.status': { $["eq"] = "active" } },
["limit"] = 100
}
});
Core Concepts
Data Sources
A data source references any database, graph, or vector store in your product:
interface IDataSource {
type: 'database' | 'graph' | 'vector';
tag: string; // Your data source tag (e.g., 'users-postgres')
entity: string; // Table, node label, or collection name
alias?: string; // Optional alias for use in joins and field references
}
Query Operations
The Warehouse supports these operations:
| Operation | Description |
|---|---|
select | Read data from one or more sources |
insert | Add new records |
update | Modify existing records |
delete | Remove records |
upsert | Insert or update based on key |
Where Clauses
Use MongoDB-style operators for filtering:
- TypeScript
- Java
- Go
- .NET
// Simple equality
{ 'u.status': { $eq: 'active' } }
// Comparison operators
{ 'u.age': { $gte: 18, $lt: 65 } }
// Logical operators
{
$and: [
{ 'u.status': { $eq: 'active' } },
{ 'u.verified': { $eq: true } }
]
}
// Array operators
{ 'u.roles': { $in: ['admin', 'moderator'] } }
// Pattern matching
{ 'u.email': { $like: '%@company.com' } }
// Null checks
{ 'u.deletedAt': { $null: true } }
// Simple equality
Map.of( 'u.status': Map.of( $"eq", "active" ) )
// Comparison operators
Map.of( 'u.age': Map.of( $"gte", 18, $"lt", 65 ) )
// Logical operators
Map.of(
$and: [
Map.of( 'u.status': Map.of( $"eq", "active" ) ),
Map.of( 'u.verified': Map.of( $"eq", true ) )
]
)
// Array operators
Map.of( 'u.roles': Map.of( $in: ['admin', 'moderator'] ) )
// Pattern matching
Map.of( 'u.email': Map.of( $"like", "%@company.com" ) )
// Null checks
Map.of( 'u.deletedAt': Map.of( $"null", true ) )
// Simple equality
{ 'u.status': { $"eq": "active" } }
// Comparison operators
{ 'u.age': { $"gte": 18, $"lt": 65 } }
// Logical operators
{
$and: [
{ 'u.status': { $"eq": "active" } },
{ 'u.verified': { $"eq": true } }
]
}
// Array operators
{ 'u.roles': { $in: ['admin', 'moderator'] } }
// Pattern matching
{ 'u.email': { $"like": "%@company.com" } }
// Null checks
{ 'u.deletedAt': { $"null": true } }
// Simple equality
{ 'u.status': { $["eq"] = "active" } }
// Comparison operators
{ 'u.age': { $["gte"] = 18, $["lt"] = 65 } }
// Logical operators
{
$and: [
{ 'u.status': { $["eq"] = "active" } },
{ 'u.verified': { $["eq"] = true } }
]
}
// Array operators
{ 'u.roles': { $in: ['admin', 'moderator'] } }
// Pattern matching
{ 'u.email': { $["like"] = "%@company.com" } }
// Null checks
{ 'u.deletedAt': { $["null"] = true } }
Convenience Methods
For simple operations, use the convenience methods:
- TypeScript
- Java
- Go
- .NET
// Select with options
const users = await ductape.warehouse.select({
source: { type: 'database', tag: 'users-postgres', entity: 'users', alias: 'u' },
fields: ['id', 'name'],
where: { status: { $eq: 'active' } },
orderBy: [{ field: 'createdAt', order: 'DESC' }],
limit: 10
});
// Insert
await ductape.warehouse.insert({
source: { type: 'database', tag: 'users-postgres', entity: 'users' },
data: { name: 'John', email: 'john@example.com' }
});
// Update
await ductape.warehouse.update({
source: { type: 'database', tag: 'users-postgres', entity: 'users' },
data: { status: 'inactive' },
where: { id: { $eq: 123 } }
});
// Delete
await ductape.warehouse.delete({
source: { type: 'database', tag: 'users-postgres', entity: 'users' },
where: { status: { $eq: 'deleted' } }
});
// Upsert
await ductape.warehouse.upsert({
source: { type: 'database', tag: 'users-postgres', entity: 'users' },
data: { id: 123, name: 'John', email: 'john@example.com' }
});
// Select with options
Map<String, Object> users = ductape.warehouse.select(Map.of(
source: Map.of( "type", "database", "tag", "users-postgres", "entity", "users", "alias", "u" ),
fields: ['id', 'name'],
where: Map.of( status: Map.of( $"eq", "active" ) ),
orderBy: [Map.of( "field", "createdAt", "order", "DESC" )],
"limit", 10
));
// Insert
ductape.warehouse.insert(Map.of(
source: Map.of( "type", "database", "tag", "users-postgres", "entity", "users" ),
data: Map.of( "name", "John", "email", "john@example.com" )
));
// Update
ductape.warehouse.update(Map.of(
source: Map.of( "type", "database", "tag", "users-postgres", "entity", "users" ),
data: Map.of( "status", "inactive" ),
where: Map.of( id: Map.of( $"eq", 123 ) )
));
// Delete
ductape.warehouse.delete(Map.of(
source: Map.of( "type", "database", "tag", "users-postgres", "entity", "users" ),
where: Map.of( status: Map.of( $"eq", "deleted" ) )
));
// Upsert
ductape.warehouse.upsert(Map.of(
source: Map.of( "type", "database", "tag", "users-postgres", "entity", "users" ),
data: Map.of( "id", 123, "name", "John", "email", "john@example.com" )
));
// Select with options
users := client.warehouse.select({
source: { "type": "database", "tag": "users-postgres", "entity": "users", "alias": "u" },
fields: ['id', 'name'],
where: { status: { $"eq": "active" } },
orderBy: [{ "field": "createdAt", "order": "DESC" }],
"limit": 10
});
// Insert
client.warehouse.insert({
source: { "type": "database", "tag": "users-postgres", "entity": "users" },
data: { "name": "John", "email": "john@example.com" }
});
// Update
client.warehouse.update({
source: { "type": "database", "tag": "users-postgres", "entity": "users" },
data: { "status": "inactive" },
where: { id: { $"eq": 123 } }
});
// Delete
client.warehouse.delete({
source: { "type": "database", "tag": "users-postgres", "entity": "users" },
where: { status: { $"eq": "deleted" } }
});
// Upsert
client.warehouse.upsert({
source: { "type": "database", "tag": "users-postgres", "entity": "users" },
data: { "id": 123, "name": "John", "email": "john@example.com" }
});
// Select with options
var users = await ductape.warehouse.select({
source: { ["type"] = "database", ["tag"] = "users-postgres", ["entity"] = "users", ["alias"] = "u" },
fields: ['id', 'name'],
where: { status: { $["eq"] = "active" } },
orderBy: [{ ["field"] = "createdAt", ["order"] = "DESC" }],
["limit"] = 10
});
// Insert
await ductape.warehouse.insert({
source: { ["type"] = "database", ["tag"] = "users-postgres", ["entity"] = "users" },
data: { ["name"] = "John", ["email"] = "john@example.com" }
});
// Update
await ductape.warehouse.update({
source: { ["type"] = "database", ["tag"] = "users-postgres", ["entity"] = "users" },
data: { ["status"] = "inactive" },
where: { id: { $["eq"] = 123 } }
});
// Delete
await ductape.warehouse.delete({
source: { ["type"] = "database", ["tag"] = "users-postgres", ["entity"] = "users" },
where: { status: { $["eq"] = "deleted" } }
});
// Upsert
await ductape.warehouse.upsert({
source: { ["type"] = "database", ["tag"] = "users-postgres", ["entity"] = "users" },
data: { ["id"] = 123, ["name"] = "John", ["email"] = "john@example.com" }
});
What's Next
- Cross-Database Joins - Learn how to join data across different sources
- Semantic Joins - Use vector similarity for AI-powered joins
- Transactions - Execute distributed transactions with saga pattern
- Query Reference - Complete query syntax reference