Skip to content

thanos/couchbase-zig-client

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

78 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

couchbase-zig-client

Zig wrapper for the libcouchbase C library.

couchbase-zig-client-4

Version 0.5.4 - Binary Protocol Features

New Features

  • Comprehensive Binary Protocol Features: Complete binary protocol implementation
  • Native Collection Support: Collection-aware binary protocol operations
  • Advanced Feature Flags: Server capability detection and negotiation
  • Binary Document Handling: Support for binary documents with content types and flags
  • Database Change Protocol (DCP): Real-time streaming of database changes
  • Protocol Version Negotiation: Automatic version negotiation and compatibility detection
  • Collection-Aware Operations: Explicit scope/collection context for binary operations
  • DCP Event Streaming: Support for mutations, deletions, and expirations
  • Feature Flag Detection: Collections, DCP, durability, tracing, and compression support
  • Memory Management: Comprehensive cleanup for all binary protocol data structures

Technical Details

  • BinaryProtocol - Core binary protocol functionality
  • FeatureFlags - Server capability detection and negotiation
  • ProtocolVersion - Protocol version information and compatibility
  • BinaryDocument - Binary document with metadata and content type
  • BinaryOperationContext - Collection-aware operation context
  • DcpEvent - Database Change Protocol event with full metadata
  • DcpEventType - Enum for different DCP event types
  • Custom format specifiers for all binary protocol types
  • Memory-safe implementation with proper cleanup

Version 0.5.3 - Advanced N1QL Query Options

New Features

  • Query Profile support (off, phases, timings modes)
  • Readonly queries functionality
  • Client Context ID for query traceability
  • Scan capabilities configuration (scan cap and wait times)
  • Flex index support for flexible index usage
  • Consistency tokens for advanced consistency control
  • Performance tuning options (max parallelism, pipeline batch/cap)
  • Pretty print formatting and metrics control
  • Query context specification and raw JSON options
  • Query option chaining with fluent API

Technical Details

  • Direct libcouchbase C API integration
  • Enhanced QueryMetadata parsing with profile information
  • Comprehensive query options builder methods
  • Type-safe option handling with graceful degradation
  • Eight new test cases for advanced N1QL features

Version 0.5.0 - Transaction Functionality Implementation

New Features

  • Complete Transaction functionality for ACID compliance
  • Transaction management operations (begin, commit, rollback)
  • Transaction-aware KV operations (get, insert, upsert, replace, remove)
  • Transaction-aware counter operations (increment, decrement)
  • Transaction-aware advanced operations (touch, unlock, query)
  • Comprehensive transaction configuration and error handling
  • Automatic rollback on operation failure
  • Transaction test suite with 11 test cases

Technical Details

  • TransactionContext and TransactionResult data structures
  • TransactionConfig for comprehensive configuration
  • Transaction state management (active, committed, rolled_back, failed)
  • Memory-safe implementation with proper cleanup
  • Comprehensive error handling and rollback logic

Version 0.4.6 - Durability & Consistency Implementation

New Features

  • Complete Durability & Consistency functionality
  • Observe-based durability operations (observe, observeMulti, waitForDurability)
  • Mutation token management with automatic extraction
  • Enhanced store operations with full durability support
  • Support for all Couchbase durability levels
  • Comprehensive durability test suite with 13 test cases

Technical Details

  • ObserveDurability, ObserveResult, and ObserveOptions data structures
  • Mutation token creation, validation, and memory management
  • Timeout handling for durability operations
  • Error handling for durability-specific errors
  • Memory-safe implementation with proper cleanup

Version 0.4.5 - Spatial Views Implementation (Deprecated)

New Features

  • Spatial Views implementation for backward compatibility
  • spatialViewQuery() function with geospatial parameters
  • BoundingBox and SpatialRange data structures for geospatial queries
  • Comprehensive spatial view test suite with 8 test cases
  • Deprecation warnings and migration guidance to Full-Text Search (FTS)

Technical Details

  • Backward compatibility with older Couchbase Server versions
  • Automatic deprecation warnings for spatial view usage
  • Clear migration guidance to modern FTS geospatial queries
  • Comprehensive error handling for unsupported operations

Note: Spatial views are deprecated in Couchbase Server 6.0+. Users are strongly encouraged to migrate to Full-Text Search (FTS) for geospatial queries.

Version 0.4.4 - Enhanced Batch Operations with Collections

New Features

  • Enhanced batch operations with collection support
  • New batch operation types: get_replica, lookup_in, mutate_in
  • Collection-aware batch operations via withCollection() method
  • Enhanced counter operations with direct delta parameter
  • Comprehensive enhanced batch test suite with 4 test cases
  • Support for all collection-aware operations in batch processing

Technical Details

  • Complete batch operation coverage for all collection-aware operations
  • Seamless integration with existing collection-aware operations
  • Improved memory management and error handling for batch operations
  • Backward compatibility maintained with clear migration path
  • Production-ready batch processing for multi-tenant applications

Version 0.4.3 - Collections & Scopes API Complete

New Features

  • Collections & Scopes API Phase 3: Advanced operations with collections
  • getReplicaWithCollection(): Collection-aware replica document retrieval
  • lookupInWithCollection(): Collection-aware subdocument lookup operations
  • mutateInWithCollection(): Collection-aware subdocument mutation operations
  • Comprehensive Advanced Operations Testing: 7 test cases covering replica and subdocument operations
  • Full Collections & Scopes API Coverage: 100% feature parity with C library

Technical Details

  • Phase 1: Core KV operations (upsert, insert, replace, remove, touch, counter, exists)
  • Phase 2: Lock operations (getAndLock, unlock)
  • Phase 3: Advanced operations (replica, subdocument lookup/mutation)
  • All operations maintain Zig idiomatic style with proper memory management
  • Full integration with libcouchbase C library collection functions

Version 0.4.1 - Collections & Scopes API Phase 1 & 2

New Features

  • Collections & Scopes API Phase 1 & 2: Core KV and lock operations with collections
  • Collection Type: Collection identifier with name, scope, and memory management
  • Scope Type: Scope identifier with name and memory management
  • CollectionManifest: Collection manifest management with search and filtering
  • CollectionManifestEntry: Individual collection metadata with UID and TTL
  • getWithCollection(): Collection-aware document retrieval
  • getCollectionManifest(): Collection manifest retrieval (simplified implementation)
  • Comprehensive Collection Testing: 11 test cases covering all collection scenarios

Version 0.4.0 - GET with Lock Operations

New Features

  • GET with Lock Operation: Complete implementation matching libcouchbase functionality
  • GetAndLockOptions: Comprehensive configuration for lock operations
  • UnlockOptions: Flexible unlock operation configuration
  • GetAndLockResult: Detailed result structure with lock time information
  • UnlockResult: Success status and CAS information for unlock operations
  • Comprehensive Lock Testing: 10 test cases covering all lock scenarios

Features

  • Key-value operations: get, insert, upsert, replace, remove, touch, counter
  • GET with Lock: getAndLock() and unlockWithOptions() operations
  • Collections & Scopes: Complete collection-aware operations (100% feature parity)
  • N1QL query execution with advanced options
  • Subdocument operations: Complete implementation with collection support
  • Batch operations: Execute multiple operations in single call
  • CAS (compare-and-swap) support
  • Durability levels and consistency controls
  • Replica reads with collection support
  • ACID transactions with rollback support
  • Diagnostics & Monitoring: Health checks, connection diagnostics, metrics
  • Binary Protocol Features: Native binary document handling and DCP streaming
  • Error type mappings

Requirements

  • Zig 0.11.0 or later
  • libcouchbase 3.x
  • Couchbase Server

Installation

libcouchbase

macOS:

brew install libcouchbase

Ubuntu/Debian:

wget https://packages.couchbase.com/clients/c/repos/deb/couchbase.key
sudo apt-key add couchbase.key
echo "deb https://packages.couchbase.com/clients/c/repos/deb/ubuntu2004 focal focal/main" | sudo tee /etc/apt/sources.list.d/couchbase.list
sudo apt-get update
sudo apt-get install libcouchbase-dev libcouchbase3 libcouchbase3-tools

Project Integration

Add to build.zig.zon:

.dependencies = .{
    .couchbase = .{
        .url = "https://github.com/yourusername/couchbase-zig-client/archive/main.tar.gz",
    },
},

Add to build.zig:

const couchbase = b.dependency("couchbase", .{
    .target = target,
    .optimize = optimize,
});
exe.root_module.addImport("couchbase", couchbase.module("couchbase"));

Usage

const std = @import("std");
const couchbase = @import("couchbase");

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();
    const allocator = gpa.allocator();

    var client = try couchbase.Client.connect(allocator, .{
        .connection_string = "couchbase://localhost",
        .username = "Administrator",
        .password = "password",
        .bucket = "default",
    });
    defer client.disconnect();

    const result = try client.upsert("user:123", \\{"name": "John Doe", "age": 30}, .{});
    
    var get_result = try client.get("user:123");
    defer get_result.deinit();
}

Examples

  • examples/basic.zig - CRUD operations
  • examples/kv_operations.zig - Key-value operations
  • examples/query.zig - N1QL queries
  • examples/diagnostics.zig - Diagnostics & Monitoring

Build and run:

zig build examples
zig build run-basic
zig build run-kv_operations
zig build run-query
zig build run-diagnostics

API

Connection

var client = try couchbase.Client.connect(allocator, .{
    .connection_string = "couchbase://localhost",
    .username = "Administrator",
    .password = "password",
    .bucket = "default",
    .timeout_ms = 10000,
});
defer client.disconnect();

Key-Value Operations

// Get document
var result = try client.get("doc-id");
defer result.deinit();

// Insert (fails if exists)
_ = try client.insert("doc-id", content, .{});

// Upsert (insert or replace)
_ = try client.upsert("doc-id", content, .{});

// Replace (fails if not exists)
_ = try client.replace("doc-id", content, .{ .cas = existing_cas });

// Remove
_ = try client.remove("doc-id", .{});

// Counter operations
const result = try client.increment("counter-id", 10, .{ .initial = 0 });
const result = try client.decrement("counter-id", 5, .{});

// Touch (update expiration)
_ = try client.touch("doc-id", 3600);

Durability

_ = try client.upsert("doc-id", content, .{
    .durability = .{
        .level = .majority,
    },
});

Queries

// Basic N1QL query
const query = "SELECT * FROM `default` WHERE type = $1";
var result = try client.query(allocator, query, .{
    .consistency = .request_plus,
    .adhoc = true,
});
defer result.deinit();

// Advanced query with profiling and performance options
const advanced_query = "SELECT * FROM `default` WHERE type = 'user' ORDER BY created_at";
var options = QueryOptions{
    .profile = .timings,
    .read_only = true,
    .client_context_id = "user-query-123",
    .scan_cap = 100,
    .scan_wait = 1000,
    .flex_index = true,
    .pretty = true,
    .metrics = true,
};
var advanced_result = try client.query(allocator, advanced_query, options);
defer advanced_result.deinit();

// Analytics query
const analytics_query = "SELECT COUNT(*) as total FROM `default` WHERE type = 'user'";
const analytics_options = AnalyticsOptions{
    .timeout_ms = 300000,
    .priority = true,
    .read_only = true,
    .client_context_id = "analytics-123",
};
var analytics_result = try client.analyticsQuery(allocator, analytics_query, analytics_options);
defer analytics_result.deinit();

// Search query (Full-Text Search)
const search_query = \\{"query": {"match": "user"}, "size": 10}
;
const search_options = SearchOptions{
    .timeout_ms = 30000,
    .limit = 10,
    .explain = true,
    .highlight_style = "html",
};
var search_result = try client.searchQuery(allocator, "user_index", search_query, search_options);
defer search_result.deinit();

for (result.rows) |row| {
    std.debug.print("Row: {s}\n", .{row});
}

Error Handling

const result = client.get("doc-id") catch |err| switch (err) {
    error.DocumentNotFound => {
        return;
    },
    error.Timeout => {
        return;
    },
    else => return err,
};

Client Methods

  • connect(allocator, options) - Connect to cluster
  • disconnect() - Disconnect and cleanup
  • get(key) - Get document
  • getFromReplica(key, mode) - Get from replica
  • insert(key, value, options) - Insert document
  • upsert(key, value, options) - Insert or replace document
  • replace(key, value, options) - Replace document
  • remove(key, options) - Remove document
  • increment(key, delta, options) - Increment counter
  • decrement(key, delta, options) - Decrement counter
  • touch(key, expiry) - Update expiration
  • unlock(key, cas) - Unlock document
  • query(allocator, statement, options) - Execute N1QL query
  • lookupIn(allocator, key, specs) - Subdocument lookup
  • mutateIn(allocator, key, specs, options) - Subdocument mutation
  • ping(allocator) - Ping services (stub)
  • diagnostics(allocator) - Get diagnostics (stub)

Error Types

  • error.DocumentNotFound
  • error.DocumentExists
  • error.DocumentLocked
  • error.Timeout
  • error.AuthenticationFailed
  • error.BucketNotFound
  • error.TemporaryFailure
  • error.DurabilityAmbiguous
  • error.InvalidArgument

Diagnostics & Monitoring

// Health monitoring
var ping_result = try client.ping(allocator);
defer ping_result.deinit();
std.debug.print("Services: {}\n", .{ping_result.services.len});

// Diagnostics
var diag_result = try client.diagnostics(allocator);
defer diag_result.deinit();
for (diag_result.services) |service| {
    std.debug.print("Service: {s} - {}us\n", .{service.id, service.last_activity_us});
}

// Cluster configuration
var cluster_config = try client.getClusterConfig(allocator);
defer cluster_config.deinit();
std.debug.print("Config: {s}\n", .{cluster_config.config});

// SDK metrics
var metrics = try client.getSdkMetrics(allocator);
defer metrics.deinit();
var iterator = metrics.metrics.iterator();
while (iterator.next()) |entry| {
    std.debug.print("Metric: {s}\n", .{entry.key_ptr.*});
}

// HTTP tracing
try client.enableHttpTracing(allocator);
var traces = try client.getHttpTraces(allocator);
defer traces.deinit();
for (traces.traces) |trace| {
    std.debug.print("Trace: {s} {s} - {}ms\n", .{trace.method, trace.url, trace.duration_ms});
}

Binary Protocol Features

// Initialize binary protocol
var client = try couchbase.Client.connect(allocator, .{
    .connection_string = "couchbase://localhost",
    .username = "Administrator",
    .password = "password",
    .bucket = "default",
});

// Negotiate binary protocol features
try client.negotiateBinaryFeatures();
const features = client.getBinaryFeatureFlags();
const protocol_version = client.getProtocolVersion();

std.debug.print("Features: {v}\n", .{features});
if (protocol_version) |pv| {
    std.debug.print("Protocol Version: {v}\n", .{pv});
}

// Binary document operations
const binary_data = "Hello, Binary World!";
var binary_doc = couchbase.BinaryDocument{
    .data = binary_data,
    .content_type = try allocator.dupe(u8, "application/octet-stream"),
    .flags = 0x12345678,
    .allocator = allocator,
};
defer binary_doc.deinit(allocator);

// Create collection context
var context = couchbase.BinaryOperationContext.init(allocator);
defer context.deinit();
try context.withCollection(allocator, "test", "default");

// Store binary document
try client.storeBinary("binary-key-1", binary_doc, &context);

// Retrieve binary document
var retrieved_doc = try client.getBinary("binary-key-1", &context);
defer retrieved_doc.deinit(allocator);

std.debug.print("Retrieved: {s}\n", .{retrieved_doc.data});
if (retrieved_doc.content_type) |ct| {
    std.debug.print("Content type: {s}\n", .{ct});
}

// DCP (Database Change Protocol) operations
try client.startDcpStream("default", 0);

// Process DCP events
if (try client.getNextDcpEvent()) |event| {
    var mutable_event = event;
    defer mutable_event.deinit();
    
    std.debug.print("DCP Event: {v}\n", .{mutable_event});
}

Custom Format Specifiers

const version = couchbase.ProtocolVersion{ .major = 1, .minor = 2, .patch = 3 };
const flags = couchbase.FeatureFlags{ .collections = true, .durability = true };

// Different format options
std.debug.print("Version - Default: {}\n", .{version});        // "1.2.3"
std.debug.print("Version - Simple: {s}\n", .{version});        // "1.2.3"
std.debug.print("Version - Verbose: {v}\n", .{version});       // "Version 1.2.3"
std.debug.print("Version - Compact: {c}\n", .{version});       // "1.2"

std.debug.print("Flags - Default: {}\n", .{flags});            // "collections=true,dcp=false,..."
std.debug.print("Flags - Simple: {s}\n", .{flags});            // "collections=true,dcp=false,..."
std.debug.print("Flags - Verbose: {v}\n", .{flags});           // "FeatureFlags{ collections: true, ... }"
std.debug.print("Flags - Compact: {c}\n", .{flags});           // "collections,durability"

Building

zig build
zig build test
zig build examples

Testing

Tests require a running Couchbase Server instance. Configure via environment variables:

export COUCHBASE_HOST="couchbase://127.0.0.1"  # or any connection string
export COUCHBASE_USER="tester"                  # default: tester
export COUCHBASE_PASSWORD="password"            # default: password
export COUCHBASE_BUCKET="default"               # default: default

Defaults (if env vars not set):

  • Host: couchbase://127.0.0.1
  • User: tester
  • Password: password
  • Bucket: default

Setup Couchbase for Testing

Start server with Docker:

docker run -d --name couchbase \
  -p 8091-8096:8091-8096 \
  -p 11210-11211:11210-11211 \
  couchbase:community

Then configure it:

  1. Go to http://localhost:8091
  2. Setup cluster (click "Setup New Cluster")
  3. Create admin user (can use tester/password)
  4. Create a bucket named "default" in the Buckets section
  5. Grant the user full access to the bucket

Or use the CLI:

# Wait for server to start
sleep 20

# Initialize cluster
docker exec couchbase couchbase-cli cluster-init \
  --cluster localhost \
  --cluster-username tester \
  --cluster-password password \
  --services data,index,query \
  --cluster-ramsize 512 \
  --cluster-index-ramsize 256

# Create bucket
docker exec couchbase couchbase-cli bucket-create \
  --cluster localhost \
  --username tester \
  --password password \
  --bucket default \
  --bucket-type couchbase \
  --bucket-ramsize 256

Run tests:

# Unit tests only (no server required)
zig build test-unit

# Integration tests (requires server)
zig build test-integration

# Coverage tests (requires server)
zig build test-coverage

# All tests
zig build test-all

Test configuration uses environment variables. See src/root.zig (getTestConfig function).

See TESTING.md and GAP_ANALYSIS.md for detailed testing documentation and feature comparison.

Structure

  • src/c.zig - C bindings
  • src/error.zig - Error types
  • src/types.zig - Common types
  • src/client.zig - Client interface
  • src/operations.zig - Operation implementations
  • src/root.zig - Public API

Implementation Notes

  • Uses callbacks internally, presents synchronous API
  • Copies string data for memory safety
  • Single-threaded per client instance
  • Blocking I/O on lcb_wait

Status

Beta. API may change before 1.0 release.

Implemented:

  • Connection management with env vars
  • KV operations (get, insert, upsert, replace, remove, append, prepend)
  • EXISTS operation
  • Subdocument operations (lookupIn, mutateIn with all 12 operation types)
  • View queries (map/reduce with all options)
  • Counter operations
  • Touch and unlock
  • CAS support
  • Durability levels
  • N1QL queries
  • Replica reads
  • Error handling
  • 69 comprehensive tests

Not implemented:

  • Analytics queries
  • Full-text search
  • Spatial views
  • Transactions
  • Connection pooling
  • Async support

License

MIT License

Links

(First beta release of the Couchbase Zig Client, an idiomatic Zig wrapper for libcouchbase. This release provides type-safe, memory-safe access to Couchbase Server with support for core key-value operations and N1QL queries.)