remoteSearch method

  1. @override
Future<List<T>> remoteSearch(
  1. SyncScope scope,
  2. QuerySpec spec
)
override

Search within a scope using a normalized query spec. Implementations should apply soft-delete semantics and only support operators and fields that are natively available on the backend. Unsupported operators/fields must throw ArgumentError with a clear message.

Implementation

@override
Future<List<T>> remoteSearch(SyncScope scope, QuerySpec spec) async {
  final plan = buildSupabaseRemoteSearchRequest(
    scope: scope,
    spec: spec,
    idColumn: config.idColumn,
    updatedAtColumn: config.updatedAtColumn,
    deletedAtColumn: config.deletedAtColumn,
    scopeNameColumn: config.scopeNameColumn,
    scopeKeysColumn: config.scopeKeysColumn,
  );
  // Test hook: execute via injected runner when provided
  if (config.searchRunner != null) {
    final rows = await config.searchRunner!(plan);
    return rows
        .map((e) => config.fromJson(Map<String, dynamic>.from(e)))
        .toList(growable: false);
  }

  dynamic q = _table().select();
  // Apply filters
  for (final op in plan.filters) {
    switch (op.method) {
      case 'eq':
        q = q.eq(op.column, op.value);
        break;
      case 'neq':
        q = q.neq(op.column, op.value);
        break;
      case 'gt':
        q = q.gt(op.column, op.value);
        break;
      case 'gte':
        q = q.gte(op.column, op.value);
        break;
      case 'lt':
        q = q.lt(op.column, op.value);
        break;
      case 'lte':
        q = q.lte(op.column, op.value);
        break;
      case 'in':
        q = q.inFilter(op.column, List.from(op.value as List));
        break;
      case 'like':
        q = q.like(op.column, op.value as String);
        break;
      case 'contains':
        q = q.contains(op.column, op.value);
        break;
      case 'isNull':
        q = q.filter(op.column, 'is', null);
        break;
      default:
        throw ArgumentError('Unsupported method in plan: ${op.method}');
    }
  }
  // Apply orders
  for (final o in plan.orders) {
    q = q.order(o.column, ascending: o.ascending);
  }
  // Apply pagination
  if (plan.limit != null) {
    q = q.limit(plan.limit!);
  }
  if (plan.rangeFrom != null && plan.rangeTo != null) {
    q = q.range(plan.rangeFrom!, plan.rangeTo!);
  }

  final res = await q;
  return (res as List)
      .map((e) => config.fromJson(Map<String, dynamic>.from(e)))
      .toList(growable: false);
}