@react-native-firebase/firestore 23.8.6 → 24.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +35 -0
- package/RNFBFirestore.podspec +2 -1
- package/android/src/reactnative/java/io/invertase/firebase/firestore/ReactNativeFirebaseFirestoreCollectionModule.java +17 -4
- package/android/src/reactnative/java/io/invertase/firebase/firestore/ReactNativeFirebaseFirestoreDocumentModule.java +2 -2
- package/android/src/reactnative/java/io/invertase/firebase/firestore/ReactNativeFirebaseFirestorePipelineExecutor.java +1243 -0
- package/android/src/reactnative/java/io/invertase/firebase/firestore/ReactNativeFirebaseFirestorePipelineNodeBuilder.java +3919 -0
- package/android/src/reactnative/java/io/invertase/firebase/firestore/ReactNativeFirebaseFirestorePipelineParser.java +1735 -0
- package/android/src/reactnative/java/io/invertase/firebase/firestore/ReactNativeFirebaseFirestoreSerialize.java +1 -1
- package/dist/module/FieldPath.js +59 -0
- package/dist/module/FieldPath.js.map +1 -0
- package/dist/module/FieldValue.js +82 -0
- package/dist/module/FieldValue.js.map +1 -0
- package/{lib → dist/module}/FirestoreAggregate.js +31 -43
- package/dist/module/FirestoreAggregate.js.map +1 -0
- package/dist/module/FirestoreBlob.js +56 -0
- package/dist/module/FirestoreBlob.js.map +1 -0
- package/dist/module/FirestoreCollectionReference.js +70 -0
- package/dist/module/FirestoreCollectionReference.js.map +1 -0
- package/{lib → dist/module}/FirestoreDocumentChange.js +12 -15
- package/dist/module/FirestoreDocumentChange.js.map +1 -0
- package/dist/module/FirestoreDocumentReference.js +170 -0
- package/dist/module/FirestoreDocumentReference.js.map +1 -0
- package/dist/module/FirestoreDocumentSnapshot.js +88 -0
- package/dist/module/FirestoreDocumentSnapshot.js.map +1 -0
- package/dist/module/FirestoreFilter.js +146 -0
- package/dist/module/FirestoreFilter.js.map +1 -0
- package/dist/module/FirestoreGeoPoint.js +80 -0
- package/dist/module/FirestoreGeoPoint.js.map +1 -0
- package/{lib → dist/module}/FirestorePath.js +5 -12
- package/dist/module/FirestorePath.js.map +1 -0
- package/{lib → dist/module}/FirestorePersistentCacheIndexManager.js +11 -4
- package/dist/module/FirestorePersistentCacheIndexManager.js.map +1 -0
- package/dist/module/FirestoreQuery.js +298 -0
- package/dist/module/FirestoreQuery.js.map +1 -0
- package/{lib → dist/module}/FirestoreQueryModifiers.js +25 -136
- package/dist/module/FirestoreQueryModifiers.js.map +1 -0
- package/dist/module/FirestoreQuerySnapshot.js +98 -0
- package/dist/module/FirestoreQuerySnapshot.js.map +1 -0
- package/dist/module/FirestoreSnapshotMetadata.js +38 -0
- package/dist/module/FirestoreSnapshotMetadata.js.map +1 -0
- package/dist/module/FirestoreStatics.js +50 -0
- package/dist/module/FirestoreStatics.js.map +1 -0
- package/{lib → dist/module}/FirestoreTimestamp.js +39 -39
- package/dist/module/FirestoreTimestamp.js.map +1 -0
- package/dist/module/FirestoreTransaction.js +113 -0
- package/dist/module/FirestoreTransaction.js.map +1 -0
- package/dist/module/FirestoreTransactionHandler.js +137 -0
- package/dist/module/FirestoreTransactionHandler.js.map +1 -0
- package/dist/module/FirestoreVectorValue.js +75 -0
- package/dist/module/FirestoreVectorValue.js.map +1 -0
- package/dist/module/FirestoreWriteBatch.js +113 -0
- package/dist/module/FirestoreWriteBatch.js.map +1 -0
- package/dist/module/LoadBundleTask.js +70 -0
- package/dist/module/LoadBundleTask.js.map +1 -0
- package/dist/module/index.js +31 -0
- package/dist/module/index.js.map +1 -0
- package/dist/module/modular/Bytes.js +67 -0
- package/dist/module/modular/Bytes.js.map +1 -0
- package/dist/module/modular/FieldPath.js +25 -0
- package/dist/module/modular/FieldPath.js.map +1 -0
- package/dist/module/modular/FieldValue.js +37 -0
- package/dist/module/modular/FieldValue.js.map +1 -0
- package/dist/module/modular/GeoPoint.js +22 -0
- package/dist/module/modular/GeoPoint.js.map +1 -0
- package/dist/module/modular/Timestamp.js +22 -0
- package/dist/module/modular/Timestamp.js.map +1 -0
- package/dist/module/modular/VectorValue.js +25 -0
- package/dist/module/modular/VectorValue.js.map +1 -0
- package/dist/module/modular/query.js +222 -0
- package/dist/module/modular/query.js.map +1 -0
- package/dist/module/modular/snapshot.js +32 -0
- package/dist/module/modular/snapshot.js.map +1 -0
- package/dist/module/modular.js +229 -0
- package/dist/module/modular.js.map +1 -0
- package/dist/module/namespaced.js +298 -0
- package/dist/module/namespaced.js.map +1 -0
- package/dist/module/package.json +1 -0
- package/dist/module/pipelines/expressions.js +1273 -0
- package/dist/module/pipelines/expressions.js.map +1 -0
- package/dist/module/pipelines/index.js +32 -0
- package/dist/module/pipelines/index.js.map +1 -0
- package/dist/module/pipelines/pipeline-result.js +58 -0
- package/dist/module/pipelines/pipeline-result.js.map +1 -0
- package/dist/module/pipelines/pipeline-source.js +4 -0
- package/dist/module/pipelines/pipeline-source.js.map +1 -0
- package/dist/module/pipelines/pipeline.js +4 -0
- package/dist/module/pipelines/pipeline.js.map +1 -0
- package/dist/module/pipelines/pipeline_impl.js +42 -0
- package/dist/module/pipelines/pipeline_impl.js.map +1 -0
- package/dist/module/pipelines/pipeline_options.js +4 -0
- package/dist/module/pipelines/pipeline_options.js.map +1 -0
- package/dist/module/pipelines/pipeline_runtime.js +526 -0
- package/dist/module/pipelines/pipeline_runtime.js.map +1 -0
- package/dist/module/pipelines/pipeline_support.js +71 -0
- package/dist/module/pipelines/pipeline_support.js.map +1 -0
- package/dist/module/pipelines/pipeline_validate.js +183 -0
- package/dist/module/pipelines/pipeline_validate.js.map +1 -0
- package/dist/module/pipelines/stage_options.js +4 -0
- package/dist/module/pipelines/stage_options.js.map +1 -0
- package/dist/module/pipelines/types.js +2 -0
- package/dist/module/pipelines/types.js.map +1 -0
- package/dist/module/types/firestore.js +4 -0
- package/dist/module/types/firestore.js.map +1 -0
- package/dist/module/types/internal.js +4 -0
- package/dist/module/types/internal.js.map +1 -0
- package/dist/module/types/namespaced.js +338 -0
- package/dist/module/types/namespaced.js.map +1 -0
- package/{lib → dist/module}/utils/index.js +59 -114
- package/dist/module/utils/index.js.map +1 -0
- package/{lib → dist/module}/utils/serialize.js +58 -116
- package/dist/module/utils/serialize.js.map +1 -0
- package/{lib → dist/module}/utils/typemap.js +6 -20
- package/dist/module/utils/typemap.js.map +1 -0
- package/dist/module/version.js +5 -0
- package/dist/module/version.js.map +1 -0
- package/dist/module/web/RNFBFirestoreModule.android.js +5 -0
- package/dist/module/web/RNFBFirestoreModule.android.js.map +1 -0
- package/dist/module/web/RNFBFirestoreModule.ios.js +5 -0
- package/dist/module/web/RNFBFirestoreModule.ios.js.map +1 -0
- package/dist/module/web/RNFBFirestoreModule.js +387 -0
- package/dist/module/web/RNFBFirestoreModule.js.map +1 -0
- package/{lib → dist/module}/web/convert.js +60 -94
- package/dist/module/web/convert.js.map +1 -0
- package/dist/module/web/pipelines/pipeline.js +34 -0
- package/dist/module/web/pipelines/pipeline.js.map +1 -0
- package/dist/module/web/pipelines/pipeline_bridge_factory.js +217 -0
- package/dist/module/web/pipelines/pipeline_bridge_factory.js.map +1 -0
- package/dist/module/web/pipelines/pipeline_node_builder.js +294 -0
- package/dist/module/web/pipelines/pipeline_node_builder.js.map +1 -0
- package/dist/module/web/pipelines/pipeline_parser.js +21 -0
- package/dist/module/web/pipelines/pipeline_parser.js.map +1 -0
- package/dist/module/web/pipelines/pipeline_snapshot_serializer.js +89 -0
- package/dist/module/web/pipelines/pipeline_snapshot_serializer.js.map +1 -0
- package/dist/module/web/query.js +95 -0
- package/dist/module/web/query.js.map +1 -0
- package/dist/typescript/lib/FieldPath.d.ts +10 -0
- package/dist/typescript/lib/FieldPath.d.ts.map +1 -0
- package/dist/typescript/lib/FieldValue.d.ts +17 -0
- package/dist/typescript/lib/FieldValue.d.ts.map +1 -0
- package/dist/typescript/lib/FirestoreAggregate.d.ts +40 -0
- package/dist/typescript/lib/FirestoreAggregate.d.ts.map +1 -0
- package/dist/typescript/lib/FirestoreBlob.d.ts +11 -0
- package/dist/typescript/lib/FirestoreBlob.d.ts.map +1 -0
- package/dist/typescript/lib/FirestoreCollectionReference.d.ts +15 -0
- package/dist/typescript/lib/FirestoreCollectionReference.d.ts.map +1 -0
- package/dist/typescript/lib/FirestoreDocumentChange.d.ts +27 -0
- package/dist/typescript/lib/FirestoreDocumentChange.d.ts.map +1 -0
- package/dist/typescript/lib/FirestoreDocumentReference.d.ts +30 -0
- package/dist/typescript/lib/FirestoreDocumentReference.d.ts.map +1 -0
- package/dist/typescript/lib/FirestoreDocumentSnapshot.d.ts +30 -0
- package/dist/typescript/lib/FirestoreDocumentSnapshot.d.ts.map +1 -0
- package/dist/typescript/lib/FirestoreFilter.d.ts +52 -0
- package/dist/typescript/lib/FirestoreFilter.d.ts.map +1 -0
- package/dist/typescript/lib/FirestoreGeoPoint.d.ts +22 -0
- package/dist/typescript/lib/FirestoreGeoPoint.d.ts.map +1 -0
- package/dist/typescript/lib/FirestorePath.d.ts +12 -0
- package/dist/typescript/lib/FirestorePath.d.ts.map +1 -0
- package/dist/typescript/lib/FirestorePersistentCacheIndexManager.d.ts +16 -0
- package/dist/typescript/lib/FirestorePersistentCacheIndexManager.d.ts.map +1 -0
- package/dist/typescript/lib/FirestoreQuery.d.ts +39 -0
- package/dist/typescript/lib/FirestoreQuery.d.ts.map +1 -0
- package/dist/typescript/lib/FirestoreQueryModifiers.d.ts +59 -0
- package/dist/typescript/lib/FirestoreQueryModifiers.d.ts.map +1 -0
- package/dist/typescript/lib/FirestoreQuerySnapshot.d.ts +49 -0
- package/dist/typescript/lib/FirestoreQuerySnapshot.d.ts.map +1 -0
- package/dist/typescript/lib/FirestoreSnapshotMetadata.d.ts +8 -0
- package/dist/typescript/lib/FirestoreSnapshotMetadata.d.ts.map +1 -0
- package/dist/typescript/lib/FirestoreStatics.d.ts +23 -0
- package/dist/typescript/lib/FirestoreStatics.d.ts.map +1 -0
- package/dist/typescript/lib/FirestoreTimestamp.d.ts +33 -0
- package/dist/typescript/lib/FirestoreTimestamp.d.ts.map +1 -0
- package/dist/typescript/lib/FirestoreTransaction.d.ts +42 -0
- package/dist/typescript/lib/FirestoreTransaction.d.ts.map +1 -0
- package/dist/typescript/lib/FirestoreTransactionHandler.d.ts +26 -0
- package/dist/typescript/lib/FirestoreTransactionHandler.d.ts.map +1 -0
- package/dist/typescript/lib/FirestoreVectorValue.d.ts +17 -0
- package/dist/typescript/lib/FirestoreVectorValue.d.ts.map +1 -0
- package/dist/typescript/lib/FirestoreWriteBatch.d.ts +21 -0
- package/dist/typescript/lib/FirestoreWriteBatch.d.ts.map +1 -0
- package/dist/typescript/lib/LoadBundleTask.d.ts +16 -0
- package/dist/typescript/lib/LoadBundleTask.d.ts.map +1 -0
- package/dist/typescript/lib/index.d.ts +6 -0
- package/dist/typescript/lib/index.d.ts.map +1 -0
- package/dist/typescript/lib/modular/Bytes.d.ts +22 -0
- package/dist/typescript/lib/modular/Bytes.d.ts.map +1 -0
- package/dist/typescript/lib/modular/FieldPath.d.ts +4 -0
- package/dist/typescript/lib/modular/FieldPath.d.ts.map +1 -0
- package/dist/typescript/lib/modular/FieldValue.d.ts +8 -0
- package/dist/typescript/lib/modular/FieldValue.d.ts.map +1 -0
- package/dist/typescript/lib/modular/GeoPoint.d.ts +3 -0
- package/dist/typescript/lib/modular/GeoPoint.d.ts.map +1 -0
- package/dist/typescript/lib/modular/Timestamp.d.ts +3 -0
- package/dist/typescript/lib/modular/Timestamp.d.ts.map +1 -0
- package/dist/typescript/lib/modular/VectorValue.d.ts +4 -0
- package/dist/typescript/lib/modular/VectorValue.d.ts.map +1 -0
- package/dist/typescript/lib/modular/query.d.ts +93 -0
- package/dist/typescript/lib/modular/query.d.ts.map +1 -0
- package/dist/typescript/lib/modular/snapshot.d.ts +30 -0
- package/dist/typescript/lib/modular/snapshot.d.ts.map +1 -0
- package/dist/typescript/lib/modular.d.ts +69 -0
- package/dist/typescript/lib/modular.d.ts.map +1 -0
- package/dist/typescript/lib/namespaced.d.ts +13 -0
- package/dist/typescript/lib/namespaced.d.ts.map +1 -0
- package/dist/typescript/lib/pipelines/expressions.d.ts +723 -0
- package/dist/typescript/lib/pipelines/expressions.d.ts.map +1 -0
- package/dist/typescript/lib/pipelines/index.d.ts +31 -0
- package/dist/typescript/lib/pipelines/index.d.ts.map +1 -0
- package/dist/typescript/lib/pipelines/pipeline-result.d.ts +30 -0
- package/dist/typescript/lib/pipelines/pipeline-result.d.ts.map +1 -0
- package/dist/typescript/lib/pipelines/pipeline-source.d.ts +64 -0
- package/dist/typescript/lib/pipelines/pipeline-source.d.ts.map +1 -0
- package/dist/typescript/lib/pipelines/pipeline.d.ts +61 -0
- package/dist/typescript/lib/pipelines/pipeline.d.ts.map +1 -0
- package/dist/typescript/lib/pipelines/pipeline_impl.d.ts +21 -0
- package/dist/typescript/lib/pipelines/pipeline_impl.d.ts.map +1 -0
- package/dist/typescript/lib/pipelines/pipeline_options.d.ts +17 -0
- package/dist/typescript/lib/pipelines/pipeline_options.d.ts.map +1 -0
- package/dist/typescript/lib/pipelines/pipeline_runtime.d.ts +10 -0
- package/dist/typescript/lib/pipelines/pipeline_runtime.d.ts.map +1 -0
- package/dist/typescript/lib/pipelines/pipeline_support.d.ts +7 -0
- package/dist/typescript/lib/pipelines/pipeline_support.d.ts.map +1 -0
- package/dist/typescript/lib/pipelines/pipeline_validate.d.ts +9 -0
- package/dist/typescript/lib/pipelines/pipeline_validate.d.ts.map +1 -0
- package/dist/typescript/lib/pipelines/stage_options.d.ts +326 -0
- package/dist/typescript/lib/pipelines/stage_options.d.ts.map +1 -0
- package/dist/typescript/lib/pipelines/types.d.ts +10 -0
- package/dist/typescript/lib/pipelines/types.d.ts.map +1 -0
- package/dist/typescript/lib/types/firestore.d.ts +263 -0
- package/dist/typescript/lib/types/firestore.d.ts.map +1 -0
- package/dist/typescript/lib/types/internal.d.ts +483 -0
- package/dist/typescript/lib/types/internal.d.ts.map +1 -0
- package/dist/typescript/lib/types/namespaced.d.ts +2285 -0
- package/dist/typescript/lib/types/namespaced.d.ts.map +1 -0
- package/dist/typescript/lib/utils/index.d.ts +15 -0
- package/dist/typescript/lib/utils/index.d.ts.map +1 -0
- package/dist/typescript/lib/utils/serialize.d.ts +17 -0
- package/dist/typescript/lib/utils/serialize.d.ts.map +1 -0
- package/dist/typescript/lib/utils/typemap.d.ts +3 -0
- package/dist/typescript/lib/utils/typemap.d.ts.map +1 -0
- package/dist/typescript/lib/version.d.ts +2 -0
- package/dist/typescript/lib/version.d.ts.map +1 -0
- package/dist/typescript/lib/web/RNFBFirestoreModule.android.d.ts +3 -0
- package/dist/typescript/lib/web/RNFBFirestoreModule.android.d.ts.map +1 -0
- package/dist/typescript/lib/web/RNFBFirestoreModule.d.ts +75 -0
- package/dist/typescript/lib/web/RNFBFirestoreModule.d.ts.map +1 -0
- package/dist/typescript/lib/web/RNFBFirestoreModule.ios.d.ts +3 -0
- package/dist/typescript/lib/web/RNFBFirestoreModule.ios.d.ts.map +1 -0
- package/dist/typescript/lib/web/convert.d.ts +14 -0
- package/dist/typescript/lib/web/convert.d.ts.map +1 -0
- package/dist/typescript/lib/web/pipelines/pipeline.d.ts +4 -0
- package/dist/typescript/lib/web/pipelines/pipeline.d.ts.map +1 -0
- package/dist/typescript/lib/web/pipelines/pipeline_bridge_factory.d.ts +5 -0
- package/dist/typescript/lib/web/pipelines/pipeline_bridge_factory.d.ts.map +1 -0
- package/dist/typescript/lib/web/pipelines/pipeline_node_builder.d.ts +5 -0
- package/dist/typescript/lib/web/pipelines/pipeline_node_builder.d.ts.map +1 -0
- package/dist/typescript/lib/web/pipelines/pipeline_parser.d.ts +3 -0
- package/dist/typescript/lib/web/pipelines/pipeline_parser.d.ts.map +1 -0
- package/dist/typescript/lib/web/pipelines/pipeline_snapshot_serializer.d.ts +4 -0
- package/dist/typescript/lib/web/pipelines/pipeline_snapshot_serializer.d.ts.map +1 -0
- package/dist/typescript/lib/web/query.d.ts +23 -0
- package/dist/typescript/lib/web/query.d.ts.map +1 -0
- package/dist/typescript/package.json +1 -0
- package/ios/RNFBFirestore/RNFBFirestoreCollectionModule.m +52 -2
- package/ios/RNFBFirestore/RNFBFirestorePipelineBridgeFactory.swift +384 -0
- package/ios/RNFBFirestore/RNFBFirestorePipelineCallHandler.swift +86 -0
- package/ios/RNFBFirestore/RNFBFirestorePipelineNodeBuilder.swift +1500 -0
- package/ios/RNFBFirestore/RNFBFirestorePipelineParser.swift +1352 -0
- package/ios/RNFBFirestore/RNFBFirestorePipelineSnapshotSerializer.swift +98 -0
- package/lib/{FirestoreFieldPath.js → FieldPath.ts} +10 -12
- package/lib/{FirestoreFieldValue.js → FieldValue.ts} +22 -19
- package/lib/FirestoreAggregate.ts +124 -0
- package/lib/FirestoreBlob.ts +73 -0
- package/lib/FirestoreCollectionReference.ts +99 -0
- package/lib/FirestoreDocumentChange.ts +71 -0
- package/lib/FirestoreDocumentReference.ts +310 -0
- package/lib/FirestoreDocumentSnapshot.ts +149 -0
- package/lib/FirestoreFilter.ts +232 -0
- package/lib/{FirestoreGeoPoint.js → FirestoreGeoPoint.ts} +48 -8
- package/lib/FirestorePath.ts +54 -0
- package/lib/FirestorePersistentCacheIndexManager.ts +46 -0
- package/lib/{FirestoreQuery.js → FirestoreQuery.ts} +208 -100
- package/lib/FirestoreQueryModifiers.ts +411 -0
- package/lib/{FirestoreQuerySnapshot.js → FirestoreQuerySnapshot.ts} +61 -32
- package/lib/{FirestoreSnapshotMetadata.js → FirestoreSnapshotMetadata.ts} +8 -6
- package/lib/{FirestoreStatics.js → FirestoreStatics.ts} +18 -11
- package/lib/FirestoreTimestamp.ts +161 -0
- package/lib/{FirestoreTransaction.js → FirestoreTransaction.ts} +64 -27
- package/lib/{FirestoreTransactionHandler.js → FirestoreTransactionHandler.ts} +54 -75
- package/lib/{FirestoreVectorValue.js → FirestoreVectorValue.ts} +36 -15
- package/lib/{FirestoreWriteBatch.js → FirestoreWriteBatch.ts} +45 -21
- package/lib/LoadBundleTask.ts +85 -0
- package/lib/index.ts +71 -0
- package/lib/modular/Bytes.ts +81 -0
- package/lib/modular/FieldPath.ts +24 -0
- package/lib/modular/FieldValue.ts +40 -0
- package/lib/modular/GeoPoint.ts +20 -0
- package/lib/modular/Timestamp.ts +20 -0
- package/lib/modular/VectorValue.ts +24 -0
- package/lib/modular/query.ts +368 -0
- package/lib/modular/snapshot.ts +137 -0
- package/lib/modular.ts +552 -0
- package/lib/{index.js → namespaced.ts} +170 -80
- package/lib/pipelines/expressions.ts +2321 -0
- package/lib/pipelines/index.ts +203 -0
- package/lib/pipelines/pipeline-result.ts +78 -0
- package/lib/pipelines/pipeline-source.ts +83 -0
- package/lib/pipelines/pipeline.ts +99 -0
- package/lib/pipelines/pipeline_impl.ts +46 -0
- package/lib/pipelines/pipeline_options.ts +32 -0
- package/lib/pipelines/pipeline_runtime.ts +863 -0
- package/lib/pipelines/pipeline_support.ts +134 -0
- package/lib/pipelines/pipeline_validate.ts +242 -0
- package/lib/pipelines/stage_options.ts +376 -0
- package/lib/pipelines/types.ts +26 -0
- package/lib/types/firestore.ts +477 -0
- package/lib/types/internal.ts +747 -0
- package/lib/{index.d.ts → types/namespaced.ts} +280 -79
- package/lib/utils/index.ts +244 -0
- package/lib/utils/serialize.ts +314 -0
- package/lib/utils/typemap.ts +65 -0
- package/lib/version.ts +2 -0
- package/lib/web/{RNFBFirestoreModule.js → RNFBFirestoreModule.ts} +222 -234
- package/lib/web/convert.ts +287 -0
- package/lib/web/pipelines/pipeline.ts +47 -0
- package/lib/web/pipelines/pipeline_bridge_factory.ts +377 -0
- package/lib/web/pipelines/pipeline_node_builder.ts +413 -0
- package/lib/web/pipelines/pipeline_parser.ts +23 -0
- package/lib/web/pipelines/pipeline_snapshot_serializer.ts +133 -0
- package/lib/web/query.ts +150 -0
- package/package.json +46 -7
- package/tsconfig.json +35 -0
- package/lib/FirestoreBlob.js +0 -107
- package/lib/FirestoreCollectionReference.js +0 -70
- package/lib/FirestoreDocumentReference.js +0 -222
- package/lib/FirestoreDocumentSnapshot.js +0 -132
- package/lib/FirestoreFilter.js +0 -156
- package/lib/modular/Bytes.d.ts +0 -11
- package/lib/modular/Bytes.js +0 -62
- package/lib/modular/FieldPath.d.ts +0 -20
- package/lib/modular/FieldPath.js +0 -7
- package/lib/modular/FieldValue.d.ts +0 -67
- package/lib/modular/FieldValue.js +0 -41
- package/lib/modular/GeoPoint.d.ts +0 -17
- package/lib/modular/GeoPoint.js +0 -3
- package/lib/modular/Timestamp.d.ts +0 -85
- package/lib/modular/Timestamp.js +0 -3
- package/lib/modular/VectorValue.d.ts +0 -30
- package/lib/modular/VectorValue.js +0 -11
- package/lib/modular/index.d.ts +0 -788
- package/lib/modular/index.js +0 -410
- package/lib/modular/query.d.ts +0 -370
- package/lib/modular/query.js +0 -233
- package/lib/modular/snapshot.d.ts +0 -256
- package/lib/modular/snapshot.js +0 -33
- package/lib/modular/utils/observer.js +0 -16
- package/lib/version.js +0 -2
- package/lib/web/query.js +0 -112
- /package/lib/web/{RNFBFirestoreModule.android.js → RNFBFirestoreModule.android.ts} +0 -0
- /package/lib/web/{RNFBFirestoreModule.ios.js → RNFBFirestoreModule.ios.ts} +0 -0
|
@@ -0,0 +1,1243 @@
|
|
|
1
|
+
package io.invertase.firebase.firestore;
|
|
2
|
+
|
|
3
|
+
/*
|
|
4
|
+
* Copyright (c) 2016-present Invertase Limited & Contributors
|
|
5
|
+
*
|
|
6
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
7
|
+
* you may not use this library except in compliance with the License.
|
|
8
|
+
* You may obtain a copy of the License at
|
|
9
|
+
*
|
|
10
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
11
|
+
*
|
|
12
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
13
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
14
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
15
|
+
* See the License for the specific language governing permissions and
|
|
16
|
+
* limitations under the License.
|
|
17
|
+
*
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import static io.invertase.firebase.common.ReactNativeFirebaseModule.rejectPromiseWithCodeAndMessage;
|
|
21
|
+
import static io.invertase.firebase.firestore.ReactNativeFirebaseFirestoreCommon.rejectPromiseFirestoreException;
|
|
22
|
+
import static io.invertase.firebase.firestore.ReactNativeFirebaseFirestoreSerialize.objectMapToWritable;
|
|
23
|
+
import static io.invertase.firebase.firestore.UniversalFirebaseFirestoreCommon.getQueryForFirestore;
|
|
24
|
+
|
|
25
|
+
import com.facebook.react.bridge.Arguments;
|
|
26
|
+
import com.facebook.react.bridge.Promise;
|
|
27
|
+
import com.facebook.react.bridge.ReadableArray;
|
|
28
|
+
import com.facebook.react.bridge.ReadableMap;
|
|
29
|
+
import com.facebook.react.bridge.ReadableMapKeySetIterator;
|
|
30
|
+
import com.facebook.react.bridge.ReadableType;
|
|
31
|
+
import com.facebook.react.bridge.WritableArray;
|
|
32
|
+
import com.facebook.react.bridge.WritableMap;
|
|
33
|
+
import com.google.android.gms.tasks.Task;
|
|
34
|
+
import com.google.firebase.Timestamp;
|
|
35
|
+
import com.google.firebase.firestore.DocumentReference;
|
|
36
|
+
import com.google.firebase.firestore.FirebaseFirestore;
|
|
37
|
+
import com.google.firebase.firestore.Pipeline;
|
|
38
|
+
import com.google.firebase.firestore.PipelineResult;
|
|
39
|
+
import com.google.firebase.firestore.PipelineSource;
|
|
40
|
+
import com.google.firebase.firestore.Query;
|
|
41
|
+
import com.google.firebase.firestore.pipeline.AggregateStage;
|
|
42
|
+
import com.google.firebase.firestore.pipeline.AliasedAggregate;
|
|
43
|
+
import com.google.firebase.firestore.pipeline.BooleanExpression;
|
|
44
|
+
import com.google.firebase.firestore.pipeline.CollectionGroupOptions;
|
|
45
|
+
import com.google.firebase.firestore.pipeline.CollectionHints;
|
|
46
|
+
import com.google.firebase.firestore.pipeline.CollectionSourceOptions;
|
|
47
|
+
import com.google.firebase.firestore.pipeline.Expression;
|
|
48
|
+
import com.google.firebase.firestore.pipeline.FindNearestOptions;
|
|
49
|
+
import com.google.firebase.firestore.pipeline.FindNearestStage;
|
|
50
|
+
import com.google.firebase.firestore.pipeline.Ordering;
|
|
51
|
+
import com.google.firebase.firestore.pipeline.RawOptions;
|
|
52
|
+
import com.google.firebase.firestore.pipeline.RawStage;
|
|
53
|
+
import com.google.firebase.firestore.pipeline.SampleStage;
|
|
54
|
+
import com.google.firebase.firestore.pipeline.Selectable;
|
|
55
|
+
import com.google.firebase.firestore.pipeline.UnnestOptions;
|
|
56
|
+
import java.util.ArrayDeque;
|
|
57
|
+
import java.util.Arrays;
|
|
58
|
+
import java.util.HashMap;
|
|
59
|
+
import java.util.List;
|
|
60
|
+
import java.util.Locale;
|
|
61
|
+
import java.util.Map;
|
|
62
|
+
|
|
63
|
+
class ReactNativeFirebaseFirestorePipelineExecutor {
|
|
64
|
+
private final FirebaseFirestore firestore;
|
|
65
|
+
private final ReactNativeFirebaseFirestorePipelineNodeBuilder nodeBuilder;
|
|
66
|
+
|
|
67
|
+
private static final class PipelineBox {
|
|
68
|
+
Pipeline value;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
private interface PendingPipelineStage {}
|
|
72
|
+
|
|
73
|
+
private static final class ReadyPipelineStage implements PendingPipelineStage {
|
|
74
|
+
final ReactNativeFirebaseFirestorePipelineParser.ParsedPipelineStage stage;
|
|
75
|
+
|
|
76
|
+
ReadyPipelineStage(ReactNativeFirebaseFirestorePipelineParser.ParsedPipelineStage stage) {
|
|
77
|
+
this.stage = stage;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
private static final class PendingUnionPipelineStage implements PendingPipelineStage {
|
|
82
|
+
final PipelineBox childBox;
|
|
83
|
+
|
|
84
|
+
PendingUnionPipelineStage(PipelineBox childBox) {
|
|
85
|
+
this.childBox = childBox;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
private abstract static class PipelineBuildFrame {}
|
|
90
|
+
|
|
91
|
+
private static final class EnterPipelineBuildFrame extends PipelineBuildFrame {
|
|
92
|
+
final ReactNativeFirebaseFirestorePipelineParser.ParsedPipelineRequest request;
|
|
93
|
+
final PipelineBox box;
|
|
94
|
+
|
|
95
|
+
EnterPipelineBuildFrame(
|
|
96
|
+
ReactNativeFirebaseFirestorePipelineParser.ParsedPipelineRequest request, PipelineBox box) {
|
|
97
|
+
this.request = request;
|
|
98
|
+
this.box = box;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
private static final class ExitPipelineBuildFrame extends PipelineBuildFrame {
|
|
103
|
+
final Pipeline sourcePipeline;
|
|
104
|
+
final List<PendingPipelineStage> stages;
|
|
105
|
+
final PipelineBox box;
|
|
106
|
+
|
|
107
|
+
ExitPipelineBuildFrame(
|
|
108
|
+
Pipeline sourcePipeline, List<PendingPipelineStage> stages, PipelineBox box) {
|
|
109
|
+
this.sourcePipeline = sourcePipeline;
|
|
110
|
+
this.stages = stages;
|
|
111
|
+
this.box = box;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
private abstract static class ReadableContainerBuildFrame {}
|
|
116
|
+
|
|
117
|
+
private static final class ReadableMapBuildFrame extends ReadableContainerBuildFrame {
|
|
118
|
+
final ReadableMap source;
|
|
119
|
+
final Map<String, Object> target;
|
|
120
|
+
|
|
121
|
+
ReadableMapBuildFrame(ReadableMap source, Map<String, Object> target) {
|
|
122
|
+
this.source = source;
|
|
123
|
+
this.target = target;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
private static final class ReadableArrayBuildFrame extends ReadableContainerBuildFrame {
|
|
128
|
+
final ReadableArray source;
|
|
129
|
+
final List<Object> target;
|
|
130
|
+
|
|
131
|
+
ReadableArrayBuildFrame(ReadableArray source, List<Object> target) {
|
|
132
|
+
this.source = source;
|
|
133
|
+
this.target = target;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
ReactNativeFirebaseFirestorePipelineExecutor(FirebaseFirestore firestore) {
|
|
138
|
+
this.firestore = firestore;
|
|
139
|
+
this.nodeBuilder = new ReactNativeFirebaseFirestorePipelineNodeBuilder();
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
void execute(ReadableMap pipeline, ReadableMap options, Promise promise) {
|
|
143
|
+
try {
|
|
144
|
+
ReactNativeFirebaseFirestorePipelineParser.ParsedPipelineRequest request =
|
|
145
|
+
ReactNativeFirebaseFirestorePipelineParser.parse(pipeline, options);
|
|
146
|
+
Pipeline sdkPipeline = buildNativePipeline(request);
|
|
147
|
+
Pipeline.ExecuteOptions executeOptions = buildExecuteOptions(request.options);
|
|
148
|
+
Task<Pipeline.Snapshot> executeTask =
|
|
149
|
+
executeOptions == null ? sdkPipeline.execute() : sdkPipeline.execute(executeOptions);
|
|
150
|
+
executeTask.addOnCompleteListener(task -> resolvePipelineTask(task, promise));
|
|
151
|
+
} catch (PipelineValidationException e) {
|
|
152
|
+
rejectPromiseWithCodeAndMessage(promise, "invalid-argument", e.getMessage());
|
|
153
|
+
} catch (Exception e) {
|
|
154
|
+
rejectPromiseWithCodeAndMessage(
|
|
155
|
+
promise, "unknown", "Failed to execute pipeline: " + e.getMessage());
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
private void resolvePipelineTask(Task<Pipeline.Snapshot> task, Promise promise) {
|
|
160
|
+
if (task.isSuccessful()) {
|
|
161
|
+
Pipeline.Snapshot snapshot = task.getResult();
|
|
162
|
+
try {
|
|
163
|
+
promise.resolve(serializeSnapshot(snapshot));
|
|
164
|
+
} catch (PipelineValidationException e) {
|
|
165
|
+
rejectPromiseWithCodeAndMessage(promise, "unknown", e.getMessage());
|
|
166
|
+
}
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
Exception exception = task.getException();
|
|
171
|
+
if (exception != null) {
|
|
172
|
+
rejectPromiseFirestoreException(promise, exception);
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
rejectPromiseWithCodeAndMessage(
|
|
177
|
+
promise, "unknown", "Failed to execute pipeline: empty pipeline task response.");
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
private Pipeline buildNativePipeline(
|
|
181
|
+
ReactNativeFirebaseFirestorePipelineParser.ParsedPipelineRequest request)
|
|
182
|
+
throws PipelineValidationException {
|
|
183
|
+
PipelineBox rootBox = new PipelineBox();
|
|
184
|
+
ArrayDeque<PipelineBuildFrame> stack = new ArrayDeque<>();
|
|
185
|
+
stack.push(new EnterPipelineBuildFrame(request, rootBox));
|
|
186
|
+
|
|
187
|
+
while (!stack.isEmpty()) {
|
|
188
|
+
PipelineBuildFrame frame = stack.pop();
|
|
189
|
+
if (frame instanceof EnterPipelineBuildFrame) {
|
|
190
|
+
EnterPipelineBuildFrame enterFrame = (EnterPipelineBuildFrame) frame;
|
|
191
|
+
Pipeline sourcePipeline = buildSourcePipeline(enterFrame.request.source);
|
|
192
|
+
List<PendingPipelineStage> pendingStages =
|
|
193
|
+
new java.util.ArrayList<>(enterFrame.request.stages.size());
|
|
194
|
+
List<
|
|
195
|
+
Map.Entry<
|
|
196
|
+
ReactNativeFirebaseFirestorePipelineParser.ParsedPipelineRequest, PipelineBox>>
|
|
197
|
+
nestedRequests = new java.util.ArrayList<>();
|
|
198
|
+
|
|
199
|
+
for (ReactNativeFirebaseFirestorePipelineParser.ParsedPipelineStage stage :
|
|
200
|
+
enterFrame.request.stages) {
|
|
201
|
+
if (stage instanceof ReactNativeFirebaseFirestorePipelineParser.ParsedUnionStage) {
|
|
202
|
+
PipelineBox childBox = new PipelineBox();
|
|
203
|
+
pendingStages.add(new PendingUnionPipelineStage(childBox));
|
|
204
|
+
nestedRequests.add(
|
|
205
|
+
new java.util.AbstractMap.SimpleEntry<>(
|
|
206
|
+
((ReactNativeFirebaseFirestorePipelineParser.ParsedUnionStage) stage).other,
|
|
207
|
+
childBox));
|
|
208
|
+
} else {
|
|
209
|
+
pendingStages.add(new ReadyPipelineStage(stage));
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
stack.push(new ExitPipelineBuildFrame(sourcePipeline, pendingStages, enterFrame.box));
|
|
214
|
+
for (int i = nestedRequests.size() - 1; i >= 0; i--) {
|
|
215
|
+
Map.Entry<ReactNativeFirebaseFirestorePipelineParser.ParsedPipelineRequest, PipelineBox>
|
|
216
|
+
nestedEntry = nestedRequests.get(i);
|
|
217
|
+
stack.push(new EnterPipelineBuildFrame(nestedEntry.getKey(), nestedEntry.getValue()));
|
|
218
|
+
}
|
|
219
|
+
continue;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
ExitPipelineBuildFrame exitFrame = (ExitPipelineBuildFrame) frame;
|
|
223
|
+
Pipeline currentPipeline = exitFrame.sourcePipeline;
|
|
224
|
+
for (PendingPipelineStage pendingStage : exitFrame.stages) {
|
|
225
|
+
if (pendingStage instanceof ReadyPipelineStage) {
|
|
226
|
+
currentPipeline = applyStage(currentPipeline, ((ReadyPipelineStage) pendingStage).stage);
|
|
227
|
+
continue;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
Pipeline otherPipelineInstance = ((PendingUnionPipelineStage) pendingStage).childBox.value;
|
|
231
|
+
if (otherPipelineInstance == null) {
|
|
232
|
+
throw new PipelineValidationException(
|
|
233
|
+
"pipelineExecute() failed to build nested union pipeline.");
|
|
234
|
+
}
|
|
235
|
+
currentPipeline = currentPipeline.union(otherPipelineInstance);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
exitFrame.box.value = currentPipeline;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
if (rootBox.value == null) {
|
|
242
|
+
throw new PipelineValidationException("pipelineExecute() failed to build pipeline.");
|
|
243
|
+
}
|
|
244
|
+
return rootBox.value;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
private Pipeline buildSourcePipeline(
|
|
248
|
+
ReactNativeFirebaseFirestorePipelineParser.ParsedPipelineSource source)
|
|
249
|
+
throws PipelineValidationException {
|
|
250
|
+
String sourceType = source.sourceType;
|
|
251
|
+
PipelineSource pipelineSource = firestore.pipeline();
|
|
252
|
+
|
|
253
|
+
if ("collection".equals(sourceType)) {
|
|
254
|
+
CollectionSourceOptions options = buildCollectionSourceOptions(source.rawOptions);
|
|
255
|
+
return options == null
|
|
256
|
+
? pipelineSource.collection(source.path)
|
|
257
|
+
: pipelineSource.collection(firestore.collection(source.path), options);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
if ("collectionGroup".equals(sourceType)) {
|
|
261
|
+
CollectionGroupOptions options = buildCollectionGroupOptions(source.rawOptions);
|
|
262
|
+
return options == null
|
|
263
|
+
? pipelineSource.collectionGroup(source.collectionId)
|
|
264
|
+
: pipelineSource.collectionGroup(source.collectionId, options);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
if ("database".equals(sourceType)) {
|
|
268
|
+
return pipelineSource.database();
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
if ("documents".equals(sourceType)) {
|
|
272
|
+
if (source.documents == null || source.documents.length == 0) {
|
|
273
|
+
throw new PipelineValidationException(
|
|
274
|
+
"pipelineExecute() expected pipeline.source.documents to contain at least one document"
|
|
275
|
+
+ " path.");
|
|
276
|
+
}
|
|
277
|
+
return pipelineSource.documents(source.documents);
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
if ("query".equals(sourceType)) {
|
|
281
|
+
Query baseQuery = getQueryForFirestore(firestore, source.path, source.queryType);
|
|
282
|
+
ReadableArray filters = Arguments.makeNativeArray(source.filters);
|
|
283
|
+
ReadableArray orders = Arguments.makeNativeArray(source.orders);
|
|
284
|
+
ReadableMap queryOptions = Arguments.makeNativeMap(source.options);
|
|
285
|
+
ReactNativeFirebaseFirestoreQuery firestoreQuery =
|
|
286
|
+
new ReactNativeFirebaseFirestoreQuery(
|
|
287
|
+
"pipeline", "pipeline", baseQuery, filters, orders, queryOptions);
|
|
288
|
+
return pipelineSource.createFrom(firestoreQuery.query);
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
throw new PipelineValidationException("pipelineExecute() received an unknown source type.");
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
private CollectionSourceOptions buildCollectionSourceOptions(Map<String, Object> rawOptions)
|
|
295
|
+
throws PipelineValidationException {
|
|
296
|
+
CollectionHints hints = buildCollectionHints(rawOptions);
|
|
297
|
+
if (hints == null) {
|
|
298
|
+
return null;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
return new CollectionSourceOptions().withHints(hints);
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
private CollectionGroupOptions buildCollectionGroupOptions(Map<String, Object> rawOptions)
|
|
305
|
+
throws PipelineValidationException {
|
|
306
|
+
CollectionHints hints = buildCollectionHints(rawOptions);
|
|
307
|
+
if (hints == null) {
|
|
308
|
+
return null;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
return new CollectionGroupOptions().withHints(hints);
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
private CollectionHints buildCollectionHints(Map<String, Object> rawOptions)
|
|
315
|
+
throws PipelineValidationException {
|
|
316
|
+
if (rawOptions == null) {
|
|
317
|
+
return null;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
CollectionHints hints = new CollectionHints();
|
|
321
|
+
boolean hasHint = false;
|
|
322
|
+
String forceIndex = optionalString(rawOptions, "forceIndex");
|
|
323
|
+
if (forceIndex != null && !forceIndex.isEmpty()) {
|
|
324
|
+
hints = hints.withForceIndex(forceIndex);
|
|
325
|
+
hasHint = true;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
if (rawOptions.containsKey("ignoreIndexFields")) {
|
|
329
|
+
Object ignoreIndexFields = rawOptions.get("ignoreIndexFields");
|
|
330
|
+
String[] fields =
|
|
331
|
+
coerceStringList(ignoreIndexFields, "pipeline.source.rawOptions.ignoreIndexFields");
|
|
332
|
+
if (fields.length > 0) {
|
|
333
|
+
hints = hints.withIgnoreIndexFields(fields);
|
|
334
|
+
hasHint = true;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
return hasHint ? hints : null;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
private Pipeline.ExecuteOptions buildExecuteOptions(
|
|
342
|
+
ReactNativeFirebaseFirestorePipelineParser.ParsedPipelineExecuteOptions options)
|
|
343
|
+
throws PipelineValidationException {
|
|
344
|
+
if (options == null || options.isEmpty()) {
|
|
345
|
+
return null;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
Pipeline.ExecuteOptions executeOptions = new Pipeline.ExecuteOptions();
|
|
349
|
+
boolean hasOptions = false;
|
|
350
|
+
|
|
351
|
+
if ("recommended".equals(options.indexMode)) {
|
|
352
|
+
// This continues to produce "Client specified an invalid argument" error so we throw early
|
|
353
|
+
// in JS code when present
|
|
354
|
+
executeOptions = executeOptions.withIndexMode(Pipeline.ExecuteOptions.IndexMode.RECOMMENDED);
|
|
355
|
+
hasOptions = true;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
if (options.rawOptions != null) {
|
|
359
|
+
// This continues to produce "Client specified an invalid argument" error so we throw early in
|
|
360
|
+
// JS code when present
|
|
361
|
+
executeOptions = applyExecuteRawOptions(executeOptions, options.rawOptions);
|
|
362
|
+
hasOptions = true;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
return hasOptions ? executeOptions : null;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
private Pipeline applyStage(
|
|
369
|
+
Pipeline pipeline, ReactNativeFirebaseFirestorePipelineParser.ParsedPipelineStage stage)
|
|
370
|
+
throws PipelineValidationException {
|
|
371
|
+
if (stage instanceof ReactNativeFirebaseFirestorePipelineParser.ParsedWhereStage) {
|
|
372
|
+
return applyWhereStage(
|
|
373
|
+
pipeline, (ReactNativeFirebaseFirestorePipelineParser.ParsedWhereStage) stage);
|
|
374
|
+
}
|
|
375
|
+
if (stage instanceof ReactNativeFirebaseFirestorePipelineParser.ParsedSelectStage) {
|
|
376
|
+
return applySelectStage(
|
|
377
|
+
pipeline, (ReactNativeFirebaseFirestorePipelineParser.ParsedSelectStage) stage);
|
|
378
|
+
}
|
|
379
|
+
if (stage instanceof ReactNativeFirebaseFirestorePipelineParser.ParsedAddFieldsStage) {
|
|
380
|
+
return applyAddFieldsStage(
|
|
381
|
+
pipeline, (ReactNativeFirebaseFirestorePipelineParser.ParsedAddFieldsStage) stage);
|
|
382
|
+
}
|
|
383
|
+
if (stage instanceof ReactNativeFirebaseFirestorePipelineParser.ParsedRemoveFieldsStage) {
|
|
384
|
+
return applyRemoveFieldsStage(
|
|
385
|
+
pipeline, (ReactNativeFirebaseFirestorePipelineParser.ParsedRemoveFieldsStage) stage);
|
|
386
|
+
}
|
|
387
|
+
if (stage instanceof ReactNativeFirebaseFirestorePipelineParser.ParsedSortStage) {
|
|
388
|
+
return applySortStage(
|
|
389
|
+
pipeline, (ReactNativeFirebaseFirestorePipelineParser.ParsedSortStage) stage);
|
|
390
|
+
}
|
|
391
|
+
if (stage instanceof ReactNativeFirebaseFirestorePipelineParser.ParsedLimitStage) {
|
|
392
|
+
return pipeline.limit(
|
|
393
|
+
coerceInt(
|
|
394
|
+
((ReactNativeFirebaseFirestorePipelineParser.ParsedLimitStage) stage).limit,
|
|
395
|
+
"stage.options.limit"));
|
|
396
|
+
}
|
|
397
|
+
if (stage instanceof ReactNativeFirebaseFirestorePipelineParser.ParsedOffsetStage) {
|
|
398
|
+
return pipeline.offset(
|
|
399
|
+
coerceInt(
|
|
400
|
+
((ReactNativeFirebaseFirestorePipelineParser.ParsedOffsetStage) stage).offset,
|
|
401
|
+
"stage.options.offset"));
|
|
402
|
+
}
|
|
403
|
+
if (stage instanceof ReactNativeFirebaseFirestorePipelineParser.ParsedAggregateStage) {
|
|
404
|
+
return applyAggregateStage(
|
|
405
|
+
pipeline, (ReactNativeFirebaseFirestorePipelineParser.ParsedAggregateStage) stage);
|
|
406
|
+
}
|
|
407
|
+
if (stage instanceof ReactNativeFirebaseFirestorePipelineParser.ParsedDistinctStage) {
|
|
408
|
+
return applyDistinctStage(
|
|
409
|
+
pipeline, (ReactNativeFirebaseFirestorePipelineParser.ParsedDistinctStage) stage);
|
|
410
|
+
}
|
|
411
|
+
if (stage instanceof ReactNativeFirebaseFirestorePipelineParser.ParsedFindNearestStage) {
|
|
412
|
+
return applyFindNearestStage(
|
|
413
|
+
pipeline, (ReactNativeFirebaseFirestorePipelineParser.ParsedFindNearestStage) stage);
|
|
414
|
+
}
|
|
415
|
+
if (stage instanceof ReactNativeFirebaseFirestorePipelineParser.ParsedReplaceWithStage) {
|
|
416
|
+
return applyReplaceWithStage(
|
|
417
|
+
pipeline, (ReactNativeFirebaseFirestorePipelineParser.ParsedReplaceWithStage) stage);
|
|
418
|
+
}
|
|
419
|
+
if (stage instanceof ReactNativeFirebaseFirestorePipelineParser.ParsedSampleStage) {
|
|
420
|
+
return applySampleStage(
|
|
421
|
+
pipeline, (ReactNativeFirebaseFirestorePipelineParser.ParsedSampleStage) stage);
|
|
422
|
+
}
|
|
423
|
+
if (stage instanceof ReactNativeFirebaseFirestorePipelineParser.ParsedUnionStage) {
|
|
424
|
+
return applyUnionStage(
|
|
425
|
+
pipeline, (ReactNativeFirebaseFirestorePipelineParser.ParsedUnionStage) stage);
|
|
426
|
+
}
|
|
427
|
+
if (stage instanceof ReactNativeFirebaseFirestorePipelineParser.ParsedUnnestStage) {
|
|
428
|
+
return applyUnnestStage(
|
|
429
|
+
pipeline, (ReactNativeFirebaseFirestorePipelineParser.ParsedUnnestStage) stage);
|
|
430
|
+
}
|
|
431
|
+
if (stage instanceof ReactNativeFirebaseFirestorePipelineParser.ParsedRawStage) {
|
|
432
|
+
return applyRawStage(
|
|
433
|
+
pipeline, (ReactNativeFirebaseFirestorePipelineParser.ParsedRawStage) stage);
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
throw new PipelineValidationException(
|
|
437
|
+
"pipelineExecute() received an unknown stage: " + stage.stageName + ".");
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
private Pipeline applyWhereStage(
|
|
441
|
+
Pipeline pipeline, ReactNativeFirebaseFirestorePipelineParser.ParsedWhereStage stage)
|
|
442
|
+
throws PipelineValidationException {
|
|
443
|
+
BooleanExpression condition =
|
|
444
|
+
nodeBuilder.coerceBooleanExpression(stage.condition, "stage.options.condition");
|
|
445
|
+
return pipeline.where(condition);
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
private Pipeline applySelectStage(
|
|
449
|
+
Pipeline pipeline, ReactNativeFirebaseFirestorePipelineParser.ParsedSelectStage stage)
|
|
450
|
+
throws PipelineValidationException {
|
|
451
|
+
List<ReactNativeFirebaseFirestorePipelineParser.ParsedSelectableNode> selections =
|
|
452
|
+
stage.selections;
|
|
453
|
+
if (selections.isEmpty()) {
|
|
454
|
+
throw new PipelineValidationException(
|
|
455
|
+
"pipelineExecute() expected stage.options.selections to contain at least one value.");
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
Selectable[] selectables = new Selectable[selections.size()];
|
|
459
|
+
for (int i = 0; i < selections.size(); i++) {
|
|
460
|
+
selectables[i] =
|
|
461
|
+
nodeBuilder.coerceSelectable(selections.get(i), "stage.options.selections[" + i + "]");
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
Selectable first = selectables[0];
|
|
465
|
+
Selectable[] rest = Arrays.copyOfRange(selectables, 1, selectables.length);
|
|
466
|
+
return pipeline.select(first, (Object[]) rest);
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
private Pipeline applyAddFieldsStage(
|
|
470
|
+
Pipeline pipeline, ReactNativeFirebaseFirestorePipelineParser.ParsedAddFieldsStage stage)
|
|
471
|
+
throws PipelineValidationException {
|
|
472
|
+
List<ReactNativeFirebaseFirestorePipelineParser.ParsedSelectableNode> fields = stage.fields;
|
|
473
|
+
if (fields.isEmpty()) {
|
|
474
|
+
throw new PipelineValidationException(
|
|
475
|
+
"pipelineExecute() expected stage.options.fields to contain at least one value.");
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
Selectable[] selectables = new Selectable[fields.size()];
|
|
479
|
+
for (int i = 0; i < fields.size(); i++) {
|
|
480
|
+
selectables[i] =
|
|
481
|
+
nodeBuilder.coerceSelectable(fields.get(i), "stage.options.fields[" + i + "]");
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
Selectable first = selectables[0];
|
|
485
|
+
Selectable[] rest = Arrays.copyOfRange(selectables, 1, selectables.length);
|
|
486
|
+
return pipeline.addFields(first, rest);
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
private Pipeline applyRemoveFieldsStage(
|
|
490
|
+
Pipeline pipeline, ReactNativeFirebaseFirestorePipelineParser.ParsedRemoveFieldsStage stage)
|
|
491
|
+
throws PipelineValidationException {
|
|
492
|
+
String[] fields = coerceStringList(stage.fields, "stage.options.fields");
|
|
493
|
+
if (fields.length == 0) {
|
|
494
|
+
throw new PipelineValidationException(
|
|
495
|
+
"pipelineExecute() expected stage.options.fields to contain at least one value.");
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
String first = fields[0];
|
|
499
|
+
String[] rest = Arrays.copyOfRange(fields, 1, fields.length);
|
|
500
|
+
return pipeline.removeFields(first, rest);
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
private Pipeline applySortStage(
|
|
504
|
+
Pipeline pipeline, ReactNativeFirebaseFirestorePipelineParser.ParsedSortStage stage)
|
|
505
|
+
throws PipelineValidationException {
|
|
506
|
+
List<ReactNativeFirebaseFirestorePipelineParser.ParsedOrderingNode> orderings = stage.orderings;
|
|
507
|
+
if (orderings.isEmpty()) {
|
|
508
|
+
throw new PipelineValidationException(
|
|
509
|
+
"pipelineExecute() expected stage.options.orderings to contain at least one value.");
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
Ordering[] nativeOrderings = new Ordering[orderings.size()];
|
|
513
|
+
for (int i = 0; i < orderings.size(); i++) {
|
|
514
|
+
nativeOrderings[i] =
|
|
515
|
+
nodeBuilder.coerceOrdering(orderings.get(i), "stage.options.orderings[" + i + "]");
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
Ordering first = nativeOrderings[0];
|
|
519
|
+
Ordering[] rest = Arrays.copyOfRange(nativeOrderings, 1, nativeOrderings.length);
|
|
520
|
+
return pipeline.sort(first, rest);
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
private Pipeline applyAggregateStage(
|
|
524
|
+
Pipeline pipeline, ReactNativeFirebaseFirestorePipelineParser.ParsedAggregateStage stage)
|
|
525
|
+
throws PipelineValidationException {
|
|
526
|
+
List<ReactNativeFirebaseFirestorePipelineParser.ParsedAggregateNode> accumulators =
|
|
527
|
+
stage.accumulators;
|
|
528
|
+
if (accumulators.isEmpty()) {
|
|
529
|
+
throw new PipelineValidationException(
|
|
530
|
+
"pipelineExecute() expected stage.options.accumulators to contain at least one value.");
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
AliasedAggregate[] aliasedAggregates = new AliasedAggregate[accumulators.size()];
|
|
534
|
+
for (int i = 0; i < accumulators.size(); i++) {
|
|
535
|
+
aliasedAggregates[i] =
|
|
536
|
+
nodeBuilder.coerceAliasedAggregate(
|
|
537
|
+
accumulators.get(i), "stage.options.accumulators[" + i + "]");
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
AliasedAggregate firstAccumulator = aliasedAggregates[0];
|
|
541
|
+
AliasedAggregate[] restAccumulators =
|
|
542
|
+
Arrays.copyOfRange(aliasedAggregates, 1, aliasedAggregates.length);
|
|
543
|
+
AggregateStage aggregateStage =
|
|
544
|
+
AggregateStage.withAccumulators(firstAccumulator, restAccumulators);
|
|
545
|
+
|
|
546
|
+
if (stage.groups != null) {
|
|
547
|
+
List<ReactNativeFirebaseFirestorePipelineParser.ParsedSelectableNode> groups = stage.groups;
|
|
548
|
+
if (!groups.isEmpty()) {
|
|
549
|
+
Selectable[] selectableGroups = new Selectable[groups.size()];
|
|
550
|
+
for (int i = 0; i < groups.size(); i++) {
|
|
551
|
+
selectableGroups[i] =
|
|
552
|
+
nodeBuilder.coerceSelectable(groups.get(i), "stage.options.groups[" + i + "]");
|
|
553
|
+
}
|
|
554
|
+
Selectable firstGroup = selectableGroups[0];
|
|
555
|
+
Object[] restGroups = Arrays.copyOfRange(selectableGroups, 1, selectableGroups.length);
|
|
556
|
+
aggregateStage = aggregateStage.withGroups(firstGroup, restGroups);
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
return pipeline.aggregate(aggregateStage);
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
private Pipeline applyDistinctStage(
|
|
564
|
+
Pipeline pipeline, ReactNativeFirebaseFirestorePipelineParser.ParsedDistinctStage stage)
|
|
565
|
+
throws PipelineValidationException {
|
|
566
|
+
List<ReactNativeFirebaseFirestorePipelineParser.ParsedSelectableNode> groups = stage.groups;
|
|
567
|
+
if (groups.isEmpty()) {
|
|
568
|
+
throw new PipelineValidationException(
|
|
569
|
+
"pipelineExecute() expected stage.options.groups to contain at least one value.");
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
Selectable[] selectables = new Selectable[groups.size()];
|
|
573
|
+
for (int i = 0; i < groups.size(); i++) {
|
|
574
|
+
selectables[i] =
|
|
575
|
+
nodeBuilder.coerceSelectable(groups.get(i), "stage.options.groups[" + i + "]");
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
Selectable first = selectables[0];
|
|
579
|
+
Object[] rest = Arrays.copyOfRange(selectables, 1, selectables.length);
|
|
580
|
+
return pipeline.distinct(first, rest);
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
private Pipeline applyFindNearestStage(
|
|
584
|
+
Pipeline pipeline, ReactNativeFirebaseFirestorePipelineParser.ParsedFindNearestStage stage)
|
|
585
|
+
throws PipelineValidationException {
|
|
586
|
+
String fieldPath = nodeBuilder.coerceFieldPath(stage.field, "stage.options.field");
|
|
587
|
+
double[] vector = nodeBuilder.coerceVectorValue(stage.vectorValue);
|
|
588
|
+
FindNearestStage.DistanceMeasure distanceMeasure =
|
|
589
|
+
coerceDistanceMeasure(stage.distanceMeasure, "stage.options.distanceMeasure");
|
|
590
|
+
|
|
591
|
+
boolean hasOptions = stage.limit != null || stage.distanceField != null;
|
|
592
|
+
if (!hasOptions) {
|
|
593
|
+
return pipeline.findNearest(fieldPath, vector, distanceMeasure);
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
FindNearestOptions options = new FindNearestOptions();
|
|
597
|
+
if (stage.limit != null) {
|
|
598
|
+
options = options.withLimit(coerceLong(stage.limit, "stage.options.limit"));
|
|
599
|
+
}
|
|
600
|
+
String distanceField = stage.distanceField;
|
|
601
|
+
if (distanceField != null && !distanceField.isEmpty()) {
|
|
602
|
+
options = options.withDistanceField(distanceField);
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
return pipeline.findNearest(fieldPath, Expression.vector(vector), distanceMeasure, options);
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
private Pipeline applyReplaceWithStage(
|
|
609
|
+
Pipeline pipeline, ReactNativeFirebaseFirestorePipelineParser.ParsedReplaceWithStage stage)
|
|
610
|
+
throws PipelineValidationException {
|
|
611
|
+
Expression expression = nodeBuilder.coerceExpression(stage.map, "stage.options.map");
|
|
612
|
+
return pipeline.replaceWith(expression);
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
private Pipeline applySampleStage(
|
|
616
|
+
Pipeline pipeline, ReactNativeFirebaseFirestorePipelineParser.ParsedSampleStage stage)
|
|
617
|
+
throws PipelineValidationException {
|
|
618
|
+
if (stage.documents != null) {
|
|
619
|
+
int documents = coerceInt(stage.documents, "stage.options.documents");
|
|
620
|
+
return pipeline.sample(documents);
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
if (stage.percentage != null) {
|
|
624
|
+
double percentage = coerceDouble(stage.percentage, "stage.options.percentage");
|
|
625
|
+
return pipeline.sample(SampleStage.withPercentage(percentage));
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
throw new PipelineValidationException(
|
|
629
|
+
"pipelineExecute() expected sample stage to include documents or percentage.");
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
private Pipeline applyUnionStage(
|
|
633
|
+
Pipeline pipeline, ReactNativeFirebaseFirestorePipelineParser.ParsedUnionStage stage)
|
|
634
|
+
throws PipelineValidationException {
|
|
635
|
+
throw new PipelineValidationException(
|
|
636
|
+
"pipelineExecute() failed to build nested union pipeline.");
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
private Pipeline applyUnnestStage(
|
|
640
|
+
Pipeline pipeline, ReactNativeFirebaseFirestorePipelineParser.ParsedUnnestStage stage)
|
|
641
|
+
throws PipelineValidationException {
|
|
642
|
+
Selectable selectable =
|
|
643
|
+
nodeBuilder.coerceSelectable(stage.selectable, "stage.options.selectable");
|
|
644
|
+
|
|
645
|
+
String indexField = stage.indexField;
|
|
646
|
+
if (indexField == null || indexField.isEmpty()) {
|
|
647
|
+
return pipeline.unnest(selectable);
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
UnnestOptions options = new UnnestOptions().withIndexField(indexField);
|
|
651
|
+
return pipeline.unnest(selectable, options);
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
private Pipeline applyRawStage(
|
|
655
|
+
Pipeline pipeline, ReactNativeFirebaseFirestorePipelineParser.ParsedRawStage stage)
|
|
656
|
+
throws PipelineValidationException {
|
|
657
|
+
RawStage rawStage = RawStage.ofName(stage.name);
|
|
658
|
+
|
|
659
|
+
if (stage.params != null) {
|
|
660
|
+
Object paramsValue = stage.params;
|
|
661
|
+
if (paramsValue instanceof List) {
|
|
662
|
+
Object[] args = ((List<?>) paramsValue).toArray();
|
|
663
|
+
rawStage = rawStage.withArguments(args);
|
|
664
|
+
} else {
|
|
665
|
+
rawStage = rawStage.withArguments(paramsValue);
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
if (stage.options != null) {
|
|
670
|
+
rawStage = applyPrimitiveRawStageOptions(rawStage, stage.options);
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
return pipeline.rawStage(rawStage);
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
private <T extends com.google.firebase.firestore.pipeline.AbstractOptions<T>>
|
|
677
|
+
T applyPrimitiveRawOptions(T options, Map<String, Object> rawOptions)
|
|
678
|
+
throws PipelineValidationException {
|
|
679
|
+
for (Map.Entry<String, Object> entry : rawOptions.entrySet()) {
|
|
680
|
+
String key = entry.getKey();
|
|
681
|
+
Object rawValue = entry.getValue();
|
|
682
|
+
if (rawValue == null) {
|
|
683
|
+
continue;
|
|
684
|
+
}
|
|
685
|
+
if (rawValue instanceof Boolean) {
|
|
686
|
+
options = options.with(key, (Boolean) rawValue);
|
|
687
|
+
continue;
|
|
688
|
+
}
|
|
689
|
+
if (rawValue instanceof String) {
|
|
690
|
+
options = options.with(key, (String) rawValue);
|
|
691
|
+
continue;
|
|
692
|
+
}
|
|
693
|
+
if (rawValue instanceof Number) {
|
|
694
|
+
Number numberValue = (Number) rawValue;
|
|
695
|
+
if (numberValue instanceof Double || numberValue instanceof Float) {
|
|
696
|
+
options = options.with(key, numberValue.doubleValue());
|
|
697
|
+
} else {
|
|
698
|
+
options = options.with(key, numberValue.longValue());
|
|
699
|
+
}
|
|
700
|
+
continue;
|
|
701
|
+
}
|
|
702
|
+
if (rawValue instanceof List) {
|
|
703
|
+
throw new PipelineValidationException(
|
|
704
|
+
"pipelineExecute() received an unsupported raw option array for key: " + key + ".");
|
|
705
|
+
}
|
|
706
|
+
if (rawValue instanceof Map) {
|
|
707
|
+
String fieldPath = nodeBuilder.coerceFieldPath(rawValue, "options.rawOptions." + key);
|
|
708
|
+
options = options.with(key, Expression.field(fieldPath));
|
|
709
|
+
continue;
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
throw new PipelineValidationException(
|
|
713
|
+
"pipelineExecute() received an unsupported raw option value for key: " + key + ".");
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
return options;
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
private Pipeline.ExecuteOptions applyExecuteRawOptions(
|
|
720
|
+
Pipeline.ExecuteOptions options, Map<String, Object> rawOptions)
|
|
721
|
+
throws PipelineValidationException {
|
|
722
|
+
for (Map.Entry<String, Object> entry : rawOptions.entrySet()) {
|
|
723
|
+
String rawKey = entry.getKey();
|
|
724
|
+
String key = normalizeRawOptionKey(rawKey);
|
|
725
|
+
Object rawValue = entry.getValue();
|
|
726
|
+
if (rawValue == null) {
|
|
727
|
+
continue;
|
|
728
|
+
}
|
|
729
|
+
if (rawValue instanceof Boolean) {
|
|
730
|
+
options = options.with(key, (Boolean) rawValue);
|
|
731
|
+
continue;
|
|
732
|
+
}
|
|
733
|
+
if (rawValue instanceof String) {
|
|
734
|
+
options = options.with(key, (String) rawValue);
|
|
735
|
+
continue;
|
|
736
|
+
}
|
|
737
|
+
if (rawValue instanceof Number) {
|
|
738
|
+
Number numberValue = (Number) rawValue;
|
|
739
|
+
if (numberValue instanceof Double || numberValue instanceof Float) {
|
|
740
|
+
options = options.with(key, numberValue.doubleValue());
|
|
741
|
+
} else {
|
|
742
|
+
options = options.with(key, numberValue.longValue());
|
|
743
|
+
}
|
|
744
|
+
continue;
|
|
745
|
+
}
|
|
746
|
+
if (rawValue instanceof Map) {
|
|
747
|
+
@SuppressWarnings("unchecked")
|
|
748
|
+
Map<String, Object> nestedMap = (Map<String, Object>) rawValue;
|
|
749
|
+
options = options.with(key, toRawOptions(nestedMap, "options.rawOptions." + rawKey));
|
|
750
|
+
continue;
|
|
751
|
+
}
|
|
752
|
+
if (rawValue instanceof List) {
|
|
753
|
+
throw new PipelineValidationException(
|
|
754
|
+
"pipelineExecute() received an unsupported raw option array for key: " + rawKey + ".");
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
throw new PipelineValidationException(
|
|
758
|
+
"pipelineExecute() received an unsupported raw option value for key: " + rawKey + ".");
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
return options;
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
private RawOptions toRawOptions(Map<String, Object> rawOptions, String fieldName)
|
|
765
|
+
throws PipelineValidationException {
|
|
766
|
+
RawOptions options = RawOptions.DEFAULT;
|
|
767
|
+
for (Map.Entry<String, Object> entry : rawOptions.entrySet()) {
|
|
768
|
+
String rawKey = entry.getKey();
|
|
769
|
+
String key = normalizeRawOptionKey(rawKey);
|
|
770
|
+
Object rawValue = entry.getValue();
|
|
771
|
+
if (rawValue == null) {
|
|
772
|
+
continue;
|
|
773
|
+
}
|
|
774
|
+
if (rawValue instanceof Boolean) {
|
|
775
|
+
options = options.with(key, (Boolean) rawValue);
|
|
776
|
+
continue;
|
|
777
|
+
}
|
|
778
|
+
if (rawValue instanceof String) {
|
|
779
|
+
options = options.with(key, (String) rawValue);
|
|
780
|
+
continue;
|
|
781
|
+
}
|
|
782
|
+
if (rawValue instanceof Number) {
|
|
783
|
+
Number numberValue = (Number) rawValue;
|
|
784
|
+
if (numberValue instanceof Double || numberValue instanceof Float) {
|
|
785
|
+
options = options.with(key, numberValue.doubleValue());
|
|
786
|
+
} else {
|
|
787
|
+
options = options.with(key, numberValue.longValue());
|
|
788
|
+
}
|
|
789
|
+
continue;
|
|
790
|
+
}
|
|
791
|
+
if (rawValue instanceof Map) {
|
|
792
|
+
@SuppressWarnings("unchecked")
|
|
793
|
+
Map<String, Object> nestedMap = (Map<String, Object>) rawValue;
|
|
794
|
+
options = options.with(key, toRawOptions(nestedMap, fieldName + "." + rawKey));
|
|
795
|
+
continue;
|
|
796
|
+
}
|
|
797
|
+
if (rawValue instanceof List) {
|
|
798
|
+
throw new PipelineValidationException(
|
|
799
|
+
"pipelineExecute() received an unsupported raw option array for key: " + rawKey + ".");
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
throw new PipelineValidationException(
|
|
803
|
+
"pipelineExecute() received an unsupported raw option value for key: " + rawKey + ".");
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
return options;
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
private String normalizeRawOptionKey(String key) {
|
|
810
|
+
if (key == null || key.isEmpty()) {
|
|
811
|
+
return key;
|
|
812
|
+
}
|
|
813
|
+
|
|
814
|
+
StringBuilder normalized = new StringBuilder();
|
|
815
|
+
for (int i = 0; i < key.length(); i++) {
|
|
816
|
+
char character = key.charAt(i);
|
|
817
|
+
if (Character.isUpperCase(character)) {
|
|
818
|
+
if (i > 0) {
|
|
819
|
+
normalized.append('_');
|
|
820
|
+
}
|
|
821
|
+
normalized.append(Character.toLowerCase(character));
|
|
822
|
+
} else {
|
|
823
|
+
normalized.append(character);
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
return normalized.toString();
|
|
827
|
+
}
|
|
828
|
+
|
|
829
|
+
private RawStage applyPrimitiveRawStageOptions(RawStage rawStage, Map<String, Object> options)
|
|
830
|
+
throws PipelineValidationException {
|
|
831
|
+
for (Map.Entry<String, Object> entry : options.entrySet()) {
|
|
832
|
+
String key = entry.getKey();
|
|
833
|
+
Object rawValue = entry.getValue();
|
|
834
|
+
if (rawValue == null) {
|
|
835
|
+
continue;
|
|
836
|
+
}
|
|
837
|
+
if (rawValue instanceof Boolean) {
|
|
838
|
+
rawStage = rawStage.withOption(key, (Boolean) rawValue);
|
|
839
|
+
continue;
|
|
840
|
+
}
|
|
841
|
+
if (rawValue instanceof String) {
|
|
842
|
+
rawStage = rawStage.withOption(key, (String) rawValue);
|
|
843
|
+
continue;
|
|
844
|
+
}
|
|
845
|
+
if (rawValue instanceof Number) {
|
|
846
|
+
Number numberValue = (Number) rawValue;
|
|
847
|
+
if (numberValue instanceof Double || numberValue instanceof Float) {
|
|
848
|
+
rawStage = rawStage.withOption(key, numberValue.doubleValue());
|
|
849
|
+
} else {
|
|
850
|
+
rawStage = rawStage.withOption(key, numberValue.longValue());
|
|
851
|
+
}
|
|
852
|
+
continue;
|
|
853
|
+
}
|
|
854
|
+
if (rawValue instanceof Map) {
|
|
855
|
+
String fieldPath = nodeBuilder.coerceFieldPath(rawValue, "stage.options.options." + key);
|
|
856
|
+
rawStage = rawStage.withOption(key, Expression.field(fieldPath));
|
|
857
|
+
continue;
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
throw new PipelineValidationException(
|
|
861
|
+
"pipelineExecute() received an unsupported raw stage option value for key: " + key + ".");
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
return rawStage;
|
|
865
|
+
}
|
|
866
|
+
|
|
867
|
+
private WritableMap serializeSnapshot(Pipeline.Snapshot snapshot)
|
|
868
|
+
throws PipelineValidationException {
|
|
869
|
+
WritableMap map = Arguments.createMap();
|
|
870
|
+
WritableArray results = Arguments.createArray();
|
|
871
|
+
List<PipelineResult> pipelineResults = snapshot != null ? snapshot.getResults() : null;
|
|
872
|
+
|
|
873
|
+
if (pipelineResults != null) {
|
|
874
|
+
for (PipelineResult result : pipelineResults) {
|
|
875
|
+
results.pushMap(serializeResult(result));
|
|
876
|
+
}
|
|
877
|
+
}
|
|
878
|
+
|
|
879
|
+
map.putArray("results", results);
|
|
880
|
+
if (snapshot != null) {
|
|
881
|
+
WritableMap executionTime = serializeTimestamp(snapshot.getExecutionTime());
|
|
882
|
+
if (executionTime == null) {
|
|
883
|
+
throw new PipelineValidationException(
|
|
884
|
+
"pipelineExecute() expected native snapshot to include executionTime.");
|
|
885
|
+
}
|
|
886
|
+
map.putMap("executionTime", executionTime);
|
|
887
|
+
}
|
|
888
|
+
return map;
|
|
889
|
+
}
|
|
890
|
+
|
|
891
|
+
private WritableMap serializeResult(PipelineResult result) {
|
|
892
|
+
WritableMap map = Arguments.createMap();
|
|
893
|
+
if (result == null) {
|
|
894
|
+
return map;
|
|
895
|
+
}
|
|
896
|
+
|
|
897
|
+
DocumentReference reference = result.getRef();
|
|
898
|
+
if (reference != null) {
|
|
899
|
+
map.putString("path", reference.getPath());
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
String id = result.getId();
|
|
903
|
+
if (id != null) {
|
|
904
|
+
map.putString("id", id);
|
|
905
|
+
} else {
|
|
906
|
+
map.putNull("id");
|
|
907
|
+
}
|
|
908
|
+
|
|
909
|
+
Map<String, Object> data = result.getData();
|
|
910
|
+
if (data != null) {
|
|
911
|
+
Object normalizedData = unwrapPipelineResultValue(data);
|
|
912
|
+
if (normalizedData instanceof Map) {
|
|
913
|
+
map.putMap("data", objectMapToWritable((Map<String, Object>) normalizedData));
|
|
914
|
+
}
|
|
915
|
+
}
|
|
916
|
+
|
|
917
|
+
WritableMap createTime = serializeTimestamp(result.getCreateTime());
|
|
918
|
+
if (createTime != null) {
|
|
919
|
+
map.putMap("createTime", createTime);
|
|
920
|
+
} else {
|
|
921
|
+
map.putNull("createTime");
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
WritableMap updateTime = serializeTimestamp(result.getUpdateTime());
|
|
925
|
+
if (updateTime != null) {
|
|
926
|
+
map.putMap("updateTime", updateTime);
|
|
927
|
+
} else {
|
|
928
|
+
map.putNull("updateTime");
|
|
929
|
+
}
|
|
930
|
+
|
|
931
|
+
return map;
|
|
932
|
+
}
|
|
933
|
+
|
|
934
|
+
private WritableMap serializeTimestamp(Timestamp timestamp) {
|
|
935
|
+
if (timestamp == null) {
|
|
936
|
+
return null;
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
WritableMap map = Arguments.createMap();
|
|
940
|
+
map.putDouble("seconds", timestamp.getSeconds());
|
|
941
|
+
map.putInt("nanoseconds", timestamp.getNanoseconds());
|
|
942
|
+
return map;
|
|
943
|
+
}
|
|
944
|
+
|
|
945
|
+
private Object unwrapPipelineResultValue(Object value) {
|
|
946
|
+
if (value instanceof List) {
|
|
947
|
+
List<?> listValue = (List<?>) value;
|
|
948
|
+
List<Object> normalized = new java.util.ArrayList<>(listValue.size());
|
|
949
|
+
for (Object item : listValue) {
|
|
950
|
+
normalized.add(unwrapPipelineResultValue(item));
|
|
951
|
+
}
|
|
952
|
+
return normalized;
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
if (!(value instanceof Map)) {
|
|
956
|
+
return value;
|
|
957
|
+
}
|
|
958
|
+
|
|
959
|
+
Map<?, ?> mapValue = (Map<?, ?>) value;
|
|
960
|
+
Object exprType = mapValue.get("exprType");
|
|
961
|
+
if (exprType instanceof String && ((String) exprType).equalsIgnoreCase("constant")) {
|
|
962
|
+
return unwrapPipelineResultValue(mapValue.get("value"));
|
|
963
|
+
}
|
|
964
|
+
|
|
965
|
+
Map<String, Object> normalized = new java.util.LinkedHashMap<>();
|
|
966
|
+
for (Map.Entry<?, ?> entry : mapValue.entrySet()) {
|
|
967
|
+
if (entry.getKey() instanceof String) {
|
|
968
|
+
normalized.put((String) entry.getKey(), unwrapPipelineResultValue(entry.getValue()));
|
|
969
|
+
}
|
|
970
|
+
}
|
|
971
|
+
return normalized;
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
private Object getJavaValue(ReadableMap map, String key) {
|
|
975
|
+
if (map == null || !map.hasKey(key)) {
|
|
976
|
+
return null;
|
|
977
|
+
}
|
|
978
|
+
|
|
979
|
+
ReadableType type = map.getType(key);
|
|
980
|
+
if (type == ReadableType.Null) {
|
|
981
|
+
return null;
|
|
982
|
+
}
|
|
983
|
+
|
|
984
|
+
switch (type) {
|
|
985
|
+
case Boolean:
|
|
986
|
+
return map.getBoolean(key);
|
|
987
|
+
case Number:
|
|
988
|
+
return coerceNumber(map.getDouble(key));
|
|
989
|
+
case String:
|
|
990
|
+
return map.getString(key);
|
|
991
|
+
case Map:
|
|
992
|
+
ReadableMap nestedMap = map.getMap(key);
|
|
993
|
+
return nestedMap == null ? null : readableMapToJava(nestedMap);
|
|
994
|
+
case Array:
|
|
995
|
+
ReadableArray nestedArray = map.getArray(key);
|
|
996
|
+
return nestedArray == null ? null : readableArrayToJava(nestedArray);
|
|
997
|
+
case Null:
|
|
998
|
+
default:
|
|
999
|
+
return null;
|
|
1000
|
+
}
|
|
1001
|
+
}
|
|
1002
|
+
|
|
1003
|
+
private Map<String, Object> readableMapToJava(ReadableMap readableMap) {
|
|
1004
|
+
Map<String, Object> output = new HashMap<>();
|
|
1005
|
+
ArrayDeque<ReadableContainerBuildFrame> stack = new ArrayDeque<>();
|
|
1006
|
+
stack.push(new ReadableMapBuildFrame(readableMap, output));
|
|
1007
|
+
populateReadableContainers(stack);
|
|
1008
|
+
return output;
|
|
1009
|
+
}
|
|
1010
|
+
|
|
1011
|
+
private List<Object> readableArrayToJava(ReadableArray readableArray) {
|
|
1012
|
+
List<Object> output = new java.util.ArrayList<>();
|
|
1013
|
+
ArrayDeque<ReadableContainerBuildFrame> stack = new ArrayDeque<>();
|
|
1014
|
+
stack.push(new ReadableArrayBuildFrame(readableArray, output));
|
|
1015
|
+
populateReadableContainers(stack);
|
|
1016
|
+
return output;
|
|
1017
|
+
}
|
|
1018
|
+
|
|
1019
|
+
private void populateReadableContainers(ArrayDeque<ReadableContainerBuildFrame> stack) {
|
|
1020
|
+
// Use an explicit stack so deeply nested pipeline inputs do not rely on JVM recursion depth.
|
|
1021
|
+
while (!stack.isEmpty()) {
|
|
1022
|
+
ReadableContainerBuildFrame frame = stack.pop();
|
|
1023
|
+
|
|
1024
|
+
if (frame instanceof ReadableMapBuildFrame) {
|
|
1025
|
+
ReadableMapBuildFrame mapFrame = (ReadableMapBuildFrame) frame;
|
|
1026
|
+
ReadableMapKeySetIterator iterator = mapFrame.source.keySetIterator();
|
|
1027
|
+
|
|
1028
|
+
while (iterator.hasNextKey()) {
|
|
1029
|
+
String key = iterator.nextKey();
|
|
1030
|
+
ReadableType type = mapFrame.source.getType(key);
|
|
1031
|
+
if (type == ReadableType.Null) {
|
|
1032
|
+
mapFrame.target.put(key, null);
|
|
1033
|
+
continue;
|
|
1034
|
+
}
|
|
1035
|
+
|
|
1036
|
+
switch (type) {
|
|
1037
|
+
case Boolean:
|
|
1038
|
+
mapFrame.target.put(key, mapFrame.source.getBoolean(key));
|
|
1039
|
+
break;
|
|
1040
|
+
case Number:
|
|
1041
|
+
mapFrame.target.put(key, coerceNumber(mapFrame.source.getDouble(key)));
|
|
1042
|
+
break;
|
|
1043
|
+
case String:
|
|
1044
|
+
mapFrame.target.put(key, mapFrame.source.getString(key));
|
|
1045
|
+
break;
|
|
1046
|
+
case Map:
|
|
1047
|
+
ReadableMap nestedMap = mapFrame.source.getMap(key);
|
|
1048
|
+
if (nestedMap == null) {
|
|
1049
|
+
mapFrame.target.put(key, null);
|
|
1050
|
+
break;
|
|
1051
|
+
}
|
|
1052
|
+
|
|
1053
|
+
Map<String, Object> nestedMapOutput = new HashMap<>();
|
|
1054
|
+
mapFrame.target.put(key, nestedMapOutput);
|
|
1055
|
+
stack.push(new ReadableMapBuildFrame(nestedMap, nestedMapOutput));
|
|
1056
|
+
break;
|
|
1057
|
+
case Array:
|
|
1058
|
+
ReadableArray nestedArray = mapFrame.source.getArray(key);
|
|
1059
|
+
if (nestedArray == null) {
|
|
1060
|
+
mapFrame.target.put(key, null);
|
|
1061
|
+
break;
|
|
1062
|
+
}
|
|
1063
|
+
|
|
1064
|
+
List<Object> nestedArrayOutput = new java.util.ArrayList<>();
|
|
1065
|
+
mapFrame.target.put(key, nestedArrayOutput);
|
|
1066
|
+
stack.push(new ReadableArrayBuildFrame(nestedArray, nestedArrayOutput));
|
|
1067
|
+
break;
|
|
1068
|
+
case Null:
|
|
1069
|
+
default:
|
|
1070
|
+
mapFrame.target.put(key, null);
|
|
1071
|
+
}
|
|
1072
|
+
}
|
|
1073
|
+
|
|
1074
|
+
continue;
|
|
1075
|
+
}
|
|
1076
|
+
|
|
1077
|
+
ReadableArrayBuildFrame arrayFrame = (ReadableArrayBuildFrame) frame;
|
|
1078
|
+
for (int i = 0; i < arrayFrame.source.size(); i++) {
|
|
1079
|
+
ReadableType type = arrayFrame.source.getType(i);
|
|
1080
|
+
if (type == ReadableType.Null) {
|
|
1081
|
+
arrayFrame.target.add(null);
|
|
1082
|
+
continue;
|
|
1083
|
+
}
|
|
1084
|
+
|
|
1085
|
+
switch (type) {
|
|
1086
|
+
case Boolean:
|
|
1087
|
+
arrayFrame.target.add(arrayFrame.source.getBoolean(i));
|
|
1088
|
+
break;
|
|
1089
|
+
case Number:
|
|
1090
|
+
arrayFrame.target.add(coerceNumber(arrayFrame.source.getDouble(i)));
|
|
1091
|
+
break;
|
|
1092
|
+
case String:
|
|
1093
|
+
arrayFrame.target.add(arrayFrame.source.getString(i));
|
|
1094
|
+
break;
|
|
1095
|
+
case Map:
|
|
1096
|
+
ReadableMap nestedMap = arrayFrame.source.getMap(i);
|
|
1097
|
+
if (nestedMap == null) {
|
|
1098
|
+
arrayFrame.target.add(null);
|
|
1099
|
+
break;
|
|
1100
|
+
}
|
|
1101
|
+
|
|
1102
|
+
Map<String, Object> nestedMapOutput = new HashMap<>();
|
|
1103
|
+
arrayFrame.target.add(nestedMapOutput);
|
|
1104
|
+
stack.push(new ReadableMapBuildFrame(nestedMap, nestedMapOutput));
|
|
1105
|
+
break;
|
|
1106
|
+
case Array:
|
|
1107
|
+
ReadableArray nestedArray = arrayFrame.source.getArray(i);
|
|
1108
|
+
if (nestedArray == null) {
|
|
1109
|
+
arrayFrame.target.add(null);
|
|
1110
|
+
break;
|
|
1111
|
+
}
|
|
1112
|
+
|
|
1113
|
+
List<Object> nestedArrayOutput = new java.util.ArrayList<>();
|
|
1114
|
+
arrayFrame.target.add(nestedArrayOutput);
|
|
1115
|
+
stack.push(new ReadableArrayBuildFrame(nestedArray, nestedArrayOutput));
|
|
1116
|
+
break;
|
|
1117
|
+
case Null:
|
|
1118
|
+
default:
|
|
1119
|
+
arrayFrame.target.add(null);
|
|
1120
|
+
break;
|
|
1121
|
+
}
|
|
1122
|
+
}
|
|
1123
|
+
}
|
|
1124
|
+
}
|
|
1125
|
+
|
|
1126
|
+
private Number coerceNumber(double value) {
|
|
1127
|
+
if (Math.floor(value) == value && value <= Long.MAX_VALUE && value >= Long.MIN_VALUE) {
|
|
1128
|
+
return (long) value;
|
|
1129
|
+
}
|
|
1130
|
+
return value;
|
|
1131
|
+
}
|
|
1132
|
+
|
|
1133
|
+
private String optionalString(Map<String, Object> map, String key) {
|
|
1134
|
+
if (map == null || !map.containsKey(key) || map.get(key) == null) {
|
|
1135
|
+
return null;
|
|
1136
|
+
}
|
|
1137
|
+
|
|
1138
|
+
Object value = map.get(key);
|
|
1139
|
+
if (!(value instanceof String)) {
|
|
1140
|
+
return null;
|
|
1141
|
+
}
|
|
1142
|
+
|
|
1143
|
+
return (String) value;
|
|
1144
|
+
}
|
|
1145
|
+
|
|
1146
|
+
private String requireNonEmptyString(Map<String, Object> map, String key, String fieldName)
|
|
1147
|
+
throws PipelineValidationException {
|
|
1148
|
+
validateNonEmptyString(map, key, fieldName);
|
|
1149
|
+
return (String) map.get(key);
|
|
1150
|
+
}
|
|
1151
|
+
|
|
1152
|
+
private int coerceInt(Object value, String fieldName) throws PipelineValidationException {
|
|
1153
|
+
if (!(value instanceof Number)) {
|
|
1154
|
+
throw new PipelineValidationException(
|
|
1155
|
+
"pipelineExecute() expected " + fieldName + " to be a number.");
|
|
1156
|
+
}
|
|
1157
|
+
return ((Number) value).intValue();
|
|
1158
|
+
}
|
|
1159
|
+
|
|
1160
|
+
private long coerceLong(Object value, String fieldName) throws PipelineValidationException {
|
|
1161
|
+
if (!(value instanceof Number)) {
|
|
1162
|
+
throw new PipelineValidationException(
|
|
1163
|
+
"pipelineExecute() expected " + fieldName + " to be a number.");
|
|
1164
|
+
}
|
|
1165
|
+
return ((Number) value).longValue();
|
|
1166
|
+
}
|
|
1167
|
+
|
|
1168
|
+
private double coerceDouble(Object value, String fieldName) throws PipelineValidationException {
|
|
1169
|
+
if (!(value instanceof Number)) {
|
|
1170
|
+
throw new PipelineValidationException(
|
|
1171
|
+
"pipelineExecute() expected " + fieldName + " to be a number.");
|
|
1172
|
+
}
|
|
1173
|
+
return ((Number) value).doubleValue();
|
|
1174
|
+
}
|
|
1175
|
+
|
|
1176
|
+
private List<Object> coerceList(Object value, String fieldName)
|
|
1177
|
+
throws PipelineValidationException {
|
|
1178
|
+
if (!(value instanceof List)) {
|
|
1179
|
+
throw new PipelineValidationException(
|
|
1180
|
+
"pipelineExecute() expected " + fieldName + " to be an array.");
|
|
1181
|
+
}
|
|
1182
|
+
return (List<Object>) value;
|
|
1183
|
+
}
|
|
1184
|
+
|
|
1185
|
+
private String[] coerceStringList(Object value, String fieldName)
|
|
1186
|
+
throws PipelineValidationException {
|
|
1187
|
+
List<Object> list = coerceList(value, fieldName);
|
|
1188
|
+
String[] values = new String[list.size()];
|
|
1189
|
+
for (int i = 0; i < list.size(); i++) {
|
|
1190
|
+
Object entry = list.get(i);
|
|
1191
|
+
if (!(entry instanceof String)) {
|
|
1192
|
+
throw new PipelineValidationException(
|
|
1193
|
+
"pipelineExecute() expected " + fieldName + " values to be strings.");
|
|
1194
|
+
}
|
|
1195
|
+
values[i] = (String) entry;
|
|
1196
|
+
}
|
|
1197
|
+
return values;
|
|
1198
|
+
}
|
|
1199
|
+
|
|
1200
|
+
private FindNearestStage.DistanceMeasure coerceDistanceMeasure(String value, String fieldName)
|
|
1201
|
+
throws PipelineValidationException {
|
|
1202
|
+
if (value == null) {
|
|
1203
|
+
throw new PipelineValidationException(
|
|
1204
|
+
"pipelineExecute() expected " + fieldName + " to be provided.");
|
|
1205
|
+
}
|
|
1206
|
+
|
|
1207
|
+
String normalized = value.trim().replace('-', '_').replace(' ', '_').toUpperCase(Locale.ROOT);
|
|
1208
|
+
if ("COSINE".equals(normalized)) {
|
|
1209
|
+
return FindNearestStage.DistanceMeasure.COSINE;
|
|
1210
|
+
}
|
|
1211
|
+
if ("EUCLIDEAN".equals(normalized)) {
|
|
1212
|
+
return FindNearestStage.DistanceMeasure.EUCLIDEAN;
|
|
1213
|
+
}
|
|
1214
|
+
if ("DOT_PRODUCT".equals(normalized) || "DOTPRODUCT".equals(normalized)) {
|
|
1215
|
+
return FindNearestStage.DistanceMeasure.DOT_PRODUCT;
|
|
1216
|
+
}
|
|
1217
|
+
|
|
1218
|
+
throw new PipelineValidationException(
|
|
1219
|
+
"pipelineExecute() expected "
|
|
1220
|
+
+ fieldName
|
|
1221
|
+
+ " to be one of COSINE, EUCLIDEAN, DOT_PRODUCT.");
|
|
1222
|
+
}
|
|
1223
|
+
|
|
1224
|
+
private void validateNonEmptyString(Map<String, Object> map, String key, String fieldName)
|
|
1225
|
+
throws PipelineValidationException {
|
|
1226
|
+
if (map == null || !map.containsKey(key) || !(map.get(key) instanceof String)) {
|
|
1227
|
+
throw new PipelineValidationException(
|
|
1228
|
+
"pipelineExecute() expected " + fieldName + " to be a string.");
|
|
1229
|
+
}
|
|
1230
|
+
|
|
1231
|
+
String value = (String) map.get(key);
|
|
1232
|
+
if (value == null || value.isEmpty()) {
|
|
1233
|
+
throw new PipelineValidationException(
|
|
1234
|
+
"pipelineExecute() expected " + fieldName + " to be a non-empty string.");
|
|
1235
|
+
}
|
|
1236
|
+
}
|
|
1237
|
+
|
|
1238
|
+
static class PipelineValidationException extends Exception {
|
|
1239
|
+
PipelineValidationException(String message) {
|
|
1240
|
+
super(message);
|
|
1241
|
+
}
|
|
1242
|
+
}
|
|
1243
|
+
}
|