prefect server in zig
at main 101 lines 3.3 kB view raw
1const std = @import("std"); 2const mem = std.mem; 3const Allocator = mem.Allocator; 4 5pub const Dialect = enum { 6 sqlite, 7 postgres, 8 9 /// Returns the function/expression for current timestamp 10 pub fn now(self: Dialect) []const u8 { 11 return switch (self) { 12 .sqlite => "datetime('now')", 13 .postgres => "NOW()", 14 }; 15 } 16 17 /// Returns the placeholder format for parameter N (1-indexed) 18 pub fn placeholder(self: Dialect, buf: *[8]u8, n: usize) []const u8 { 19 return switch (self) { 20 .sqlite => "?", 21 .postgres => std.fmt.bufPrint(buf, "${d}", .{n}) catch "?", 22 }; 23 } 24 25 /// Rewrites SQL with ? placeholders to dialect-specific format 26 /// For SQLite: returns input unchanged 27 /// For PostgreSQL: rewrites ? to $1, $2, etc. 28 pub fn rewritePlaceholders(self: Dialect, alloc: Allocator, sql: []const u8) ![]const u8 { 29 if (self == .sqlite) { 30 return sql; // no rewrite needed 31 } 32 33 // count placeholders 34 var count: usize = 0; 35 for (sql) |c| { 36 if (c == '?') count += 1; 37 } 38 39 if (count == 0) { 40 return sql; 41 } 42 43 // allocate output (each ? becomes $N, max 4 chars for reasonable N) 44 var output = try alloc.alloc(u8, sql.len + count * 4); 45 var out_idx: usize = 0; 46 var param_num: usize = 1; 47 48 for (sql) |c| { 49 if (c == '?') { 50 var buf: [8]u8 = undefined; 51 const ph = std.fmt.bufPrint(&buf, "${d}", .{param_num}) catch "$?"; 52 @memcpy(output[out_idx..][0..ph.len], ph); 53 out_idx += ph.len; 54 param_num += 1; 55 } else { 56 output[out_idx] = c; 57 out_idx += 1; 58 } 59 } 60 61 // Shrink to exact size so free() works correctly 62 if (alloc.resize(output, out_idx)) { 63 return output[0..out_idx]; 64 } 65 // If resize not supported, realloc 66 const exact = alloc.realloc(output, out_idx) catch return output[0..out_idx]; 67 return exact; 68 } 69 70 /// Returns the INSERT conflict ignore syntax 71 /// SQLite: INSERT OR IGNORE INTO ... 72 /// PostgreSQL: INSERT INTO ... ON CONFLICT DO NOTHING 73 pub fn insertOrIgnorePrefix(self: Dialect) []const u8 { 74 return switch (self) { 75 .sqlite => "INSERT OR IGNORE INTO", 76 .postgres => "INSERT INTO", 77 }; 78 } 79 80 pub fn insertOrIgnoreSuffix(self: Dialect) []const u8 { 81 return switch (self) { 82 .sqlite => "", 83 .postgres => " ON CONFLICT DO NOTHING", 84 }; 85 } 86}; 87 88test "rewritePlaceholders - sqlite unchanged" { 89 const alloc = std.testing.allocator; 90 const sql = "SELECT * FROM foo WHERE a = ? AND b = ?"; 91 const result = try Dialect.sqlite.rewritePlaceholders(alloc, sql); 92 try std.testing.expectEqualStrings(sql, result); 93} 94 95test "rewritePlaceholders - postgres" { 96 const alloc = std.testing.allocator; 97 const sql = "SELECT * FROM foo WHERE a = ? AND b = ?"; 98 const result = try Dialect.postgres.rewritePlaceholders(alloc, sql); 99 defer alloc.free(result); 100 try std.testing.expectEqualStrings("SELECT * FROM foo WHERE a = $1 AND b = $2", result); 101}