2024-10-16 12:01:16 +02:00
|
|
|
const std = @import("std");
|
|
|
|
const _sql = @import("sql.zig");
|
|
|
|
const errors = @import("errors.zig");
|
|
|
|
|
|
|
|
const Static = @This();
|
|
|
|
|
|
|
|
/// Create a value condition on a column.
|
2024-11-22 15:40:10 +01:00
|
|
|
pub fn value(comptime ValueType: type, allocator: std.mem.Allocator, comptime _column: []const u8, comptime operator: []const u8, _value: ValueType) !_sql.RawQuery {
|
2024-10-16 12:01:16 +02:00
|
|
|
// Initialize the SQL condition string.
|
|
|
|
var comptimeSql: [_column.len + 1 + operator.len + 1 + 1]u8 = undefined;
|
|
|
|
@memcpy(comptimeSql[0.._column.len], _column);
|
|
|
|
@memcpy(comptimeSql[_column.len.._column.len + 1], " ");
|
|
|
|
@memcpy(comptimeSql[_column.len + 1..(_column.len + 1 + operator.len)], operator);
|
|
|
|
@memcpy(comptimeSql[_column.len + 1 + operator.len..], " ?");
|
|
|
|
|
|
|
|
// Initialize SQL buffer and set its value to comptime-generated SQL.
|
|
|
|
const sqlBuf = try allocator.alloc(u8, comptimeSql.len);
|
|
|
|
std.mem.copyForwards(u8, sqlBuf, &comptimeSql);
|
|
|
|
|
|
|
|
// Initialize parameters array.
|
2024-11-22 15:40:10 +01:00
|
|
|
const params = try allocator.alloc(_sql.RawQueryParameter, 1);
|
|
|
|
params[0] = try _sql.RawQueryParameter.fromValue(_value);
|
2024-10-16 12:01:16 +02:00
|
|
|
|
|
|
|
// Return the built SQL condition.
|
|
|
|
return .{
|
|
|
|
.sql = sqlBuf,
|
|
|
|
.params = params,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Create a column condition on a column.
|
2024-11-22 15:40:10 +01:00
|
|
|
pub fn column(allocator: std.mem.Allocator, comptime _column: []const u8, comptime operator: []const u8, comptime valueColumn: []const u8) !_sql.RawQuery {
|
2024-10-16 12:01:16 +02:00
|
|
|
// Initialize the SQL condition string.
|
|
|
|
var comptimeSql: [_column.len + 1 + operator.len + 1 + valueColumn.len]u8 = undefined;
|
|
|
|
@memcpy(comptimeSql[0.._column.len], _column);
|
|
|
|
@memcpy(comptimeSql[_column.len.._column.len + 1], " ");
|
|
|
|
@memcpy(comptimeSql[_column.len + 1..(_column.len + 1 + operator.len)], operator);
|
|
|
|
@memcpy(comptimeSql[_column.len + 1 + operator.len.._column.len + 1 + operator.len + 1], " ");
|
|
|
|
@memcpy(comptimeSql[_column.len + 1 + operator.len + 1..], valueColumn);
|
|
|
|
|
|
|
|
// Initialize SQL buffer and set its value to comptime-generated SQL.
|
|
|
|
const sqlBuf = try allocator.alloc(u8, comptimeSql.len);
|
|
|
|
std.mem.copyForwards(u8, sqlBuf, &comptimeSql);
|
|
|
|
|
|
|
|
// Return the built SQL condition.
|
|
|
|
return .{
|
|
|
|
.sql = sqlBuf,
|
2024-11-22 15:40:10 +01:00
|
|
|
.params = &[0]_sql.RawQueryParameter{},
|
2024-10-16 12:01:16 +02:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Create an IN condition on a column.
|
2024-11-22 15:40:10 +01:00
|
|
|
pub fn in(comptime ValueType: type, allocator: std.mem.Allocator, _column: []const u8, _value: []const ValueType) !_sql.RawQuery {
|
2024-10-16 12:01:16 +02:00
|
|
|
// Generate parameters SQL.
|
|
|
|
const parametersSql = try _sql.generateParametersSql(allocator, _value.len);
|
|
|
|
// Get all query parameters from given values.
|
2024-11-22 15:40:10 +01:00
|
|
|
var valueParameters: []_sql.RawQueryParameter = try allocator.alloc(_sql.RawQueryParameter, _value.len);
|
2024-10-16 12:01:16 +02:00
|
|
|
for (0.._value.len) |i| {
|
|
|
|
// Convert every given value to a query parameter.
|
2024-11-22 15:40:10 +01:00
|
|
|
valueParameters[i] = try _sql.RawQueryParameter.fromValue(_value[i]);
|
2024-10-16 12:01:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Initialize the SQL condition string.
|
|
|
|
var sqlBuf: []u8 = try allocator.alloc(u8, _column.len + 1 + 2 + 1 + 1 + parametersSql.len + 1);
|
|
|
|
std.mem.copyForwards(u8, sqlBuf[0.._column.len], _column);
|
|
|
|
std.mem.copyForwards(u8, sqlBuf[_column.len.._column.len + 1 + 2 + 1 + 1], " IN (");
|
|
|
|
std.mem.copyForwards(u8, sqlBuf[_column.len + 1 + 2 + 1 + 1.._column.len + 1 + 2 + 1 + 1 + parametersSql.len], parametersSql);
|
|
|
|
std.mem.copyForwards(u8, sqlBuf[_column.len + 1 + 2 + 1 + 1 + parametersSql.len..], ")");
|
|
|
|
|
|
|
|
// Return the built SQL condition.
|
|
|
|
return .{
|
|
|
|
.sql = sqlBuf,
|
|
|
|
.params = valueParameters,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Generic conditions combiner generator.
|
2024-11-22 15:40:10 +01:00
|
|
|
fn conditionsCombiner(comptime keyword: []const u8, allocator: std.mem.Allocator, subconditions: []const _sql.RawQuery) !_sql.RawQuery {
|
2024-10-16 12:01:16 +02:00
|
|
|
if (subconditions.len == 0) {
|
|
|
|
// At least one condition is required.
|
|
|
|
return errors.ZrmError.AtLeastOneConditionRequired;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Full keyword constant.
|
|
|
|
const fullKeyword = " " ++ keyword ++ " ";
|
|
|
|
|
|
|
|
// Compute size of the SQL to generate, and the count of query parameters in total.
|
|
|
|
var sqlSize: usize = 1 + 1; // parentheses.
|
|
|
|
var queryParametersCount: usize = 0;
|
|
|
|
for (subconditions) |subcondition| {
|
|
|
|
sqlSize += subcondition.sql.len;
|
|
|
|
queryParametersCount += subcondition.params.len;
|
|
|
|
}
|
|
|
|
// There are n-1 keywords.
|
|
|
|
sqlSize += (subconditions.len - 1) * fullKeyword.len;
|
|
|
|
|
|
|
|
// Initialize the SQL condition string.
|
|
|
|
var sqlBuf = try allocator.alloc(u8, sqlSize);
|
|
|
|
// Initialize the query parameters array.
|
2024-11-22 15:40:10 +01:00
|
|
|
var parameters = try allocator.alloc(_sql.RawQueryParameter, queryParametersCount);
|
2024-10-16 12:01:16 +02:00
|
|
|
var sqlBufCursor: usize = 0; var parametersCursor: usize = 0;
|
|
|
|
|
|
|
|
// Add first parenthesis.
|
|
|
|
sqlBuf[sqlBufCursor] = '('; sqlBufCursor += 1;
|
|
|
|
|
|
|
|
// Add all subconditions.
|
|
|
|
for (0..subconditions.len) |i| {
|
|
|
|
// Add each subcondition to SQL.
|
|
|
|
const subcondition = subconditions[i];
|
|
|
|
std.mem.copyForwards(u8, sqlBuf[sqlBufCursor..sqlBufCursor + subcondition.sql.len], subcondition.sql);
|
|
|
|
sqlBufCursor += subcondition.sql.len;
|
|
|
|
|
|
|
|
if (i < subconditions.len - 1) {
|
|
|
|
// Append the keyword, if required.
|
|
|
|
@memcpy(sqlBuf[sqlBufCursor..sqlBufCursor + fullKeyword.len], fullKeyword);
|
|
|
|
sqlBufCursor += fullKeyword.len;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add query parameters to the array.
|
2024-11-22 15:40:10 +01:00
|
|
|
std.mem.copyForwards(_sql.RawQueryParameter, parameters[parametersCursor..parametersCursor+subcondition.params.len], subcondition.params);
|
2024-10-16 12:01:16 +02:00
|
|
|
parametersCursor += subcondition.params.len;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add last parenthesis.
|
|
|
|
sqlBuf[sqlBufCursor] = ')'; sqlBufCursor += 1;
|
|
|
|
|
|
|
|
// Return built SQL params.
|
|
|
|
return .{
|
|
|
|
.sql = sqlBuf,
|
|
|
|
.params = parameters,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Create an AND condition between multiple sub-conditions.
|
2024-11-22 15:40:10 +01:00
|
|
|
pub fn @"and"(allocator: std.mem.Allocator, subconditions: []const _sql.RawQuery) !_sql.RawQuery {
|
2024-10-16 12:01:16 +02:00
|
|
|
return conditionsCombiner("AND", allocator, subconditions);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Create an OR condition between multiple sub-conditions.
|
2024-11-22 15:40:10 +01:00
|
|
|
pub fn @"or"(allocator: std.mem.Allocator, subconditions: []const _sql.RawQuery) !_sql.RawQuery {
|
2024-10-16 12:01:16 +02:00
|
|
|
return conditionsCombiner("OR", allocator, subconditions);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// A conditions builder.
|
|
|
|
pub const Builder = struct {
|
|
|
|
const Self = @This();
|
|
|
|
|
|
|
|
allocator: std.mem.Allocator,
|
|
|
|
|
|
|
|
/// Create a value condition on a column.
|
2024-11-22 15:40:10 +01:00
|
|
|
pub fn value(self: Self, comptime ValueType: type, comptime _column: []const u8, comptime operator: []const u8, _value: ValueType) !_sql.RawQuery {
|
2024-10-16 12:01:16 +02:00
|
|
|
return Static.value(ValueType, self.allocator, _column, operator, _value);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Create a column condition on a column.
|
2024-11-22 15:40:10 +01:00
|
|
|
pub fn column(self: Self, comptime _column: []const u8, comptime operator: []const u8, comptime valueColumn: []const u8) !_sql.RawQuery {
|
2024-10-16 12:01:16 +02:00
|
|
|
return Static.column(self.allocator, _column, operator, valueColumn);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Create an IN condition on a column.
|
2024-11-22 15:40:10 +01:00
|
|
|
pub fn in(self: Self, comptime ValueType: type, _column: []const u8, _value: []const ValueType) !_sql.RawQuery {
|
2024-10-16 12:01:16 +02:00
|
|
|
return Static.in(ValueType, self.allocator, _column, _value);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Create an AND condition between multiple sub-conditions.
|
2024-11-22 15:40:10 +01:00
|
|
|
pub fn @"and"(self: Self, subconditions: []const _sql.RawQuery) !_sql.RawQuery {
|
2024-10-16 12:01:16 +02:00
|
|
|
return Static.@"and"(self.allocator, subconditions);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Create an OR condition between multiple sub-conditions.
|
2024-11-22 15:40:10 +01:00
|
|
|
pub fn @"or"(self: Self, subconditions: []const _sql.RawQuery) !_sql.RawQuery {
|
2024-10-16 12:01:16 +02:00
|
|
|
return Static.@"or"(self.allocator, subconditions);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Initialize a new conditions builder with the given allocator.
|
|
|
|
pub fn init(allocator: std.mem.Allocator) Self {
|
|
|
|
return .{
|
|
|
|
.allocator = allocator,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
};
|