milestone 18: collapse duplicated infrastructure into shared listener core, crud list helper, resource shells, transport race, name and line helpers, ui modules
This commit is contained in:
@@ -38,35 +38,23 @@ const list_clients_sql =
|
||||
|
||||
/// Every string in the result is a heap copy owned by `gpa`.
|
||||
pub fn listClients(database: *db.Db, gpa: Allocator) db.Error!std.ArrayList(model.Client) {
|
||||
var stmt = try database.prepare(list_clients_sql);
|
||||
defer stmt.deinit();
|
||||
return crud.listRows(model.Client, database, gpa, list_clients_sql, readClient);
|
||||
}
|
||||
|
||||
var out: std.ArrayList(model.Client) = .empty;
|
||||
// `errdefer`s run in reverse: `freeClients` is declared last so it runs
|
||||
// before the backing array is released.
|
||||
errdefer out.deinit(gpa);
|
||||
errdefer freeClients(gpa, out.items);
|
||||
|
||||
while (try stmt.step()) {
|
||||
const ip = try stmt.columnTextAlloc(gpa, 0);
|
||||
errdefer gpa.free(ip);
|
||||
// `clients.name` is nullable; `columnTextAlloc` reads NULL as "", which
|
||||
// is exactly the model's default.
|
||||
const name = try stmt.columnTextAlloc(gpa, 1);
|
||||
errdefer gpa.free(name);
|
||||
const group = try stmt.columnTextAlloc(gpa, 2);
|
||||
errdefer gpa.free(group);
|
||||
try out.append(gpa, .{ .ip = ip, .name = name, .group = group });
|
||||
}
|
||||
return out;
|
||||
fn readClient(stmt: *db.Stmt, gpa: Allocator) db.Error!model.Client {
|
||||
const ip = try stmt.columnTextAlloc(gpa, 0);
|
||||
errdefer gpa.free(ip);
|
||||
// `clients.name` is nullable; `columnTextAlloc` reads NULL as "", which is
|
||||
// exactly the model's default.
|
||||
const name = try stmt.columnTextAlloc(gpa, 1);
|
||||
errdefer gpa.free(name);
|
||||
const group = try stmt.columnTextAlloc(gpa, 2);
|
||||
errdefer gpa.free(group);
|
||||
return .{ .ip = ip, .name = name, .group = group };
|
||||
}
|
||||
|
||||
pub fn freeClients(gpa: Allocator, items: []const model.Client) void {
|
||||
for (items) |item| {
|
||||
gpa.free(item.ip);
|
||||
gpa.free(item.name);
|
||||
gpa.free(item.group);
|
||||
}
|
||||
crud.freeRows(model.Client, gpa, items);
|
||||
}
|
||||
|
||||
const insert_client_sql =
|
||||
@@ -154,31 +142,22 @@ const list_client_prefixes_sql =
|
||||
;
|
||||
|
||||
pub fn listClientPrefixes(database: *db.Db, gpa: Allocator) db.Error!std.ArrayList(model.ClientPrefix) {
|
||||
var stmt = try database.prepare(list_client_prefixes_sql);
|
||||
defer stmt.deinit();
|
||||
return crud.listRows(model.ClientPrefix, database, gpa, list_client_prefixes_sql, readClientPrefix);
|
||||
}
|
||||
|
||||
var out: std.ArrayList(model.ClientPrefix) = .empty;
|
||||
errdefer out.deinit(gpa);
|
||||
errdefer freeClientPrefixes(gpa, out.items);
|
||||
|
||||
while (try stmt.step()) {
|
||||
const prefix = try stmt.columnTextAlloc(gpa, 0);
|
||||
errdefer gpa.free(prefix);
|
||||
const group = try stmt.columnTextAlloc(gpa, 1);
|
||||
errdefer gpa.free(group);
|
||||
// The column is a 64-bit integer; the model field is `i32`. A value
|
||||
// outside that range means something other than nxdns wrote the row.
|
||||
const priority = std.math.cast(i32, stmt.columnInt(2)) orelse return error.Mismatch;
|
||||
try out.append(gpa, .{ .prefix = prefix, .group = group, .priority = priority });
|
||||
}
|
||||
return out;
|
||||
fn readClientPrefix(stmt: *db.Stmt, gpa: Allocator) db.Error!model.ClientPrefix {
|
||||
const prefix = try stmt.columnTextAlloc(gpa, 0);
|
||||
errdefer gpa.free(prefix);
|
||||
const group = try stmt.columnTextAlloc(gpa, 1);
|
||||
errdefer gpa.free(group);
|
||||
// The column is a 64-bit integer; the model field is `i32`. A value outside
|
||||
// that range means something other than nxdns wrote the row.
|
||||
const priority = std.math.cast(i32, stmt.columnInt(2)) orelse return error.Mismatch;
|
||||
return .{ .prefix = prefix, .group = group, .priority = priority };
|
||||
}
|
||||
|
||||
pub fn freeClientPrefixes(gpa: Allocator, items: []const model.ClientPrefix) void {
|
||||
for (items) |item| {
|
||||
gpa.free(item.prefix);
|
||||
gpa.free(item.group);
|
||||
}
|
||||
crud.freeRows(model.ClientPrefix, gpa, items);
|
||||
}
|
||||
|
||||
pub fn insertClientPrefix(database: *db.Db, item: model.ClientPrefix, ctx: InsertContext) db.Error!void {
|
||||
@@ -257,29 +236,15 @@ const get_client_sql =
|
||||
/// Every client, materialised ones included. Every string is a heap copy owned
|
||||
/// by `gpa`.
|
||||
pub fn listClientRows(database: *db.Db, gpa: Allocator) db.Error!std.ArrayList(ClientRow) {
|
||||
var stmt = try database.prepare(list_client_rows_sql);
|
||||
defer stmt.deinit();
|
||||
|
||||
var out: std.ArrayList(ClientRow) = .empty;
|
||||
errdefer out.deinit(gpa);
|
||||
errdefer freeClientRows(gpa, out.items);
|
||||
|
||||
while (try stmt.step()) {
|
||||
const row = try readClientRow(&stmt, gpa);
|
||||
errdefer freeClientRow(gpa, row);
|
||||
try out.append(gpa, row);
|
||||
}
|
||||
return out;
|
||||
return crud.listRows(ClientRow, database, gpa, list_client_rows_sql, readClientRow);
|
||||
}
|
||||
|
||||
pub fn freeClientRow(gpa: Allocator, row: ClientRow) void {
|
||||
gpa.free(row.ip);
|
||||
gpa.free(row.name);
|
||||
gpa.free(row.group);
|
||||
crud.freeRow(ClientRow, gpa, row);
|
||||
}
|
||||
|
||||
pub fn freeClientRows(gpa: Allocator, items: []const ClientRow) void {
|
||||
for (items) |item| freeClientRow(gpa, item);
|
||||
crud.freeRows(ClientRow, gpa, items);
|
||||
}
|
||||
|
||||
pub fn getClient(database: *db.Db, gpa: Allocator, id: i64) db.Error!?ClientRow {
|
||||
@@ -383,39 +348,32 @@ const list_client_prefix_rows_sql =
|
||||
/// Same order as `listClientPrefixes`; every string is a heap copy owned by
|
||||
/// `gpa`.
|
||||
pub fn listClientPrefixRows(database: *db.Db, gpa: Allocator) db.Error!std.ArrayList(ClientPrefixRow) {
|
||||
var stmt = try database.prepare(list_client_prefix_rows_sql);
|
||||
defer stmt.deinit();
|
||||
return crud.listRows(ClientPrefixRow, database, gpa, list_client_prefix_rows_sql, readClientPrefixRow);
|
||||
}
|
||||
|
||||
var out: std.ArrayList(ClientPrefixRow) = .empty;
|
||||
errdefer out.deinit(gpa);
|
||||
errdefer freeClientPrefixRows(gpa, out.items);
|
||||
|
||||
while (try stmt.step()) {
|
||||
const prefix = try stmt.columnTextAlloc(gpa, 1);
|
||||
errdefer gpa.free(prefix);
|
||||
const group = try stmt.columnTextAlloc(gpa, 3);
|
||||
errdefer gpa.free(group);
|
||||
// The column is a 64-bit integer; the row field is `i32`. A value
|
||||
// outside that range means something other than nxdns wrote the row.
|
||||
const priority = std.math.cast(i32, stmt.columnInt(4)) orelse return error.Mismatch;
|
||||
try out.append(gpa, .{
|
||||
.id = stmt.columnInt(0),
|
||||
.prefix = prefix,
|
||||
.group_id = stmt.columnInt(2),
|
||||
.group = group,
|
||||
.priority = priority,
|
||||
});
|
||||
}
|
||||
return out;
|
||||
fn readClientPrefixRow(stmt: *db.Stmt, gpa: Allocator) db.Error!ClientPrefixRow {
|
||||
const prefix = try stmt.columnTextAlloc(gpa, 1);
|
||||
errdefer gpa.free(prefix);
|
||||
const group = try stmt.columnTextAlloc(gpa, 3);
|
||||
errdefer gpa.free(group);
|
||||
// The column is a 64-bit integer; the row field is `i32`. A value outside
|
||||
// that range means something other than nxdns wrote the row.
|
||||
const priority = std.math.cast(i32, stmt.columnInt(4)) orelse return error.Mismatch;
|
||||
return .{
|
||||
.id = stmt.columnInt(0),
|
||||
.prefix = prefix,
|
||||
.group_id = stmt.columnInt(2),
|
||||
.group = group,
|
||||
.priority = priority,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn freeClientPrefixRow(gpa: Allocator, row: ClientPrefixRow) void {
|
||||
gpa.free(row.prefix);
|
||||
gpa.free(row.group);
|
||||
crud.freeRow(ClientPrefixRow, gpa, row);
|
||||
}
|
||||
|
||||
pub fn freeClientPrefixRows(gpa: Allocator, items: []const ClientPrefixRow) void {
|
||||
for (items) |item| freeClientPrefixRow(gpa, item);
|
||||
crud.freeRows(ClientPrefixRow, gpa, items);
|
||||
}
|
||||
|
||||
/// Replaces the whole prefix table inside a transaction (ruling 9 makes
|
||||
|
||||
Reference in New Issue
Block a user