/*--------------------------------------------------------------------------- * * _change_stream_init -- * * Called after @stream has the collection name, database name, read * preferences, and read concern set. Creates the change streams * cursor. * *-------------------------------------------------------------------------- */ void _change_stream_init (mongoc_change_stream_t *stream, const bson_t *pipeline, const bson_t *opts) { BSON_ASSERT (pipeline); stream->max_await_time_ms = -1; stream->batch_size = -1; bson_init (&stream->pipeline_to_append); bson_init (&stream->resume_token); bson_init (&stream->err_doc); if (!_mongoc_change_stream_opts_parse ( stream->client, opts, &stream->opts, &stream->err)) { return; } stream->full_document = BCON_NEW ("fullDocument", stream->opts.fullDocument); if (!bson_empty (&(stream->opts.resumeAfter))) { bson_append_document ( &stream->resume_token, "resumeAfter", 11, &(stream->opts.resumeAfter)); } _mongoc_timestamp_set (&stream->operation_time, &(stream->opts.startAtOperationTime)); stream->batch_size = stream->opts.batchSize; stream->max_await_time_ms = stream->opts.maxAwaitTimeMS; /* Accept two forms of user pipeline: * 1. A document like: { "pipeline": [...] } * 2. An array-like document: { "0": {}, "1": {}, ... } * If the passed pipeline is invalid, we pass it along and let the server * error instead. */ if (!bson_empty (pipeline)) { bson_iter_t iter; if (bson_iter_init_find (&iter, pipeline, "pipeline") && BSON_ITER_HOLDS_ARRAY (&iter)) { if (!BSON_APPEND_VALUE (&stream->pipeline_to_append, "pipeline", bson_iter_value (&iter))) { CHANGE_STREAM_ERR ("pipeline"); } } else { if (!BSON_APPEND_ARRAY ( &stream->pipeline_to_append, "pipeline", pipeline)) { CHANGE_STREAM_ERR ("pipeline"); } } } if (stream->err.code == 0) { (void) _make_cursor (stream); } }
mongoc_change_stream_t * _mongoc_change_stream_new (const mongoc_collection_t *coll, const bson_t *pipeline, const bson_t *opts) { bool full_doc_set = false; mongoc_change_stream_t *stream = (mongoc_change_stream_t *) bson_malloc0 (sizeof (mongoc_change_stream_t)); BSON_ASSERT (coll); BSON_ASSERT (pipeline); stream->max_await_time_ms = -1; stream->batch_size = -1; stream->coll = mongoc_collection_copy ((mongoc_collection_t *) coll); bson_init (&stream->pipeline_to_append); bson_init (&stream->full_document); bson_init (&stream->opts); bson_init (&stream->resume_token); bson_init (&stream->err_doc); /* * The passed options may consist of: * fullDocument: 'default'|'updateLookup', passed to $changeStream stage * resumeAfter: optional<Doc>, passed to $changeStream stage * maxAwaitTimeMS: Optional<Int64>, set on the cursor * batchSize: Optional<Int32>, passed as agg option, {cursor: { batchSize: }} * standard command options like "sessionId", "maxTimeMS", or "collation" */ if (opts) { bson_iter_t iter; if (bson_iter_init_find (&iter, opts, "fullDocument")) { SET_BSON_OR_ERR (&stream->full_document, "fullDocument"); full_doc_set = true; } if (bson_iter_init_find (&iter, opts, "resumeAfter")) { SET_BSON_OR_ERR (&stream->resume_token, "resumeAfter"); } if (bson_iter_init_find (&iter, opts, "batchSize")) { if (BSON_ITER_HOLDS_INT32 (&iter)) { stream->batch_size = bson_iter_int32 (&iter); } } if (bson_iter_init_find (&iter, opts, "maxAwaitTimeMS") && BSON_ITER_HOLDS_INT (&iter)) { stream->max_await_time_ms = bson_iter_as_int64 (&iter); } /* save the remaining opts for mongoc_collection_read_command_with_opts */ bson_copy_to_excluding_noinit (opts, &stream->opts, "fullDocument", "resumeAfter", "batchSize", "maxAwaitTimeMS", NULL); } if (!full_doc_set) { if (!BSON_APPEND_UTF8 ( &stream->full_document, "fullDocument", "default")) { CHANGE_STREAM_ERR ("fullDocument"); } } /* Accept two forms of user pipeline: * 1. A document like: { "pipeline": [...] } * 2. An array-like document: { "0": {}, "1": {}, ... } * If the passed pipeline is invalid, we pass it along and let the server * error instead. */ if (!bson_empty (pipeline)) { bson_iter_t iter; if (bson_iter_init_find (&iter, pipeline, "pipeline") && BSON_ITER_HOLDS_ARRAY (&iter)) { SET_BSON_OR_ERR (&stream->pipeline_to_append, "pipeline"); } else { if (!BSON_APPEND_ARRAY ( &stream->pipeline_to_append, "pipeline", pipeline)) { CHANGE_STREAM_ERR ("pipeline"); } } } if (stream->err.code == 0) { (void) _make_cursor (stream); } return stream; }