pipe/test/fixtures/firestore_queries/lib/data/gateway.dart
trvon 1f60197a15
feat(queries): inventory firestore query surfaces as typed records
Add `pipe queries`, which lists every Firestore query a project can issue:
scope, collection, path pattern, filters with operators and value types,
composites, orderBy, limit, cursors, realtime, aggregation, in-loop, plus a
confidence and the reasons it is not exact. Receivers are matched by static
type and cloud_firestore library URI, never by name.

Queries are followed through chains, local variables (flow-insensitive with
two cuts), fields, getters and one level of helper methods with arguments
bound. An --adapter-config (YAML or JSON) maps declarative query APIs such as
a server-side gateway onto the same schema.

Inventory only: no rules, findings or baseline changes. Every emitted name is
validated against a safe character set so no source text reaches the output.
2026-09-23 18:03:09 -06:00

110 lines
2.7 KiB
Dart

/// A declarative query API in the shape of a server-side Firestore gateway:
/// filters are value objects, not chained calls, so only an adapter config can
/// tell pipe what each argument means.
class WhereEquals {
const WhereEquals(this.field, this.value);
final String field;
final Object? value;
}
class WhereIn {
const WhereIn(this.field, this.values);
final String field;
final List<Object?> values;
}
class WhereArrayContains {
const WhereArrayContains(this.field, this.value);
final String field;
final Object? value;
}
class WhereRange {
const WhereRange(this.field, {this.gte, this.gt, this.lte, this.lt});
final String field;
final Object? gte;
final Object? gt;
final Object? lte;
final Object? lt;
}
enum Cmp { lessThan, greaterThan }
/// An operator carried as an enum argument rather than a named bound.
class WhereCmp {
const WhereCmp(this.field, this.cmp, this.value);
final String field;
final Cmp cmp;
final Object? value;
}
class OrderBy {
const OrderBy(this.field, {this.descending = false});
final String field;
final bool descending;
}
abstract class Transaction {
Future<List<Object>> queryCollection(
String collectionPath, {
List<WhereEquals> filters = const [],
int? limit,
});
}
abstract class Gateway {
Future<List<Object>> queryCollection(
String collectionPath, {
List<WhereEquals> filters = const [],
WhereArrayContains? arrayContains,
List<Object> ranges = const [],
List<OrderBy> orderBy = const [],
String? startAfterId,
int? limit,
});
Future<List<Object>> queryCollectionGroup(
String collectionId, {
List<WhereEquals> filters = const [],
WhereIn? inFilter,
List<Object> ranges = const [],
List<OrderBy> orderBy = const [],
int? limit,
});
Future<Object?> getDocument(String path);
Future<T> runTransaction<T>(Future<T> Function(Transaction txn) action);
}
class InMemoryGateway implements Gateway {
@override
Future<List<Object>> queryCollection(
String collectionPath, {
List<WhereEquals> filters = const [],
WhereArrayContains? arrayContains,
List<Object> ranges = const [],
List<OrderBy> orderBy = const [],
String? startAfterId,
int? limit,
}) async =>
const [];
@override
Future<List<Object>> queryCollectionGroup(
String collectionId, {
List<WhereEquals> filters = const [],
WhereIn? inFilter,
List<Object> ranges = const [],
List<OrderBy> orderBy = const [],
int? limit,
}) async =>
const [];
@override
Future<Object?> getDocument(String path) async => null;
@override
Future<T> runTransaction<T>(Future<T> Function(Transaction txn) action) =>
throw UnimplementedError();
}