SchemaLang Examples

Real-world examples demonstrating SchemaLang features.

Simple Struct

struct User {
    int64: id: primary_key: required: auto_increment: 
        description("Unique user ID");
    string: username: required: unique: 
        description("Username");
    string: email: required: 
        description("Email address");
}

Relationships

struct Post {
    int64: id: primary_key: required: auto_increment: 
        description("Post ID");
    string: title: required: 
        description("Post title");
    string: content: required: 
        description("Post content");
    int64: authorId: required: reference(User.id): 
        description("Author user ID");
}

Arrays

struct Article {
    int64: id: primary_key: required: auto_increment: 
        description("Article ID");
    string: title: required: 
        description("Article title");
    array<string>: tags: optional: unique_items: min_items(1): max_items(10): 
        description("Article tags");
}

Enumerations

enum UserRole {
    Guest = 0,
    User = 1,
    Admin = 2
}

struct User {
    int64: id: primary_key: required: auto_increment: 
        description("User ID");
    string: username: required: 
        description("Username");
    UserRole: role: required: 
        description("User role");
}

Complete System

enum OrderStatus {
    Pending,
    Processing,
    Shipped,
    Delivered,
    Cancelled
}

struct Customer: version(1.0.0) {
    int64: id: primary_key: required: auto_increment: 
        description("Customer ID");
    string: name: required: 
        description("Customer name");
    string: email: required: unique: 
        description("Customer email");
}

struct Product: version(1.0.0) {
    int64: id: primary_key: required: auto_increment: 
        description("Product ID");
    string: name: required: 
        description("Product name");
    double: price: required: 
        description("Product price in USD");
    int32: stock: required: 
        description("Available stock");
}

struct Order: version(1.0.0) {
    int64: id: primary_key: required: auto_increment: 
        description("Order ID");
    int64: customerId: required: reference(Customer.id): 
        description("Customer ID");
    OrderStatus: status: required: 
        description("Order status");
    double: total: required: 
        description("Order total amount");
}

struct OrderItem: version(1.0.0) {
    int64: id: primary_key: required: auto_increment: 
        description("Order item ID");
    int64: orderId: required: reference(Order.id): 
        description("Order ID");
    int64: productId: required: reference(Product.id): 
        description("Product ID");
    int32: quantity: required: 
        description("Quantity ordered");
    double: price: required: 
        description("Price at time of order");
}

Using Generated Code

SchemaLang generates a complete database abstraction layer with query builders, making database operations type-safe and intuitive.

Generated SQLiteDB Class

class SQLiteDB {
public:
    // Query builders for each struct
    auto SelectCustomer() -> SQLiteQueryBuilder<Customer>;
    auto SelectProduct() -> SQLiteQueryBuilder<Product>;
    auto SelectOrder() -> SQLiteQueryBuilder<Order>;
    auto SelectOrderItem() -> SQLiteQueryBuilder<OrderItem>;
    
    // Connection with automatic migrations
    void connect();
    sqlite3* getDB();
};

Query Builder Usage

// Select with conditions
auto high_value_orders = db->SelectOrder()
    .WhereGreaterThan("total", "1000.00")
    .OrderBy("total", "DESC")
    .Limit(10)
    .Exec<Order>();

// Complex queries with multiple conditions
auto pending_orders = db->SelectOrder()
    .WhereEquals("status", std::to_string(OrderStatus::Pending))
    .WhereEquals("customer_id", std::to_string(customer_id))
    .OrderBy("id", "DESC")
    .Exec<Order>();

// Get first result
auto customer = db->SelectCustomer()
    .WhereEquals("email", email)
    .First<Customer>();

Real HTTP Server Example

// GET /api/orders endpoint
void handle_get_orders(int64_t user_id) {
    // Validate access
    if (!db->is_admin_or_dm(user_id)) {
        send_error("Forbidden", 403);
        return;
    }
    
    // Build query dynamically
    auto query = db->SelectOrder();
    
    // Filter by status if provided
    if (params.contains("status")) {
        query.WhereEquals("status", params["status"]);
    }
    
    // Execute query
    auto orders = query
        .OrderBy("id", "DESC")
        .Limit(50)
        .Exec<Order>();
    
    // Convert to JSON using generated methods
    json response = json::array();
    for (const auto& order_ptr : orders) {
        if (order_ptr) {
            response.push_back(order_ptr->toJSON());
        }
    }
    
    send_json_response(response);
}

// POST /api/orders endpoint
void handle_create_order(const json& request_body) {
    // Create from JSON using generated method
    auto order = std::make_shared<Order>();
    order->fromJSON(request_body);
    order->setStatus(OrderStatus::Pending);
    
    // Validate and insert
    if (order->SQLiteInsert(db->getDB())) {
        send_json_response(order->toJSON(), 201);
    } else {
        send_error("Failed to create order", 500);
    }
}

// Custom database class extending generated code
class PopulatedSQLiteDB : public SQLiteDB {
public:
    // Add custom helper methods
    bool user_has_access_to_order(int64_t user_id, 
                                   int64_t order_id) {
        auto order = SelectOrder()
            .WhereEquals("id", std::to_string(order_id))
            .First<Order>();
            
        if (!order) return false;
        
        // Check if user owns the customer
        return order->getCustomer_id() == user_id ||
               is_admin_or_dm(user_id);
    }
    
    std::vector<int64_t> get_accessible_order_ids(
        int64_t user_id) {
        // Use generated query builder
        auto orders = SelectOrder()
            .WhereEquals("customer_id", 
                        std::to_string(user_id))
            .Exec<Order>();
            
        std::vector<int64_t> ids;
        for (const auto& order : orders) {
            if (order) ids.push_back(order->getId());
        }
        return ids;
    }
};

Key Benefits

  • Type Safety: All queries are type-checked at compile time
  • No SQL Injection: All values properly escaped by query builder
  • Auto-complete: IDE provides suggestions for all methods
  • Migrations: Database schema updated automatically on connect()
  • JSON Integration: Seamless conversion between database and JSON
  • Extensible: Inherit from generated classes to add custom logic