fediglam/src/api/services/notes.zig

166 lines
4.1 KiB
Zig
Raw Normal View History

2022-09-08 07:52:23 +00:00
const std = @import("std");
const util = @import("util");
2022-10-02 05:18:24 +00:00
const sql = @import("sql");
2022-11-12 12:39:49 +00:00
const common = @import("./common.zig");
2022-09-08 07:52:23 +00:00
const Uuid = util.Uuid;
const DateTime = util.DateTime;
pub const Note = struct {
id: Uuid,
author_id: Uuid,
content: []const u8,
created_at: DateTime,
};
2022-10-02 05:18:24 +00:00
pub const CreateError = error{
DatabaseFailure,
2022-09-08 07:52:23 +00:00
};
pub fn create(
db: anytype,
author: Uuid,
content: []const u8,
2022-10-02 05:18:24 +00:00
alloc: std.mem.Allocator,
) CreateError!Uuid {
2022-10-08 20:47:54 +00:00
const id = Uuid.randV4(util.getThreadPrng());
2022-09-08 07:52:23 +00:00
2022-10-02 05:18:24 +00:00
db.insert("note", .{
2022-09-08 07:52:23 +00:00
.id = id,
.author_id = author,
.content = content,
.created_at = DateTime.now(),
2022-10-02 05:18:24 +00:00
}, alloc) catch return error.DatabaseFailure;
2022-09-08 07:52:23 +00:00
return id;
}
2022-10-02 05:18:24 +00:00
pub const GetError = error{
DatabaseFailure,
NotFound,
};
2022-10-08 07:51:22 +00:00
const selectStarFromNote = std.fmt.comptimePrint(
\\SELECT {s}
\\FROM note
\\
2022-11-12 13:23:55 +00:00
, .{util.comptimeJoinWithPrefix(",", "note.", std.meta.fieldNames(Note))});
2022-10-02 05:18:24 +00:00
pub fn get(db: anytype, id: Uuid, alloc: std.mem.Allocator) GetError!Note {
return db.queryRow(
Note,
2022-10-08 07:51:22 +00:00
selectStarFromNote ++
2022-10-02 05:18:24 +00:00
\\WHERE id = $1
\\LIMIT 1
,
2022-09-08 07:52:23 +00:00
.{id},
alloc,
2022-10-02 05:18:24 +00:00
) catch |err| switch (err) {
error.NoRows => error.NotFound,
else => error.DatabaseFailure,
2022-09-08 07:52:23 +00:00
};
}
2022-11-12 12:39:49 +00:00
const max_max_items = 100;
pub const QueryArgs = struct {
pub const PageDirection = common.PageDirection;
2022-11-14 07:00:20 +00:00
pub const Prev = std.meta.Child(std.meta.fieldInfo(@This(), .prev).field_type);
2022-11-12 12:39:49 +00:00
max_items: usize = 20,
created_before: ?DateTime = null,
created_after: ?DateTime = null,
2022-11-12 13:23:55 +00:00
community_id: ?Uuid = null,
2022-11-12 12:39:49 +00:00
prev: ?struct {
id: Uuid,
created_at: DateTime,
} = null,
page_direction: PageDirection = .forward,
};
pub const QueryResult = struct {
items: []Note,
prev_page: QueryArgs,
next_page: QueryArgs,
};
pub fn query(db: anytype, args: QueryArgs, alloc: std.mem.Allocator) !QueryResult {
var builder = sql.QueryBuilder.init(alloc);
defer builder.deinit();
2022-11-12 13:23:55 +00:00
try builder.appendSlice(selectStarFromNote ++
\\ JOIN actor ON actor.id = note.author_id
\\
);
2022-11-12 12:39:49 +00:00
if (args.created_before != null) try builder.andWhere("note.created_at < $1");
if (args.created_after != null) try builder.andWhere("note.created_at > $2");
if (args.prev != null) {
try builder.andWhere("(note.created_at, note.id)");
switch (args.page_direction) {
.forward => try builder.appendSlice(" < "),
.backward => try builder.appendSlice(" > "),
}
try builder.appendSlice("($3, $4)");
}
2022-11-12 13:23:55 +00:00
if (args.community_id != null) try builder.andWhere("actor.community_id = $5");
2022-11-12 12:39:49 +00:00
try builder.appendSlice(
\\
\\ORDER BY note.created_at DESC
2022-11-12 13:23:55 +00:00
\\LIMIT $6
2022-11-12 12:39:49 +00:00
\\
);
const max_items = if (args.max_items > max_max_items) max_max_items else args.max_items;
const query_args = blk: {
const prev_created_at = if (args.prev) |prev| @as(?DateTime, prev.created_at) else null;
const prev_id = if (args.prev) |prev| @as(?Uuid, prev.id) else null;
break :blk .{
args.created_before,
args.created_after,
prev_created_at,
prev_id,
2022-11-12 13:23:55 +00:00
args.community_id,
2022-11-12 12:39:49 +00:00
max_items,
};
};
const results = try db.queryRowsWithOptions(
2022-11-12 12:39:49 +00:00
Note,
try builder.terminate(),
query_args,
max_items,
2022-11-12 13:08:01 +00:00
.{ .allocator = alloc, .ignore_unused_arguments = true },
2022-11-12 12:39:49 +00:00
);
errdefer util.deepFree(results);
2022-11-12 12:39:49 +00:00
var next_page = args;
var prev_page = args;
prev_page.page_direction = .backward;
next_page.page_direction = .forward;
if (results.len != 0) {
2022-11-12 12:39:49 +00:00
prev_page.prev = .{
.id = results[0].id,
.created_at = results[0].created_at,
2022-11-12 12:39:49 +00:00
};
next_page.prev = .{
.id = results[results.len - 1].id,
.created_at = results[results.len - 1].created_at,
2022-11-12 12:39:49 +00:00
};
}
// TODO: this will give incorrect links on an empty page
return QueryResult{
.items = results,
2022-11-12 12:39:49 +00:00
.next_page = next_page,
.prev_page = prev_page,
};
}