@@ -22,7 +22,9 @@ class MockSupabaseHttpClient extends BaseClient {
2222 );
2323
2424 // Decode the request body if it's not a GET request
25- final body = (request.method != 'GET' && request.method != 'DELETE' ) &&
25+ final body = (request.method != 'GET' &&
26+ request.method != 'DELETE' &&
27+ request.method != 'HEAD' ) &&
2628 request is Request
2729 ? jsonDecode (await request.finalize ().transform (utf8.decoder).join ())
2830 : null ;
@@ -43,6 +45,8 @@ class MockSupabaseHttpClient extends BaseClient {
4345 return _handleDelete (tableName, body, request);
4446 case 'GET' :
4547 return _handleSelect (tableName, request.url.queryParameters, request);
48+ case 'HEAD' :
49+ return _handleHead (tableName, request.url.queryParameters, request);
4650 default :
4751 return _createResponse ({'error' : 'Method not allowed' },
4852 statusCode: 405 , request: request);
@@ -219,7 +223,10 @@ class MockSupabaseHttpClient extends BaseClient {
219223 }
220224
221225 StreamedResponse _handleSelect (
222- String tableName, Map <String , String > queryParams, BaseRequest request) {
226+ String tableName,
227+ Map <String , String > queryParams,
228+ BaseRequest request,
229+ ) {
223230 // Handle selecting data from the mock database
224231 if (! _database.containsKey (tableName)) {
225232 return _createResponse ([], request: request);
@@ -283,6 +290,9 @@ class MockSupabaseHttpClient extends BaseClient {
283290 }
284291 });
285292
293+ // Get the count value before any limiting
294+ final countValue = returningRows.length;
295+
286296 // Handle top level table ordering
287297 if (queryParams.containsKey ('order' )) {
288298 final orderParams = queryParams['order' ]! .split ('.' );
@@ -316,9 +326,12 @@ class MockSupabaseHttpClient extends BaseClient {
316326 }).toList ();
317327 });
318328
329+ final offset = queryParams.containsKey ('offset' )
330+ ? int .parse (queryParams['offset' ]! )
331+ : 0 ;
332+
319333 // Handle top level table offset
320- if (queryParams.containsKey ('offset' )) {
321- final offset = int .parse (queryParams['offset' ]! );
334+ if (offset > 0 ) {
322335 returningRows = returningRows.skip (offset).toList ();
323336 }
324337
@@ -395,13 +408,28 @@ class MockSupabaseHttpClient extends BaseClient {
395408 // Handle top level column selection
396409 if (! selectedColumns.contains ('*' )) {
397410 returningRows = returningRows.map ((row) {
398- print (row);
399411 return Map <String , dynamic >.fromEntries (row.entries
400412 .where ((entry) => selectedColumns.contains (entry.key)));
401413 }).toList ();
402414 }
403415 }
404416
417+ // Handle count
418+ final preferHeader = request.headers['Prefer' ];
419+ final isCountRequest =
420+ preferHeader != null && preferHeader.contains ('count=' );
421+
422+ if (isCountRequest) {
423+ final countType =
424+ preferHeader.contains ('count=exact' ) ? 'exact' : 'planned' ;
425+
426+ return _createResponse (returningRows, request: request, headers: {
427+ 'content-range' : '$offset -${offset + returningRows .length }/$countValue ' ,
428+ 'content-profile' : tableName,
429+ 'preference-applied' : 'count=$countType '
430+ });
431+ }
432+
405433 // Handle single
406434 if (request.headers['Accept' ] == 'application/vnd.pgrst.object+json' ) {
407435 if (returningRows.length == 1 ) {
@@ -430,6 +458,61 @@ class MockSupabaseHttpClient extends BaseClient {
430458 return _createResponse (returningRows, request: request);
431459 }
432460
461+ StreamedResponse _handleHead (
462+ String tableName, Map <String , String > queryParams, BaseRequest request) {
463+ // Perform the same filtering as in _handleSelect
464+ var returningRows =
465+ List <Map <String , dynamic >>.from (_database[tableName] ?? []);
466+
467+ // Apply filters (you may want to extract this to a separate method)
468+ queryParams.forEach ((key, value) {
469+ if (key != 'select' &&
470+ key != 'order' &&
471+ key != 'limit' &&
472+ key != 'range' ) {
473+ final filter = _parseFilter (
474+ columnName: key,
475+ postrestFilter: value,
476+ targetRow: returningRows.isNotEmpty ? returningRows.first : {},
477+ );
478+ returningRows = returningRows.where ((item) => filter (item)).toList ();
479+ }
480+ });
481+
482+ // Handle count
483+ final preferHeader = request.headers['Prefer' ];
484+ final isCountRequest =
485+ preferHeader != null && preferHeader.contains ('count=' );
486+
487+ if (isCountRequest) {
488+ final count = returningRows.length;
489+ final countType =
490+ preferHeader.contains ('count=exact' ) ? 'exact' : 'planned' ;
491+
492+ // Return only headers for HEAD request
493+ return StreamedResponse (
494+ Stream .value ([]), // Empty body for HEAD request
495+ 200 ,
496+ headers: {
497+ 'content-range' : '0-$count /$count ' ,
498+ 'content-profile' : tableName,
499+ 'preference-applied' : 'count=$countType '
500+ },
501+ request: request,
502+ );
503+ }
504+
505+ // If it's not a count request, return basic headers
506+ return StreamedResponse (
507+ Stream .value ([]), // Empty body for HEAD request
508+ 200 ,
509+ headers: {
510+ 'content-profile' : tableName,
511+ },
512+ request: request,
513+ );
514+ }
515+
433516 bool Function (Map <String , dynamic > row) _parseFilter ({
434517 required String columnName,
435518 required String postrestFilter,
@@ -530,12 +613,18 @@ class MockSupabaseHttpClient extends BaseClient {
530613 }
531614
532615 StreamedResponse _createResponse (dynamic data,
533- {int statusCode = 200 , required BaseRequest request}) {
534- // Create a response for the mock client
616+ {int statusCode = 200 ,
617+ required BaseRequest request,
618+ Map <String , String >? headers}) {
619+ final responseHeaders = {
620+ 'content-type' : 'application/json; charset=utf-8' ,
621+ ...? headers,
622+ };
623+
535624 return StreamedResponse (
536625 Stream .value (utf8.encode (jsonEncode (data))),
537626 statusCode,
538- headers: { 'content-type' : 'application/json; charset=utf-8' } ,
627+ headers: responseHeaders ,
539628 request: request,
540629 );
541630 }
0 commit comments