search for standard sites pub-search.waow.tech
search zig blog atproto
11
fork

Configure Feed

Select the types of activity you want to include in your feed.

add platform field to search results and ?platform= filter

- include platform field in all document search results
- add ?platform= query param to /search endpoint
- filter by platform in-memory (simple approach for initial impl)
- publications only shown when platform=leaflet or unfiltered
- update findSimilar query to include platform

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

zzstoatzz d7572926 f7a4f0e7

+30 -13
+27 -11
backend/src/search.zig
··· 15 15 createdAt: []const u8 = "", 16 16 rkey: []const u8, 17 17 basePath: []const u8, 18 + platform: []const u8, 18 19 }; 19 20 20 21 /// Document search result (internal) ··· 27 28 rkey: []const u8, 28 29 basePath: []const u8, 29 30 hasPublication: bool, 31 + platform: []const u8, 30 32 31 33 fn fromRow(row: db.Row) Doc { 32 34 return .{ ··· 38 40 .rkey = row.text(5), 39 41 .basePath = row.text(6), 40 42 .hasPublication = row.int(7) != 0, 43 + .platform = row.text(8), 41 44 }; 42 45 } 43 46 ··· 51 54 .createdAt = self.createdAt, 52 55 .rkey = self.rkey, 53 56 .basePath = self.basePath, 57 + .platform = self.platform, 54 58 }; 55 59 } 56 60 }; 57 61 58 62 const DocsByTag = zql.Query( 59 63 \\SELECT d.uri, d.did, d.title, '' as snippet, 60 - \\ d.created_at, d.rkey, p.base_path, 61 - \\ CASE WHEN d.publication_uri != '' THEN 1 ELSE 0 END as has_publication 64 + \\ d.created_at, d.rkey, COALESCE(p.base_path, '') as base_path, 65 + \\ CASE WHEN d.publication_uri != '' THEN 1 ELSE 0 END as has_publication, 66 + \\ d.platform 62 67 \\FROM documents d 63 68 \\LEFT JOIN publications p ON d.publication_uri = p.uri 64 69 \\JOIN document_tags dt ON d.uri = dt.document_uri ··· 69 74 const DocsByFtsAndTag = zql.Query( 70 75 \\SELECT f.uri, d.did, d.title, 71 76 \\ snippet(documents_fts, 2, '', '', '...', 32) as snippet, 72 - \\ d.created_at, d.rkey, p.base_path, 73 - \\ CASE WHEN d.publication_uri != '' THEN 1 ELSE 0 END as has_publication 77 + \\ d.created_at, d.rkey, COALESCE(p.base_path, '') as base_path, 78 + \\ CASE WHEN d.publication_uri != '' THEN 1 ELSE 0 END as has_publication, 79 + \\ d.platform 74 80 \\FROM documents_fts f 75 81 \\JOIN documents d ON f.uri = d.uri 76 82 \\LEFT JOIN publications p ON d.publication_uri = p.uri ··· 82 88 const DocsByFts = zql.Query( 83 89 \\SELECT f.uri, d.did, d.title, 84 90 \\ snippet(documents_fts, 2, '', '', '...', 32) as snippet, 85 - \\ d.created_at, d.rkey, p.base_path, 86 - \\ CASE WHEN d.publication_uri != '' THEN 1 ELSE 0 END as has_publication 91 + \\ d.created_at, d.rkey, COALESCE(p.base_path, '') as base_path, 92 + \\ CASE WHEN d.publication_uri != '' THEN 1 ELSE 0 END as has_publication, 93 + \\ d.platform 87 94 \\FROM documents_fts f 88 95 \\JOIN documents d ON f.uri = d.uri 89 96 \\LEFT JOIN publications p ON d.publication_uri = p.uri ··· 120 127 .snippet = self.snippet, 121 128 .rkey = self.rkey, 122 129 .basePath = self.basePath, 130 + .platform = "leaflet", // publications are leaflet-only for now 123 131 }; 124 132 } 125 133 }; ··· 134 142 \\ORDER BY rank LIMIT 10 135 143 ); 136 144 137 - pub fn search(alloc: Allocator, query: []const u8, tag_filter: ?[]const u8) ![]const u8 { 145 + pub fn search(alloc: Allocator, query: []const u8, tag_filter: ?[]const u8, platform_filter: ?[]const u8) ![]const u8 { 138 146 const c = db.getClient() orelse return error.NotInitialized; 139 147 140 148 var output: std.Io.Writer.Allocating = .init(alloc); ··· 155 163 156 164 if (doc_result) |*res| { 157 165 defer res.deinit(); 158 - for (res.rows) |row| try jw.write(Doc.fromRow(row).toJson()); 166 + for (res.rows) |row| { 167 + const doc = Doc.fromRow(row); 168 + // filter by platform if specified 169 + if (platform_filter) |pf| { 170 + if (!std.mem.eql(u8, doc.platform, pf)) continue; 171 + } 172 + try jw.write(doc.toJson()); 173 + } 159 174 } 160 175 161 - // publications are excluded when filtering by tag (tags only apply to documents) 162 - if (tag_filter == null) { 176 + // publications are excluded when filtering by tag or platform (only leaflet has publications) 177 + if (tag_filter == null and (platform_filter == null or std.mem.eql(u8, platform_filter.?, "leaflet"))) { 163 178 var pub_result = c.query( 164 179 PubSearch.positional, 165 180 PubSearch.bind(.{ .query = fts_query }), ··· 201 216 var res = c.query( 202 217 \\SELECT d2.uri, d2.did, d2.title, '' as snippet, 203 218 \\ d2.created_at, d2.rkey, COALESCE(p.base_path, '') as base_path, 204 - \\ CASE WHEN d2.publication_uri != '' THEN 1 ELSE 0 END as has_publication 219 + \\ CASE WHEN d2.publication_uri != '' THEN 1 ELSE 0 END as has_publication, 220 + \\ d2.platform 205 221 \\FROM documents d1, documents d2 206 222 \\LEFT JOIN publications p ON d2.publication_uri = p.uri 207 223 \\WHERE d1.uri = ?
+3 -2
backend/src/server.zig
··· 74 74 defer arena.deinit(); 75 75 const alloc = arena.allocator(); 76 76 77 - // parse query param: /search?q=something&tag=foo 77 + // parse query params: /search?q=something&tag=foo&platform=leaflet 78 78 const query = parseQueryParam(alloc, target, "q") catch ""; 79 79 const tag_filter = parseQueryParam(alloc, target, "tag") catch null; 80 + const platform_filter = parseQueryParam(alloc, target, "platform") catch null; 80 81 81 82 if (query.len == 0 and tag_filter == null) { 82 83 try sendJson(request, "{\"error\":\"enter a search term\"}"); ··· 84 85 } 85 86 86 87 // perform FTS search - arena handles cleanup 87 - const results = search.search(alloc, query, tag_filter) catch |err| { 88 + const results = search.search(alloc, query, tag_filter, platform_filter) catch |err| { 88 89 stats.recordError(); 89 90 return err; 90 91 };