pipe/test/fixtures/firestore_queries/lib/built_queries.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

129 lines
3.8 KiB
Dart

import 'package:cloud_firestore/cloud_firestore.dart';
/// Queries assembled across statements, getters and helpers.
class NotificationRepository {
NotificationRepository(this._firestore)
: _receipts = _firestore.collection('notificationReceipts');
final FirebaseFirestore _firestore;
final CollectionReference<Map<String, dynamic>> _receipts;
late final CollectionReference<Map<String, dynamic>> _inbox =
_firestore.collection('inbox');
CollectionReference<Map<String, dynamic>> get _collection =>
_firestore.collection('notifications');
Stream<QuerySnapshot<Map<String, dynamic>>> streamUserNotifications(
String userId, {
bool unreadOnly = false,
int? limit,
DocumentSnapshot<Object?>? startAfter,
}) {
Query<Map<String, dynamic>> query = _collection.where(
'userId',
isEqualTo: userId,
);
query = query.orderBy('timestamp', descending: true);
if (limit != null && !unreadOnly) {
query = query.limit(limit);
}
if (startAfter != null) {
query = query.startAfterDocument(startAfter);
}
return query.snapshots();
}
/// A clause assigned inside the same `if` as the terminal is not optional
/// there; an assignment after a terminal cannot reach it.
Stream<QuerySnapshot<Map<String, dynamic>>> platform({
bool onlyActive = false,
}) {
Query<Map<String, dynamic>> query = _collection.where(
'userId',
isNull: true,
);
if (onlyActive) {
query = query.where('isActive', isEqualTo: true);
return query.snapshots();
}
query = query.orderBy('timestamp', descending: true);
return query.snapshots();
}
Future<void> fallback(Query<Map<String, dynamic>>? custom) async {
await (custom ?? _collection.where('kind', isEqualTo: 'default')).get();
}
Future<void> ternaryClause(bool newestFirst) async {
final base = _collection.where('isRead', isEqualTo: false);
final ordered = newestFirst
? base.orderBy('createdAt', descending: true)
: base.orderBy('createdAt');
await ordered.get();
}
Future<void> receipts(String userId) async {
await _receipts.where('userId', isEqualTo: userId).get();
await _inbox.limit(3).get();
}
Query<Map<String, dynamic>> _buildListingQuery({
required String userId,
required String collectionName,
}) {
return _firestore
.collectionGroup(collectionName)
.where('userId', isEqualTo: userId)
.orderBy('createdAt', descending: true);
}
Future<void> listingPage(String userId, int pageSize) async {
final orderedQuery = _buildListingQuery(
userId: userId,
collectionName: 'products',
);
await orderedQuery.limit(pageSize).get();
}
Query<Map<String, dynamic>> _nested() => _buildListingQuery(
userId: 'u',
collectionName: 'services',
);
Future<void> nestedHelper() async {
await _nested().get();
}
Future<void> fromParameter(Query<Map<String, dynamic>> query) async {
await query.where('visible', isEqualTo: true).limit(10).get();
}
Future<void> inLoops(List<String> ids) async {
for (final id in ids) {
await _firestore.collection('stores').doc(id).collection('items').get();
}
await Future.wait(
ids.map(
(id) => _firestore
.collectionGroup('products')
.where('userId', whereIn: [id]).get(),
),
);
ids.forEach((id) {
_firestore.collection('audit').where('id', isEqualTo: id).get();
});
await Future.wait([_firestore.collection('once').get()]);
}
}
/// A top-level helper returning a query.
Query<Map<String, dynamic>> activeStores(FirebaseFirestore firestore) =>
firestore.collection('stores').where('active', isEqualTo: true);
Future<void> countActiveStores(FirebaseFirestore firestore) async {
await activeStores(firestore).count().get();
}