Client examples¶
shard-db speaks newline-delimited JSON over TCP. Any TCP-capable language can talk to it — no client library required. Below: terminal one-liners (socat / nc), and reference clients in Python, Java, and Node.js.
For the full wire format (request/response framing, pipelining, errors), see Query protocol → Overview. For TLS-wrapped variants, see Operations → Deployment.
Terminal: socat / nc¶
# Using socat
echo '{"mode":"get","dir":"default","object":"users","key":"user1"}' \
| socat - TCP:localhost:9199
# Using nc/ncat
echo '{"mode":"insert","dir":"default","object":"users","key":"u1","value":{"name":"Bob"}}' \
| nc -q1 localhost 9199
# Pipeline multiple requests over one connection
printf '%s\n%s\n%s\n' \
'{"mode":"insert","dir":"default","object":"users","key":"u1","value":{"name":"Alice"}}' \
'{"mode":"insert","dir":"default","object":"users","key":"u2","value":{"name":"Bob"}}' \
'{"mode":"get","dir":"default","object":"users","key":"u1"}' \
| socat - TCP:localhost:9199
Python¶
import socket
import json
def query(request, host="localhost", port=9199):
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((host, port))
sock.sendall((json.dumps(request) + "\n").encode())
sock.shutdown(socket.SHUT_WR)
data = b""
while True:
chunk = sock.recv(4096)
if not chunk:
break
data += chunk
sock.close()
# Strip trailing null byte
text = data.decode().strip().rstrip("\x00").strip()
return json.loads(text) if text else None
# Create an object
query({
"mode": "create-object",
"dir": "default",
"object": "products",
"splits": 16,
"max_key": 128,
"fields": ["name:varchar:100", "price:numeric:10,2", "stock:int", "active:bool"]
})
# Insert
query({
"mode": "insert",
"dir": "default",
"object": "products",
"key": "prod-001",
"value": {"name": "Widget", "price": "29.99", "stock": 150, "active": True}
})
# Insert only if key doesn't exist
query({
"mode": "insert",
"dir": "default",
"object": "products",
"key": "prod-001",
"value": {"name": "Widget", "price": "29.99", "stock": 150, "active": True},
"if_not_exists": True
})
# Update with compare-and-swap
query({
"mode": "update",
"dir": "default",
"object": "products",
"key": "prod-001",
"value": {"stock": 149},
"if": [{"field": "stock", "op": "eq", "value": "150"}]
})
# Get
result = query({"mode": "get", "dir": "default", "object": "products", "key": "prod-001"})
# Get with field projection
result = query({
"mode": "get",
"dir": "default",
"object": "products",
"key": "prod-001",
"fields": "name,price"
})
# Multi-get
results = query({
"mode": "get",
"dir": "default",
"object": "products",
"keys": ["prod-001", "prod-002", "prod-003"]
})
# Find with criteria
results = query({
"mode": "find",
"dir": "default",
"object": "products",
"criteria": [
{"field": "price", "op": "lt", "value": "50.00"},
{"field": "active", "op": "eq", "value": "true"}
],
"offset": 0,
"limit": 20
})
# Count matching records
result = query({
"mode": "count",
"dir": "default",
"object": "products",
"criteria": [{"field": "active", "op": "eq", "value": "true"}]
})
# Bulk insert
query({
"mode": "bulk-insert",
"dir": "default",
"object": "products",
"records": [
{"id": "prod-100", "data": {"name": "Gadget A", "price": "9.99", "stock": 500}},
{"id": "prod-101", "data": {"name": "Gadget B", "price": "19.99", "stock": 250}}
]
})
# Bulk update by criteria
query({
"mode": "bulk-update",
"dir": "default",
"object": "products",
"criteria": [{"field": "stock", "op": "eq", "value": "0"}],
"value": {"active": False},
"limit": 1000
})
# Bulk delete by criteria (dry run first)
query({
"mode": "bulk-delete",
"dir": "default",
"object": "products",
"criteria": [{"field": "active", "op": "eq", "value": "false"}],
"dry_run": True
})
Pipelining (Python)¶
def pipeline(requests, host="localhost", port=9199):
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((host, port))
payload = "".join(json.dumps(r) + "\n" for r in requests)
sock.sendall(payload.encode())
sock.shutdown(socket.SHUT_WR)
data = b""
while True:
chunk = sock.recv(65536)
if not chunk:
break
data += chunk
sock.close()
results = []
for line in data.decode().split("\x00"):
line = line.strip()
if line:
results.append(json.loads(line))
return results
# Send 1000 inserts in one TCP connection
records = [
{"mode": "insert", "dir": "default", "object": "products",
"key": f"bulk-{i}", "value": {"name": f"Item {i}", "price": "1.00", "stock": i}}
for i in range(1000)
]
results = pipeline(records)
TLS variant (Python)¶
import ssl
def query_tls(request, host="your-server", port=9200):
ctx = ssl.create_default_context()
# For self-signed certs during dev:
# ctx.check_hostname = False
# ctx.verify_mode = ssl.CERT_NONE
raw = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock = ctx.wrap_socket(raw, server_hostname=host)
sock.connect((host, port))
sock.sendall((json.dumps(request) + "\n").encode())
sock.shutdown(socket.SHUT_WR)
data = b""
while True:
chunk = sock.recv(4096)
if not chunk: break
data += chunk
sock.close()
return json.loads(data.decode().strip().rstrip("\x00").strip())
Java¶
import java.io.*;
import java.net.*;
import java.nio.charset.StandardCharsets;
public class ShardDbClient {
private final String host;
private final int port;
public ShardDbClient(String host, int port) {
this.host = host;
this.port = port;
}
public String query(String json) throws IOException {
try (Socket socket = new Socket(host, port)) {
OutputStream out = socket.getOutputStream();
out.write((json + "\n").getBytes(StandardCharsets.UTF_8));
out.flush();
socket.shutdownOutput();
InputStream in = socket.getInputStream();
ByteArrayOutputStream buf = new ByteArrayOutputStream();
byte[] tmp = new byte[4096];
int n;
while ((n = in.read(tmp)) != -1) {
buf.write(tmp, 0, n);
}
String result = buf.toString(StandardCharsets.UTF_8).trim();
if (result.endsWith("\0")) {
result = result.substring(0, result.length() - 1).trim();
}
return result;
}
}
/** Pipeline multiple requests over one connection */
public String[] pipeline(String[] requests) throws IOException {
try (Socket socket = new Socket(host, port)) {
OutputStream out = socket.getOutputStream();
StringBuilder sb = new StringBuilder();
for (String req : requests) {
sb.append(req).append("\n");
}
out.write(sb.toString().getBytes(StandardCharsets.UTF_8));
out.flush();
socket.shutdownOutput();
InputStream in = socket.getInputStream();
ByteArrayOutputStream buf = new ByteArrayOutputStream();
byte[] tmp = new byte[65536];
int n;
while ((n = in.read(tmp)) != -1) {
buf.write(tmp, 0, n);
}
return buf.toString(StandardCharsets.UTF_8).split("\0");
}
}
public static void main(String[] args) throws IOException {
ShardDbClient db = new ShardDbClient("localhost", 9199);
// Create object
db.query("{\"mode\":\"create-object\",\"dir\":\"default\",\"object\":\"orders\","
+ "\"splits\":16,\"max_key\":128,"
+ "\"fields\":[\"customer:varchar:100\",\"total:numeric:12,2\",\"status:varchar:20\",\"created:datetime\"],"
+ "\"indexes\":[\"customer\",\"status\"]}");
// Insert
System.out.println(db.query(
"{\"mode\":\"insert\",\"dir\":\"default\",\"object\":\"orders\","
+ "\"key\":\"ord-001\","
+ "\"value\":{\"customer\":\"Alice\",\"total\":\"249.99\",\"status\":\"pending\"}}"));
// Update with CAS
System.out.println(db.query(
"{\"mode\":\"update\",\"dir\":\"default\",\"object\":\"orders\","
+ "\"key\":\"ord-001\","
+ "\"value\":{\"status\":\"shipped\"},"
+ "\"if\":[{\"field\":\"status\",\"op\":\"eq\",\"value\":\"pending\"}]}"));
// Find
System.out.println(db.query(
"{\"mode\":\"find\",\"dir\":\"default\",\"object\":\"orders\","
+ "\"criteria\":[{\"field\":\"status\",\"op\":\"eq\",\"value\":\"shipped\"}],"
+ "\"limit\":50}"));
// Pipeline
String[] results = db.pipeline(new String[]{
"{\"mode\":\"get\",\"dir\":\"default\",\"object\":\"orders\",\"key\":\"ord-001\"}",
"{\"mode\":\"size\",\"dir\":\"default\",\"object\":\"orders\"}"
});
for (String r : results) System.out.println(r.trim());
}
}
TLS variant (Java)¶
import javax.net.ssl.SSLSocketFactory;
SSLSocketFactory sf = (SSLSocketFactory) SSLSocketFactory.getDefault();
Socket socket = sf.createSocket("your-server", 9200);
// ... same read/write logic as plain TCP client above
Node.js¶
const net = require("net");
function query(request, host = "localhost", port = 9199) {
return new Promise((resolve, reject) => {
const socket = new net.Socket();
let data = "";
socket.connect(port, host, () => {
socket.write(JSON.stringify(request) + "\n");
socket.end();
});
socket.on("data", (chunk) => (data += chunk.toString()));
socket.on("end", () => {
const text = data.replace(/\0/g, "").trim();
try { resolve(JSON.parse(text)); }
catch { resolve(text); }
});
socket.on("error", reject);
});
}
function pipeline(requests, host = "localhost", port = 9199) {
return new Promise((resolve, reject) => {
const socket = new net.Socket();
let data = "";
socket.connect(port, host, () => {
const payload = requests.map((r) => JSON.stringify(r)).join("\n") + "\n";
socket.write(payload);
socket.end();
});
socket.on("data", (chunk) => (data += chunk.toString()));
socket.on("end", () => {
const results = data
.split("\0")
.map((s) => s.trim())
.filter(Boolean)
.map((s) => { try { return JSON.parse(s); } catch { return s; } });
resolve(results);
});
socket.on("error", reject);
});
}
(async () => {
// Create object
await query({
mode: "create-object", dir: "default", object: "events",
splits: 16, max_key: 128,
fields: [
"type:varchar:50", "source:varchar:100",
"payload:varchar:2000", "timestamp:datetime", "severity:short",
],
indexes: ["type", "source"],
});
// Insert
await query({
mode: "insert", dir: "default", object: "events", key: "evt-001",
value: { type: "login", source: "web", payload: '{"ip":"1.2.3.4"}', severity: 1 },
});
// Find
console.log(await query({
mode: "find", dir: "default", object: "events",
criteria: [{ field: "type", op: "eq", value: "login" }],
limit: 100,
}));
// Pipeline 1000 inserts
const reqs = Array.from({ length: 1000 }, (_, i) => ({
mode: "insert", dir: "default", object: "events",
key: `batch-${i}`,
value: { type: "batch", source: "script", severity: 1 },
}));
const results = await pipeline(reqs);
console.log(`Pipelined ${results.length} responses`);
})();
TLS variant (Node.js)¶
const tls = require("tls");
function queryTls(request, host = "your-server", port = 9200) {
return new Promise((resolve, reject) => {
const socket = tls.connect(port, host, () => {
socket.write(JSON.stringify(request) + "\n");
socket.end();
});
let data = "";
socket.on("data", (chunk) => (data += chunk.toString()));
socket.on("end", () => resolve(JSON.parse(data.replace(/\0/g, "").trim())));
socket.on("error", reject);
});
}