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.
110 lines
2.7 KiB
Dart
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();
|
|
}
|