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