diff --git a/src/api/services/communities.zig b/src/api/services/communities.zig index 879f57d..45e2fe1 100644 --- a/src/api/services/communities.zig +++ b/src/api/services/communities.zig @@ -281,45 +281,34 @@ pub fn query(db: anytype, args: QueryArgs, alloc: std.mem.Allocator) !QueryResul try builder.array.append(0); - var results = try db.queryWithOptions( + var results = try db.queryRowsWithOptions( Community, std.meta.assumeSentinel(builder.array.items, 0), query_args, + max_items, .{ .prep_allocator = alloc, .ignore_unused_arguments = true }, ); - defer results.finish(); - - const result_buf = try alloc.alloc(Community, args.max_items); - errdefer alloc.free(result_buf); - - var count: usize = 0; - errdefer for (result_buf[0..count]) |c| util.deepFree(alloc, c); - - for (result_buf) |*c| { - c.* = (try results.row(alloc)) orelse break; - - count += 1; - } + errdefer util.deepFree(alloc, results); var next_page = args; var prev_page = args; prev_page.page_direction = .backward; next_page.page_direction = .forward; - if (count != 0) { + if (results.len != 0) { prev_page.prev = .{ - .id = result_buf[0].id, - .order_val = getOrderVal(result_buf[0], args.order_by), + .id = results[0].id, + .order_val = getOrderVal(results[0], args.order_by), }; next_page.prev = .{ - .id = result_buf[count - 1].id, - .order_val = getOrderVal(result_buf[count - 1], args.order_by), + .id = results[results.len - 1].id, + .order_val = getOrderVal(results[results.len - 1], args.order_by), }; } // TODO: This will give incorrect links on an empty page return QueryResult{ - .items = result_buf[0..count], + .items = results, .next_page = next_page, .prev_page = prev_page, diff --git a/src/api/services/notes.zig b/src/api/services/notes.zig index fdaa97b..5156530 100644 --- a/src/api/services/notes.zig +++ b/src/api/services/notes.zig @@ -125,45 +125,34 @@ pub fn query(db: anytype, args: QueryArgs, alloc: std.mem.Allocator) !QueryResul }; }; - var results = try db.queryWithOptions( + const results = try db.queryRowsWithOptions( Note, try builder.terminate(), query_args, + max_items, .{ .prep_allocator = alloc, .ignore_unused_arguments = true }, ); - defer results.finish(); - - const result_buf = try alloc.alloc(Note, args.max_items); - errdefer alloc.free(result_buf); - - var count: usize = 0; - errdefer for (result_buf[0..count]) |c| util.deepFree(alloc, c); - - for (result_buf) |*c| { - c.* = (try results.row(alloc)) orelse break; - - count += 1; - } + errdefer util.deepFree(results); var next_page = args; var prev_page = args; prev_page.page_direction = .backward; next_page.page_direction = .forward; - if (count != 0) { + if (results.len != 0) { prev_page.prev = .{ - .id = result_buf[0].id, - .created_at = result_buf[0].created_at, + .id = results[0].id, + .created_at = results[0].created_at, }; next_page.prev = .{ - .id = result_buf[count - 1].id, - .created_at = result_buf[count - 1].created_at, + .id = results[results.len - 1].id, + .created_at = results[results.len - 1].created_at, }; } // TODO: this will give incorrect links on an empty page return QueryResult{ - .items = result_buf[0..count], + .items = results, .next_page = next_page, .prev_page = prev_page, }; diff --git a/src/sql/lib.zig b/src/sql/lib.zig index 0941d21..830f7a1 100644 --- a/src/sql/lib.zig +++ b/src/sql/lib.zig @@ -487,6 +487,45 @@ fn Tx(comptime tx_level: u8) type { return row; } + // Runs a query to completion and returns the results as a slice + pub fn queryRowsWithOptions( + self: Self, + comptime RowType: type, + q: [:0]const u8, + args: anytype, + max_items: ?usize, + options: QueryOptions, + ) QueryRowError![]RowType { + var results = try self.queryWithOptions(RowType, q, args, options); + defer results.finish(); + + const alloc = options.prep_allocator orelse return error.AllocatorRequired; + + var result_array = std.ArrayList(RowType).init(alloc); + errdefer result_array.deinit(); + if (max_items) |max| try result_array.ensureTotalCapacity(max); + + errdefer for (result_array.items) |r| util.deepFree(alloc, r); + + var too_many: bool = false; + while (try results.row(alloc)) |row| { + errdefer util.deepFree(alloc, row); + if (max_items) |max| { + if (result_array.items.len >= max) { + util.deepFree(alloc, row); + too_many = true; + continue; + } + } + + try result_array.append(row); + } + + if (too_many) return error.TooManyRows; + + return result_array.toOwnedSlice(); + } + // Inserts a single value into a table pub fn insert( self: Self,