@@ -142,6 +142,21 @@ class _PipelineExamplePageState extends State<PipelineExamplePage> {
142142 'b' : 2 ,
143143 'tags' : ['p' , 'q' ],
144144 },
145+ {
146+ 'title' : 'Regex Email Doc' ,
147+ 'score' : 99 ,
148+ 'year' : 2024 ,
149+ 'category' : 'tech' ,
150+ 'email' : 'demo@example.com' ,
151+ 'pi' : 3.14159 ,
152+ },
153+ {
154+ 'title' : 'Dup Tags' ,
155+ 'score' : 8 ,
156+ 'year' : 2023 ,
157+ 'category' : 'tech' ,
158+ 'tags' : ['a' , 'b' , 'a' ],
159+ },
145160 ];
146161
147162 for (final item in items) {
@@ -231,6 +246,21 @@ class _PipelineExamplePageState extends State<PipelineExamplePage> {
231246 'b' : 2 ,
232247 'tags' : ['p' , 'q' ],
233248 },
249+ {
250+ 'title' : 'Regex Email Doc' ,
251+ 'score' : 99 ,
252+ 'year' : 2024 ,
253+ 'category' : 'tech' ,
254+ 'email' : 'demo@example.com' ,
255+ 'pi' : 3.14159 ,
256+ },
257+ {
258+ 'title' : 'Dup Tags' ,
259+ 'score' : 8 ,
260+ 'year' : 2023 ,
261+ 'category' : 'tech' ,
262+ 'tags' : ['a' , 'b' , 'a' ],
263+ },
234264 ];
235265
236266 for (final item in items) {
@@ -965,6 +995,224 @@ class _PipelineExamplePageState extends State<PipelineExamplePage> {
965995 .execute (),
966996 );
967997
998+ // ── New pipeline expressions (regex, map, string, array, agg) ───────────
999+
1000+ Future <void > _runPipeline47 () => _runPipeline (
1001+ 'Pipeline 47: where(has email) → addFields regexFind(@.+)' ,
1002+ () => _firestore
1003+ .pipeline ()
1004+ .collection (_collectionId)
1005+ .where (Expression .field ('email' ).exists ())
1006+ .addFields (Expression .field ('email' ).regexFind ('@.+' ).as ('at_domain' ))
1007+ .limit (5 )
1008+ .execute (),
1009+ );
1010+
1011+ Future <void > _runPipeline48 () => _runPipeline (
1012+ 'Pipeline 48: where(has email) → addFields regexFindAll([a-z]+)' ,
1013+ () => _firestore
1014+ .pipeline ()
1015+ .collection (_collectionId)
1016+ .where (Expression .field ('email' ).exists ())
1017+ .addFields (
1018+ Expression .field ('email' ).regexFindAll ('[a-z]+' ).as ('word_chunks' ),
1019+ )
1020+ .limit (5 )
1021+ .execute (),
1022+ );
1023+
1024+ Future <void > _runPipeline49 () => _runPipeline (
1025+ 'Pipeline 49: test=expressions + has s → stringReplaceOne, stringIndexOf, stringRepeat' ,
1026+ () => _firestore
1027+ .pipeline ()
1028+ .collection (_collectionId)
1029+ .where (
1030+ Expression .and (
1031+ Expression .field ('test' ).equalValue ('expressions' ),
1032+ Expression .field ('s' ).exists (),
1033+ ),
1034+ )
1035+ .addFields (
1036+ Expression .field ('s' ).stringReplaceOneLiteral ('A' , 'Z' ).as ('s_replace_one' ),
1037+ Expression .field ('s' ).stringIndexOf ('y' ).as ('idx_y' ),
1038+ Expression .field ('s' ).stringRepeat (2 ).as ('s_twice' ),
1039+ )
1040+ .limit (8 )
1041+ .execute (),
1042+ );
1043+
1044+ Future <void > _runPipeline50 () => _runPipeline (
1045+ 'Pipeline 50: title " Padded " → ltrim, rtrim' ,
1046+ () => _firestore
1047+ .pipeline ()
1048+ .collection (_collectionId)
1049+ .where (Expression .field ('title' ).equalValue (' Padded ' ))
1050+ .addFields (
1051+ Expression .field ('title' ).ltrim ().as ('lt' ),
1052+ Expression .field ('title' ).rtrim ().as ('rt' ),
1053+ )
1054+ .limit (3 )
1055+ .execute (),
1056+ );
1057+
1058+ Future <void > _runPipeline51 () => _runPipeline (
1059+ 'Pipeline 51: where(has items) → mapSet(z), mapEntries()' ,
1060+ () => _firestore
1061+ .pipeline ()
1062+ .collection (_collectionId)
1063+ .where (Expression .field ('items' ).exists ())
1064+ .addFields (
1065+ Expression .field ('items' ).mapSet ('z' , 'added' ).as ('items_plus' ),
1066+ Expression .field ('items' ).mapEntries ().as ('items_entries' ),
1067+ )
1068+ .limit (3 )
1069+ .execute (),
1070+ );
1071+
1072+ Future <void > _runPipeline52 () => _runPipeline (
1073+ 'Pipeline 52: addFields type(score)' ,
1074+ () => _firestore
1075+ .pipeline ()
1076+ .collection (_collectionId)
1077+ .addFields (Expression .field ('score' ).type ().as ('score_type' ))
1078+ .limit (6 )
1079+ .execute (),
1080+ );
1081+
1082+ Future <void > _runPipeline53 () => _runPipeline (
1083+ 'Pipeline 53: where(score isType int64) → select title, score' ,
1084+ () => _firestore
1085+ .pipeline ()
1086+ .collection (_collectionId)
1087+ .where (Expression .field ('score' ).isType ('int64' ))
1088+ .select (Expression .field ('title' ), Expression .field ('score' ))
1089+ .limit (8 )
1090+ .execute (),
1091+ );
1092+
1093+ Future <void > _runPipeline54 () => _runPipeline (
1094+ 'Pipeline 54: where(has pi) → trunc(pi), trunc(2dp), rand()' ,
1095+ () => _firestore
1096+ .pipeline ()
1097+ .collection (_collectionId)
1098+ .where (Expression .field ('pi' ).exists ())
1099+ .addFields (
1100+ Expression .field ('pi' ).trunc ().as ('pi_trunc' ),
1101+ Expression .field ('pi' ).trunc (Expression .constant (2 )).as ('pi_2' ),
1102+ Expression .rand ().as ('rnd' ),
1103+ )
1104+ .limit (3 )
1105+ .execute (),
1106+ );
1107+
1108+ Future <void > _runPipeline55 () => _runPipeline (
1109+ 'Pipeline 55: title Item G → arrayFirst, arrayLast(tags)' ,
1110+ () => _firestore
1111+ .pipeline ()
1112+ .collection (_collectionId)
1113+ .where (Expression .field ('title' ).equalValue ('Item G' ))
1114+ .addFields (
1115+ Expression .field ('tags' ).arrayFirst ().as ('tag_first' ),
1116+ Expression .field ('tags' ).arrayLast ().as ('tag_last' ),
1117+ )
1118+ .limit (3 )
1119+ .execute (),
1120+ );
1121+
1122+ Future <void > _runPipeline56 () => _runPipeline (
1123+ 'Pipeline 56: Item G → arrayFirstN(2), arrayLastN(2)(tags)' ,
1124+ () => _firestore
1125+ .pipeline ()
1126+ .collection (_collectionId)
1127+ .where (Expression .field ('title' ).equalValue ('Item G' ))
1128+ .addFields (
1129+ Expression .field ('tags' ).arrayFirstN (2 ).as ('tags_head' ),
1130+ Expression .field ('tags' ).arrayLastN (2 ).as ('tags_tail' ),
1131+ )
1132+ .limit (3 )
1133+ .execute (),
1134+ );
1135+
1136+ Future <void > _runPipeline57 () => _runPipeline (
1137+ 'Pipeline 57: where(has scores) → arrayMaximum, arrayMinimum' ,
1138+ () => _firestore
1139+ .pipeline ()
1140+ .collection (_collectionId)
1141+ .where (Expression .field ('scores' ).exists ())
1142+ .addFields (
1143+ Expression .field ('scores' ).arrayMaximum ().as ('smax' ),
1144+ Expression .field ('scores' ).arrayMinimum ().as ('smin' ),
1145+ )
1146+ .limit (3 )
1147+ .execute (),
1148+ );
1149+
1150+ Future <void > _runPipeline58 () => _runPipeline (
1151+ 'Pipeline 58: where(has scores) → arrayMaximumN(2), arrayMinimumN(2)' ,
1152+ () => _firestore
1153+ .pipeline ()
1154+ .collection (_collectionId)
1155+ .where (Expression .field ('scores' ).exists ())
1156+ .addFields (
1157+ Expression .field ('scores' ).arrayMaximumN (2 ).as ('top2' ),
1158+ Expression .field ('scores' ).arrayMinimumN (2 ).as ('bottom2' ),
1159+ )
1160+ .limit (3 )
1161+ .execute (),
1162+ );
1163+
1164+ Future <void > _runPipeline59 () => _runPipeline (
1165+ 'Pipeline 59: Dup Tags → arrayIndexOf(a), arrayLastIndexOf(a), arrayIndexOfAll(a)' ,
1166+ () => _firestore
1167+ .pipeline ()
1168+ .collection (_collectionId)
1169+ .where (Expression .field ('title' ).equalValue ('Dup Tags' ))
1170+ .addFields (
1171+ Expression .field ('tags' ).arrayIndexOf ('a' ).as ('idx_first_a' ),
1172+ Expression .field ('tags' ).arrayLastIndexOf ('a' ).as ('idx_last_a' ),
1173+ Expression .field ('tags' ).arrayIndexOfAll ('a' ).as ('all_a' ),
1174+ )
1175+ .limit (3 )
1176+ .execute (),
1177+ );
1178+
1179+ Future <void > _runPipeline60 () => _runPipeline (
1180+ 'Pipeline 60: aggregate first(score), last(score)' ,
1181+ () => _firestore
1182+ .pipeline ()
1183+ .collection (_collectionId)
1184+ .limit (50 )
1185+ .aggregate (
1186+ Expression .field ('score' ).first ().as ('first_score' ),
1187+ Expression .field ('score' ).last ().as ('last_score' ),
1188+ )
1189+ .execute (),
1190+ );
1191+
1192+ Future <void > _runPipeline61 () => _runPipeline (
1193+ 'Pipeline 61: limit 25 → aggregate array_agg(title)' ,
1194+ () => _firestore
1195+ .pipeline ()
1196+ .collection (_collectionId)
1197+ .limit (25 )
1198+ .aggregate (
1199+ Expression .field ('title' ).arrayAgg ().as ('all_titles' ),
1200+ )
1201+ .execute (),
1202+ );
1203+
1204+ Future <void > _runPipeline62 () => _runPipeline (
1205+ 'Pipeline 62: limit 25 → aggregate array_agg_distinct(category)' ,
1206+ () => _firestore
1207+ .pipeline ()
1208+ .collection (_collectionId)
1209+ .limit (25 )
1210+ .aggregate (
1211+ Expression .field ('category' ).arrayAggDistinct ().as ('cats' ),
1212+ )
1213+ .execute (),
1214+ );
1215+
9681216 @override
9691217 Widget build (BuildContext context) {
9701218 return Scaffold (
@@ -1043,7 +1291,6 @@ class _PipelineExamplePageState extends State<PipelineExamplePage> {
10431291 _btn ('24: lower/upper' , _runPipeline24),
10441292 _btn ('25: trim' , _runPipeline25),
10451293 _btn ('26: substring' , _runPipeline26),
1046- // test comment
10471294 _btn ('28: split' , _runPipeline28),
10481295 _btn ('29: join' , _runPipeline29),
10491296 _btn ('30: if_absent' , _runPipeline30),
@@ -1064,6 +1311,22 @@ class _PipelineExamplePageState extends State<PipelineExamplePage> {
10641311 _btn ('44: notEqualAny' , _runPipeline44),
10651312 _btn ('45: asBoolean' , _runPipeline45),
10661313 _btn ('46: isError' , _runPipeline46),
1314+ _btn ('47: regexFind' , _runPipeline47),
1315+ _btn ('48: regexFindAll' , _runPipeline48),
1316+ _btn ('49: string idx/repeat' , _runPipeline49),
1317+ _btn ('50: ltrim/rtrim' , _runPipeline50),
1318+ _btn ('51: mapSet/entries' , _runPipeline51),
1319+ _btn ('52: type(score)' , _runPipeline52),
1320+ _btn ('53: isType int64' , _runPipeline53),
1321+ _btn ('54: trunc/rand' , _runPipeline54),
1322+ _btn ('55: array first/last' , _runPipeline55),
1323+ _btn ('56: arrayFirstN/LastN' , _runPipeline56),
1324+ _btn ('57: array max/min' , _runPipeline57),
1325+ _btn ('58: arrayMaxN/MinN' , _runPipeline58),
1326+ _btn ('59: arrayIndexOf*' , _runPipeline59),
1327+ _btn ('60: agg first/last' , _runPipeline60),
1328+ _btn ('61: agg array_agg' , _runPipeline61),
1329+ _btn ('62: agg array_agg_dist' , _runPipeline62),
10671330 ],
10681331 ),
10691332 ),
0 commit comments