@@ -82,6 +82,12 @@ pub fn run(allocator: std.mem.Allocator, indexes: *MultiIndex, address: []const
82
82
// Bulk API
83
83
router .post ("/:index/_update" , handleUpdate );
84
84
85
+ // Fingerprint API
86
+ router .head ("/:index/:id" , handleHeadFingerprint );
87
+ router .get ("/:index/:id" , handleGetFingerprint );
88
+ router .put ("/:index/:id" , handlePutFingerprint );
89
+ router .delete ("/:index/:id" , handleDeleteFingerprint );
90
+
85
91
// Index API
86
92
router .head ("/:index" , handleHeadIndex );
87
93
router .get ("/:index" , handleGetIndex );
@@ -113,8 +119,34 @@ const SearchResultsJSON = struct {
113
119
results : []SearchResultJSON ,
114
120
};
115
121
122
+ fn getId (req : * httpz.Request , res : * httpz.Response , send_body : bool ) ! ? u32 {
123
+ const id_str = req .param ("id" ) orelse {
124
+ if (send_body ) {
125
+ try writeErrorResponse (400 , error .MissingId , req , res );
126
+ } else {
127
+ res .status = 400 ;
128
+ }
129
+ return null ;
130
+ };
131
+ return std .fmt .parseInt (u32 , id_str , 10 ) catch | err | {
132
+ if (send_body ) {
133
+ try writeErrorResponse (400 , err , req , res );
134
+ } else {
135
+ res .status = 400 ;
136
+ }
137
+ return null ;
138
+ };
139
+ }
140
+
116
141
fn getIndex (ctx : * Context , req : * httpz.Request , res : * httpz.Response , send_body : bool ) ! ? * IndexData {
117
- const index_name = req .param ("index" ) orelse return null ;
142
+ const index_name = req .param ("index" ) orelse {
143
+ if (send_body ) {
144
+ try writeErrorResponse (400 , error .MissingIndexName , req , res );
145
+ } else {
146
+ res .status = 400 ;
147
+ }
148
+ return null ;
149
+ };
118
150
const index = ctx .indexes .getIndex (index_name ) catch | err | {
119
151
if (err == error .IndexNotFound ) {
120
152
if (send_body ) {
@@ -278,6 +310,83 @@ fn handleUpdate(ctx: *Context, req: *httpz.Request, res: *httpz.Response) !void
278
310
return writeResponse (EmptyResponse {}, req , res );
279
311
}
280
312
313
+ fn handleHeadFingerprint (ctx : * Context , req : * httpz.Request , res : * httpz.Response ) ! void {
314
+ const index_ref = try getIndex (ctx , req , res , false ) orelse return ;
315
+ const index = & index_ref .index ;
316
+ defer releaseIndex (ctx , index_ref );
317
+
318
+ const id = try getId (req , res , false ) orelse return ;
319
+ const info = try index .getDocInfo (id );
320
+
321
+ res .status = if (info == null ) 404 else 200 ;
322
+ }
323
+
324
+ const GetFingerprintResponse = struct {
325
+ version : u64 ,
326
+
327
+ pub fn msgpackFormat () msgpack.StructFormat {
328
+ return .{ .as_map = .{ .key = .{ .field_name_prefix = 1 } } };
329
+ }
330
+ };
331
+
332
+ fn handleGetFingerprint (ctx : * Context , req : * httpz.Request , res : * httpz.Response ) ! void {
333
+ const index_ref = try getIndex (ctx , req , res , true ) orelse return ;
334
+ const index = & index_ref .index ;
335
+ defer releaseIndex (ctx , index_ref );
336
+
337
+ const id = try getId (req , res , true ) orelse return ;
338
+ const info = try index .getDocInfo (id ) orelse {
339
+ return writeErrorResponse (404 , error .FingerprintNotFound , req , res );
340
+ };
341
+
342
+ return writeResponse (GetFingerprintResponse { .version = info .version }, req , res );
343
+ }
344
+
345
+ const PutFingerprintRequest = struct {
346
+ hashes : []u32 ,
347
+
348
+ pub fn msgpackFormat () msgpack.StructFormat {
349
+ return .{ .as_map = .{ .key = .{ .field_name_prefix = 1 } } };
350
+ }
351
+ };
352
+
353
+ fn handlePutFingerprint (ctx : * Context , req : * httpz.Request , res : * httpz.Response ) ! void {
354
+ const body = try getRequestBody (PutFingerprintRequest , req , res ) orelse return ;
355
+
356
+ const index_ref = try getIndex (ctx , req , res , true ) orelse return ;
357
+ const index = & index_ref .index ;
358
+ defer releaseIndex (ctx , index_ref );
359
+
360
+ const id = try getId (req , res , true ) orelse return ;
361
+ const change : Change = .{ .insert = .{
362
+ .id = id ,
363
+ .hashes = body .hashes ,
364
+ } };
365
+
366
+ metrics .update (1 );
367
+
368
+ try index .update (&[_ ]Change {change });
369
+
370
+ return writeResponse (EmptyResponse {}, req , res );
371
+ }
372
+
373
+ fn handleDeleteFingerprint (ctx : * Context , req : * httpz.Request , res : * httpz.Response ) ! void {
374
+ const index_ref = try getIndex (ctx , req , res , true ) orelse return ;
375
+ const index = & index_ref .index ;
376
+ defer releaseIndex (ctx , index_ref );
377
+
378
+ const id = try getId (req , res , true ) orelse return ;
379
+ const change : Change = .{ .delete = .{
380
+ .id = id ,
381
+ } };
382
+
383
+ metrics .update (1 );
384
+
385
+ try index .update (&[_ ]Change {change });
386
+
387
+ return writeResponse (EmptyResponse {}, req , res );
388
+ }
389
+
281
390
const Attributes = struct {
282
391
attributes : std .AutoHashMapUnmanaged (u64 , u64 ),
283
392
0 commit comments