milestone 18: collapse duplicated infrastructure into shared listener core, crud list helper, resource shells, transport race, name and line helpers, ui modules
CI / test (push) Successful in 1m22s
CI / test-aarch64 (push) Successful in 5m6s
CI / frontend (push) Successful in 45s
CI / cross (push) Successful in 7m53s
CI / docker (push) Failing after 1h10m57s

This commit is contained in:
2026-08-07 18:20:30 +02:00
parent c50c6d285a
commit 6f67940995
82 changed files with 3167 additions and 3114 deletions
+40 -74
View File
@@ -25,34 +25,23 @@ const list_local_records_sql =
/// Every string in the result is a heap copy owned by `gpa`.
pub fn listLocalRecords(database: *db.Db, gpa: Allocator) db.Error!std.ArrayList(model.LocalRecord) {
var stmt = try database.prepare(list_local_records_sql);
defer stmt.deinit();
return crud.listRows(model.LocalRecord, database, gpa, list_local_records_sql, readLocalRecord);
}
var out: std.ArrayList(model.LocalRecord) = .empty;
// `errdefer`s run in reverse: the free pass is declared last so it runs
// before the backing array is released.
errdefer out.deinit(gpa);
errdefer freeLocalRecords(gpa, out.items);
while (try stmt.step()) {
const name = try stmt.columnTextAlloc(gpa, 0);
errdefer gpa.free(name);
const value = try stmt.columnTextAlloc(gpa, 2);
errdefer gpa.free(value);
// The DDL's CHECK constraint makes the decode total for any row nxdns
// wrote; `error.Mismatch` covers a row that something else wrote.
const rtype = model.RecordType.fromDb(stmt.columnText(1)) orelse return error.Mismatch;
const ttl = std.math.cast(u32, stmt.columnInt(3)) orelse return error.Mismatch;
try out.append(gpa, .{ .name = name, .rtype = rtype, .value = value, .ttl = ttl });
}
return out;
fn readLocalRecord(stmt: *db.Stmt, gpa: Allocator) db.Error!model.LocalRecord {
// The DDL's CHECK constraint makes the decode total for any row nxdns
// wrote; `error.Mismatch` covers a row that something else wrote.
const rtype = model.RecordType.fromDb(stmt.columnText(1)) orelse return error.Mismatch;
const ttl = std.math.cast(u32, stmt.columnInt(3)) orelse return error.Mismatch;
const name = try stmt.columnTextAlloc(gpa, 0);
errdefer gpa.free(name);
const value = try stmt.columnTextAlloc(gpa, 2);
errdefer gpa.free(value);
return .{ .name = name, .rtype = rtype, .value = value, .ttl = ttl };
}
pub fn freeLocalRecords(gpa: Allocator, items: []const model.LocalRecord) void {
for (items) |item| {
gpa.free(item.name);
gpa.free(item.value);
}
crud.freeRows(model.LocalRecord, gpa, items);
}
const insert_local_record_sql =
@@ -83,28 +72,25 @@ pub fn countLocalRecords(database: *db.Db) db.Error!i64 {
// ---------------------------------------------------------------------------
pub fn listForwardZones(database: *db.Db, gpa: Allocator) db.Error!std.ArrayList(model.ForwardZone) {
var stmt = try database.prepare("SELECT zone, resolver FROM forward_zones ORDER BY zone");
defer stmt.deinit();
return crud.listRows(
model.ForwardZone,
database,
gpa,
"SELECT zone, resolver FROM forward_zones ORDER BY zone",
readForwardZone,
);
}
var out: std.ArrayList(model.ForwardZone) = .empty;
errdefer out.deinit(gpa);
errdefer freeForwardZones(gpa, out.items);
while (try stmt.step()) {
const zone = try stmt.columnTextAlloc(gpa, 0);
errdefer gpa.free(zone);
const resolver = try stmt.columnTextAlloc(gpa, 1);
errdefer gpa.free(resolver);
try out.append(gpa, .{ .zone = zone, .resolver = resolver });
}
return out;
fn readForwardZone(stmt: *db.Stmt, gpa: Allocator) db.Error!model.ForwardZone {
const zone = try stmt.columnTextAlloc(gpa, 0);
errdefer gpa.free(zone);
const resolver = try stmt.columnTextAlloc(gpa, 1);
errdefer gpa.free(resolver);
return .{ .zone = zone, .resolver = resolver };
}
pub fn freeForwardZones(gpa: Allocator, items: []const model.ForwardZone) void {
for (items) |item| {
gpa.free(item.zone);
gpa.free(item.resolver);
}
crud.freeRows(model.ForwardZone, gpa, items);
}
pub fn insertForwardZone(database: *db.Db, item: model.ForwardZone, ctx: InsertContext) db.Error!void {
@@ -145,28 +131,15 @@ const list_local_record_rows_sql =
/// Same order as `listLocalRecords`; every string is a heap copy owned by `gpa`.
pub fn listLocalRecordRows(database: *db.Db, gpa: Allocator) db.Error!std.ArrayList(LocalRecordRow) {
var stmt = try database.prepare(list_local_record_rows_sql);
defer stmt.deinit();
var out: std.ArrayList(LocalRecordRow) = .empty;
errdefer out.deinit(gpa);
errdefer freeLocalRecordRows(gpa, out.items);
while (try stmt.step()) {
const row = try readLocalRecordRow(&stmt, gpa);
errdefer freeLocalRecordRow(gpa, row);
try out.append(gpa, row);
}
return out;
return crud.listRows(LocalRecordRow, database, gpa, list_local_record_rows_sql, readLocalRecordRow);
}
pub fn freeLocalRecordRow(gpa: Allocator, row: LocalRecordRow) void {
gpa.free(row.name);
gpa.free(row.value);
crud.freeRow(LocalRecordRow, gpa, row);
}
pub fn freeLocalRecordRows(gpa: Allocator, items: []const LocalRecordRow) void {
for (items) |item| freeLocalRecordRow(gpa, item);
crud.freeRows(LocalRecordRow, gpa, items);
}
pub fn getLocalRecord(database: *db.Db, gpa: Allocator, id: i64) db.Error!?LocalRecordRow {
@@ -232,28 +205,21 @@ pub const ForwardZoneRow = struct { id: i64, zone: []const u8, resolver: []const
/// Same order as `listForwardZones`; every string is a heap copy owned by `gpa`.
pub fn listForwardZoneRows(database: *db.Db, gpa: Allocator) db.Error!std.ArrayList(ForwardZoneRow) {
var stmt = try database.prepare("SELECT id, zone, resolver FROM forward_zones ORDER BY zone");
defer stmt.deinit();
var out: std.ArrayList(ForwardZoneRow) = .empty;
errdefer out.deinit(gpa);
errdefer freeForwardZoneRows(gpa, out.items);
while (try stmt.step()) {
const row = try readForwardZoneRow(&stmt, gpa);
errdefer freeForwardZoneRow(gpa, row);
try out.append(gpa, row);
}
return out;
return crud.listRows(
ForwardZoneRow,
database,
gpa,
"SELECT id, zone, resolver FROM forward_zones ORDER BY zone",
readForwardZoneRow,
);
}
pub fn freeForwardZoneRow(gpa: Allocator, row: ForwardZoneRow) void {
gpa.free(row.zone);
gpa.free(row.resolver);
crud.freeRow(ForwardZoneRow, gpa, row);
}
pub fn freeForwardZoneRows(gpa: Allocator, items: []const ForwardZoneRow) void {
for (items) |item| freeForwardZoneRow(gpa, item);
crud.freeRows(ForwardZoneRow, gpa, items);
}
pub fn getForwardZone(database: *db.Db, gpa: Allocator, id: i64) db.Error!?ForwardZoneRow {