Skip to content

Commit 2b7b65e

Browse files
CDRIVER-4277: Pre-point-in-time support (#1016)
- Support NULLable strings in generate-opts: - If an option is given a "None" default value, it's C value will be NULL. - Updates the `fullDocument` as well as add the `fullDocumentBeforeChange` option. - Forward the `fullDocumentBeforeChange` option through changestream options. - Enable the pre_and_post_images tests.
1 parent 584eaca commit 2b7b65e

File tree

8 files changed

+44
-9
lines changed

8 files changed

+44
-9
lines changed

build/generate-opts.py

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1414
# See the License for the specific language governing permissions and
1515
# limitations under the License.
16-
1716
"""IDL for functions that take flexible options as a bson_t.
1817
1918
Defines the options accepted by functions that receive a const bson_t *opts,
@@ -25,6 +24,7 @@
2524
Written for Python 2.6+, requires Jinja 2 for templating.
2625
"""
2726

27+
# yapf: disable
2828
from collections import OrderedDict
2929
from os.path import basename, dirname, join as joinpath, normpath
3030
import re
@@ -292,9 +292,25 @@ def __init__(self, items, **defaults):
292292
('startAfter', {'type': 'document', 'help': 'A ``Document`` representing the logical starting point of the change stream. Unlike ``resumeAfter``, this can resume notifications after an "invalidate" event. The result of :symbol:`mongoc_change_stream_get_resume_token()` or the ``_id`` field of any change received from a change stream can be used here. This option is mutually exclusive with ``resumeAfter`` and ``startAtOperationTime``.'}),
293293
('startAtOperationTime', {'type': 'timestamp', 'help': 'A ``Timestamp``. The change stream only provides changes that occurred at or after the specified timestamp. Any command run against the server will return an operation time that can be used here. This option is mutually exclusive with ``resumeAfter`` and ``startAfter``.'}),
294294
('maxAwaitTimeMS', {'type': 'int64_t', 'convert': '_mongoc_convert_int64_positive', 'help': 'An ``int64`` representing the maximum amount of time a call to :symbol:`mongoc_change_stream_next` will block waiting for data'}),
295-
('fullDocument', {'type': 'utf8', 'help': 'A UTF-8 string. Set this option to "updateLookup" to direct the change stream cursor to lookup the most current majority-committed version of the document associated to an update change stream event.'}),
295+
('fullDocument', {
296+
'type': 'utf8',
297+
'help': 'An optional UTF-8 string. Set this option to "default", '
298+
'"updateLookup", "whenAvailable", or "required", If unset, '
299+
'The string "default" is assumed. Set this option to '
300+
'"updateLookup" to direct the change stream cursor to '
301+
'lookup the most current majority-committed version of the '
302+
'document associated to an update change stream event.'
303+
}),
304+
('fullDocumentBeforeChange', {
305+
'type': 'utf8',
306+
'help': 'An optional UTF-8 string. Set this option to '
307+
'"whenAvailable", "required", or "off". When unset, the '
308+
'default value is "off". Similar to "fullDocument", but '
309+
'returns the value of the document before the associated '
310+
'change.',
311+
}),
296312
comment_option_string_pre_4_4,
297-
], fullDocument="default")),
313+
], fullDocument=None, fullDocumentBeforeChange=None)),
298314

299315
('mongoc_create_index_opts_t', Struct([
300316
write_concern_option,

build/opts_templates/mongoc-opts.c.template

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@ _{{ struct_name }}_parse (
3434
{% elif info['type'] in ('document', 'array') %}
3535
bson_init (&{{ struct_name }}->{{ path }});
3636
{% elif info['type'] == 'utf8' %}
37-
{{ struct_name }}->{{ path }} = "{{ description.default(opt_name, "")}}";
37+
{% set dflt = description.default(opt_name, "") -%}
38+
{{ struct_name }}->{{ path }} = {{ "NULL" if dflt is none else (dflt|tojson) }};
3839
{% elif info['type'] == 'timestamp' %}
3940
memset (&{{ struct_name }}->{{ path }}, 0, sizeof (mongoc_timestamp_t));
4041
{% else %}

src/libmongoc/doc/includes/change-stream-opts.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,6 @@
1010
* ``startAfter``: A ``Document`` representing the logical starting point of the change stream. Unlike ``resumeAfter``, this can resume notifications after an "invalidate" event. The result of :symbol:`mongoc_change_stream_get_resume_token()` or the ``_id`` field of any change received from a change stream can be used here. This option is mutually exclusive with ``resumeAfter`` and ``startAtOperationTime``.
1111
* ``startAtOperationTime``: A ``Timestamp``. The change stream only provides changes that occurred at or after the specified timestamp. Any command run against the server will return an operation time that can be used here. This option is mutually exclusive with ``resumeAfter`` and ``startAfter``.
1212
* ``maxAwaitTimeMS``: An ``int64`` representing the maximum amount of time a call to :symbol:`mongoc_change_stream_next` will block waiting for data
13-
* ``fullDocument``: A UTF-8 string. Set this option to "updateLookup" to direct the change stream cursor to lookup the most current majority-committed version of the document associated to an update change stream event.
13+
* ``fullDocument``: An optional UTF-8 string. Set this option to "default", "updateLookup", "whenAvailable", or "required", If unset, The string "default" is assumed. Set this option to "updateLookup" to direct the change stream cursor to lookup the most current majority-committed version of the document associated to an update change stream event.
14+
* ``fullDocumentBeforeChange``: An optional UTF-8 string. Set this option to "whenAvailable", "required", or "off". When unset, the default value is "off". Similar to "fullDocument", but returns the value of the document before the associated change.
1415
* ``comment``: A :symbol:`bson_value_t` specifying the comment to attach to this command. The comment will appear in log messages, profiler output, and currentOp output. Only string values are supported prior to MongoDB 4.4.

src/libmongoc/src/mongoc/mongoc-change-stream-private.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ struct _mongoc_change_stream_t {
3838
bson_t pipeline_to_append;
3939
bson_t resume_token;
4040
bson_t *full_document;
41+
bson_t *full_document_before_change;
4142

4243
bson_error_t err;
4344
bson_t err_doc;

src/libmongoc/src/mongoc/mongoc-change-stream.c

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,9 @@ _make_command (mongoc_change_stream_t *stream, bson_t *command)
126126
if (stream->full_document) {
127127
bson_concat (&change_stream_doc, stream->full_document);
128128
}
129+
if (stream->full_document_before_change) {
130+
bson_concat (&change_stream_doc, stream->full_document_before_change);
131+
}
129132

130133
if (stream->resumed) {
131134
/* Change stream spec: Resume Process */
@@ -418,8 +421,11 @@ _change_stream_init (mongoc_change_stream_t *stream,
418421
if (stream->opts.fullDocument) {
419422
stream->full_document =
420423
BCON_NEW ("fullDocument", stream->opts.fullDocument);
421-
} else {
422-
stream->full_document = NULL;
424+
}
425+
426+
if (stream->opts.fullDocumentBeforeChange) {
427+
stream->full_document_before_change = BCON_NEW (
428+
"fullDocumentBeforeChange", stream->opts.fullDocumentBeforeChange);
423429
}
424430

425431
_mongoc_timestamp_set (&stream->operation_time,
@@ -668,6 +674,7 @@ mongoc_change_stream_destroy (mongoc_change_stream_t *stream)
668674
bson_destroy (&stream->pipeline_to_append);
669675
bson_destroy (&stream->resume_token);
670676
bson_destroy (stream->full_document);
677+
bson_destroy (stream->full_document_before_change);
671678
bson_destroy (&stream->err_doc);
672679
_mongoc_change_stream_opts_cleanup (&stream->opts);
673680
mongoc_cursor_destroy (stream->cursor);

src/libmongoc/src/mongoc/mongoc-opts-private.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ typedef struct _mongoc_change_stream_opts_t {
145145
mongoc_timestamp_t startAtOperationTime;
146146
int64_t maxAwaitTimeMS;
147147
const char *fullDocument;
148+
const char *fullDocumentBeforeChange;
148149
bson_value_t comment;
149150
bson_t extra;
150151
} mongoc_change_stream_opts_t;

src/libmongoc/src/mongoc/mongoc-opts.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1582,6 +1582,7 @@ _mongoc_change_stream_opts_parse (
15821582
memset (&mongoc_change_stream_opts->startAtOperationTime, 0, sizeof (mongoc_timestamp_t));
15831583
mongoc_change_stream_opts->maxAwaitTimeMS = 0;
15841584
mongoc_change_stream_opts->fullDocument = NULL;
1585+
mongoc_change_stream_opts->fullDocumentBeforeChange = NULL;
15851586
memset (&mongoc_change_stream_opts->comment, 0, sizeof (bson_value_t));
15861587
bson_init (&mongoc_change_stream_opts->extra);
15871588

@@ -1652,6 +1653,15 @@ _mongoc_change_stream_opts_parse (
16521653
return false;
16531654
}
16541655
}
1656+
else if (!strcmp (bson_iter_key (&iter), "fullDocumentBeforeChange")) {
1657+
if (!_mongoc_convert_utf8 (
1658+
client,
1659+
&iter,
1660+
&mongoc_change_stream_opts->fullDocumentBeforeChange,
1661+
error)) {
1662+
return false;
1663+
}
1664+
}
16551665
else if (!strcmp (bson_iter_key (&iter), "comment")) {
16561666
if (!_mongoc_convert_bson_value_t (
16571667
client,

src/libmongoc/tests/unified/runner.c

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,6 @@ skipped_unified_test_t SKIPPED_TESTS[] = {
7979
{"cursors are correctly pinned to connections for load-balanced clusters", "listIndexes pins the cursor to a connection"},
8080
/* libmongoc does not pin connections to cursors. It cannot force an error from waitQueueTimeoutMS by creating cursors in load balanced mode. */
8181
{"wait queue timeout errors include details about checked out connections", SKIP_ALL_TESTS},
82-
/* CDRIVER-4277: Change streams support for user-facing PIT pre- and post-images */
83-
{"change-streams-pre_and_post_images", SKIP_ALL_TESTS},
8482
{0},
8583
};
8684
/* clang-format on */

0 commit comments

Comments
 (0)