Skip to content

Commit 7c6d456

Browse files
committed
BulkWriteCommand update methods
1 parent b6fcb3b commit 7c6d456

File tree

1 file changed

+312
-9
lines changed

1 file changed

+312
-9
lines changed

src/MongoDB/BulkWriteCommand.c

+312-9
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,35 @@ static void php_phongo_bulkwritecommand_extract_id(bson_t* doc, zval** return_va
6161
zval_ptr_dtor(&state.zchild);
6262
}
6363

64+
// TODO: Make this a common utility function to share with BulkWrite.c
65+
/* Returns whether the BSON array's keys are a sequence of integer strings
66+
* starting with "0". */
67+
static inline bool phongo_bulkwrite_bson_array_has_valid_keys(bson_t* array)
68+
{
69+
bson_iter_t iter;
70+
71+
if (bson_empty(array)) {
72+
return true;
73+
}
74+
75+
if (bson_iter_init(&iter, array)) {
76+
char key[12];
77+
int count = 0;
78+
79+
while (bson_iter_next(&iter)) {
80+
bson_snprintf(key, sizeof(key), "%d", count);
81+
82+
if (0 != strcmp(key, bson_iter_key(&iter))) {
83+
return false;
84+
}
85+
86+
count++;
87+
}
88+
}
89+
90+
return true;
91+
}
92+
6493
/* Constructs a new BulkWrite */
6594
static PHP_METHOD(MongoDB_Driver_BulkWriteCommand, __construct)
6695
{
@@ -176,6 +205,28 @@ static bool phongo_bwc_parse_document(zval* zdocument, bson_t* bdocument, const
176205
return true;
177206
}
178207

208+
static bool phongo_bwc_parse_array(zval* zarray, bson_t* barray, const char* key)
209+
{
210+
if (Z_TYPE_P(zarray) != IS_OBJECT && Z_TYPE_P(zarray) != IS_ARRAY) {
211+
phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Expected \"%s\" option to be array or object, %s given", key, zend_get_type_by_const(Z_TYPE_P(zarray)));
212+
return false;
213+
}
214+
215+
// Explicitly allow MongoDB\BSON\PackedArray for array values
216+
php_phongo_zval_to_bson(zarray, PHONGO_BSON_ALLOW_ROOT_ARRAY, barray, NULL);
217+
218+
if (EG(exception)) {
219+
return false;
220+
}
221+
222+
if (!phongo_bulkwrite_bson_array_has_valid_keys(barray)) {
223+
phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Expected \"%s\" option to yield array but got non-sequential keys", key);
224+
return false;
225+
}
226+
227+
return true;
228+
}
229+
179230
static PHP_METHOD(MongoDB_Driver_BulkWriteCommand, deleteMany)
180231
{
181232
php_phongo_bulkwritecommand_t* intern;
@@ -378,32 +429,284 @@ static PHP_METHOD(MongoDB_Driver_BulkWriteCommand, insertOne)
378429

379430
static PHP_METHOD(MongoDB_Driver_BulkWriteCommand, replaceOne)
380431
{
381-
php_phongo_bulkwritecommand_t* intern;
432+
php_phongo_bulkwritecommand_t* intern;
433+
char* ns;
434+
size_t ns_len;
435+
zval* zfilter;
436+
zval* zupdate;
437+
zval* zoptions = NULL;
438+
bson_t bfilter = BSON_INITIALIZER;
439+
bson_t bupdate = BSON_INITIALIZER;
440+
mongoc_bulkwrite_replaceoneopts_t* opts = NULL;
441+
bson_error_t error = { 0 };
382442

383443
intern = Z_BULKWRITECOMMAND_OBJ_P(getThis());
384444

385-
// TODO: implementation
386-
PHONGO_PARSE_PARAMETERS_NONE();
445+
PHONGO_PARSE_PARAMETERS_START(3, 4)
446+
Z_PARAM_STRING(ns, ns_len)
447+
Z_PARAM_ARRAY_OR_OBJECT(zfilter)
448+
Z_PARAM_ARRAY_OR_OBJECT(zupdate)
449+
Z_PARAM_OPTIONAL
450+
Z_PARAM_ARRAY_OR_NULL(zoptions)
451+
PHONGO_PARSE_PARAMETERS_END();
452+
453+
if (strlen(ns) != ns_len) {
454+
phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Namespace string should not contain null bytes");
455+
return;
456+
}
457+
458+
php_phongo_zval_to_bson(zfilter, PHONGO_BSON_NONE, &bfilter, NULL);
459+
460+
if (EG(exception)) {
461+
goto cleanup;
462+
}
463+
464+
// Explicitly allow MongoDB\BSON\PackedArray for update pipelines
465+
php_phongo_zval_to_bson(zupdate, PHONGO_BSON_ALLOW_ROOT_ARRAY, &bupdate, NULL);
466+
467+
if (EG(exception)) {
468+
goto cleanup;
469+
}
470+
471+
if (zoptions) {
472+
opts = mongoc_bulkwrite_replaceoneopts_new();
473+
474+
if (php_array_existsc(zoptions, "collation")) {
475+
bson_t bcollation = BSON_INITIALIZER;
476+
477+
if (!phongo_bwc_parse_document(php_array_fetchc_deref(zoptions, "collation"), &bcollation, "collation")) {
478+
bson_destroy(&bcollation);
479+
goto cleanup;
480+
}
481+
482+
mongoc_bulkwrite_replaceoneopts_set_collation(opts, &bcollation);
483+
bson_destroy(&bcollation);
484+
}
485+
486+
if (php_array_existsc(zoptions, "hint")) {
487+
bson_value_t bhint = { 0 };
488+
489+
if (!phongo_bwc_parse_hint(php_array_fetchc_deref(zoptions, "hint"), &bhint)) {
490+
bson_value_destroy(&bhint);
491+
goto cleanup;
492+
}
493+
494+
mongoc_bulkwrite_replaceoneopts_set_hint(opts, &bhint);
495+
bson_value_destroy(&bhint);
496+
}
497+
498+
if (php_array_existsc(zoptions, "upsert")) {
499+
mongoc_bulkwrite_replaceoneopts_set_upsert(opts, php_array_fetchc_bool(zoptions, "upsert"));
500+
}
501+
}
502+
503+
if (!mongoc_bulkwrite_append_replaceone(intern->bw, ns, &bfilter, &bupdate, opts, &error)) {
504+
phongo_throw_exception_from_bson_error_t(&error);
505+
goto cleanup;
506+
}
507+
508+
intern->num_ops++;
509+
510+
cleanup:
511+
bson_destroy(&bfilter);
512+
bson_destroy(&bupdate);
513+
mongoc_bulkwrite_replaceoneopts_destroy(opts);
387514
}
388515

389516
static PHP_METHOD(MongoDB_Driver_BulkWriteCommand, updateMany)
390517
{
391-
php_phongo_bulkwritecommand_t* intern;
518+
php_phongo_bulkwritecommand_t* intern;
519+
char* ns;
520+
size_t ns_len;
521+
zval* zfilter;
522+
zval* zupdate;
523+
zval* zoptions = NULL;
524+
bson_t bfilter = BSON_INITIALIZER;
525+
bson_t bupdate = BSON_INITIALIZER;
526+
mongoc_bulkwrite_updatemanyopts_t* opts = NULL;
527+
bson_error_t error = { 0 };
392528

393529
intern = Z_BULKWRITECOMMAND_OBJ_P(getThis());
394530

395-
// TODO: implementation
396-
PHONGO_PARSE_PARAMETERS_NONE();
531+
PHONGO_PARSE_PARAMETERS_START(3, 4)
532+
Z_PARAM_STRING(ns, ns_len)
533+
Z_PARAM_ARRAY_OR_OBJECT(zfilter)
534+
Z_PARAM_ARRAY_OR_OBJECT(zupdate)
535+
Z_PARAM_OPTIONAL
536+
Z_PARAM_ARRAY_OR_NULL(zoptions)
537+
PHONGO_PARSE_PARAMETERS_END();
538+
539+
if (strlen(ns) != ns_len) {
540+
phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Namespace string should not contain null bytes");
541+
return;
542+
}
543+
544+
php_phongo_zval_to_bson(zfilter, PHONGO_BSON_NONE, &bfilter, NULL);
545+
546+
if (EG(exception)) {
547+
goto cleanup;
548+
}
549+
550+
// Explicitly allow MongoDB\BSON\PackedArray for update pipelines
551+
php_phongo_zval_to_bson(zupdate, PHONGO_BSON_ALLOW_ROOT_ARRAY, &bupdate, NULL);
552+
553+
if (EG(exception)) {
554+
goto cleanup;
555+
}
556+
557+
if (zoptions) {
558+
opts = mongoc_bulkwrite_updatemanyopts_new();
559+
560+
if (php_array_existsc(zoptions, "arrayFilters")) {
561+
bson_t barrayfilters = BSON_INITIALIZER;
562+
563+
if (!phongo_bwc_parse_array(php_array_fetchc_deref(zoptions, "arrayFilters"), &barrayfilters, "arrayFilters")) {
564+
bson_destroy(&barrayfilters);
565+
goto cleanup;
566+
}
567+
568+
mongoc_bulkwrite_updatemanyopts_set_arrayfilters(opts, &barrayfilters);
569+
bson_destroy(&barrayfilters);
570+
}
571+
572+
if (php_array_existsc(zoptions, "collation")) {
573+
bson_t bcollation = BSON_INITIALIZER;
574+
575+
if (!phongo_bwc_parse_document(php_array_fetchc_deref(zoptions, "collation"), &bcollation, "collation")) {
576+
bson_destroy(&bcollation);
577+
goto cleanup;
578+
}
579+
580+
mongoc_bulkwrite_updatemanyopts_set_collation(opts, &bcollation);
581+
bson_destroy(&bcollation);
582+
}
583+
584+
if (php_array_existsc(zoptions, "hint")) {
585+
bson_value_t bhint = { 0 };
586+
587+
if (!phongo_bwc_parse_hint(php_array_fetchc_deref(zoptions, "hint"), &bhint)) {
588+
bson_value_destroy(&bhint);
589+
goto cleanup;
590+
}
591+
592+
mongoc_bulkwrite_updatemanyopts_set_hint(opts, &bhint);
593+
bson_value_destroy(&bhint);
594+
}
595+
596+
if (php_array_existsc(zoptions, "upsert")) {
597+
mongoc_bulkwrite_updatemanyopts_set_upsert(opts, php_array_fetchc_bool(zoptions, "upsert"));
598+
}
599+
}
600+
601+
if (!mongoc_bulkwrite_append_updatemany(intern->bw, ns, &bfilter, &bupdate, opts, &error)) {
602+
phongo_throw_exception_from_bson_error_t(&error);
603+
goto cleanup;
604+
}
605+
606+
intern->num_ops++;
607+
608+
cleanup:
609+
bson_destroy(&bfilter);
610+
bson_destroy(&bupdate);
611+
mongoc_bulkwrite_updatemanyopts_destroy(opts);
397612
}
398613

399614
static PHP_METHOD(MongoDB_Driver_BulkWriteCommand, updateOne)
400615
{
401-
php_phongo_bulkwritecommand_t* intern;
616+
php_phongo_bulkwritecommand_t* intern;
617+
char* ns;
618+
size_t ns_len;
619+
zval* zfilter;
620+
zval* zupdate;
621+
zval* zoptions = NULL;
622+
bson_t bfilter = BSON_INITIALIZER;
623+
bson_t bupdate = BSON_INITIALIZER;
624+
mongoc_bulkwrite_updateoneopts_t* opts = NULL;
625+
bson_error_t error = { 0 };
402626

403627
intern = Z_BULKWRITECOMMAND_OBJ_P(getThis());
404628

405-
// TODO: implementation
406-
PHONGO_PARSE_PARAMETERS_NONE();
629+
PHONGO_PARSE_PARAMETERS_START(3, 4)
630+
Z_PARAM_STRING(ns, ns_len)
631+
Z_PARAM_ARRAY_OR_OBJECT(zfilter)
632+
Z_PARAM_ARRAY_OR_OBJECT(zupdate)
633+
Z_PARAM_OPTIONAL
634+
Z_PARAM_ARRAY_OR_NULL(zoptions)
635+
PHONGO_PARSE_PARAMETERS_END();
636+
637+
if (strlen(ns) != ns_len) {
638+
phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Namespace string should not contain null bytes");
639+
return;
640+
}
641+
642+
php_phongo_zval_to_bson(zfilter, PHONGO_BSON_NONE, &bfilter, NULL);
643+
644+
if (EG(exception)) {
645+
goto cleanup;
646+
}
647+
648+
// Explicitly allow MongoDB\BSON\PackedArray for update pipelines
649+
php_phongo_zval_to_bson(zupdate, PHONGO_BSON_ALLOW_ROOT_ARRAY, &bupdate, NULL);
650+
651+
if (EG(exception)) {
652+
goto cleanup;
653+
}
654+
655+
if (zoptions) {
656+
opts = mongoc_bulkwrite_updateoneopts_new();
657+
658+
if (php_array_existsc(zoptions, "arrayFilters")) {
659+
bson_t barrayfilters = BSON_INITIALIZER;
660+
661+
if (!phongo_bwc_parse_array(php_array_fetchc_deref(zoptions, "arrayFilters"), &barrayfilters, "arrayFilters")) {
662+
bson_destroy(&barrayfilters);
663+
goto cleanup;
664+
}
665+
666+
mongoc_bulkwrite_updateoneopts_set_arrayfilters(opts, &barrayfilters);
667+
bson_destroy(&barrayfilters);
668+
}
669+
670+
if (php_array_existsc(zoptions, "collation")) {
671+
bson_t bcollation = BSON_INITIALIZER;
672+
673+
if (!phongo_bwc_parse_document(php_array_fetchc_deref(zoptions, "collation"), &bcollation, "collation")) {
674+
bson_destroy(&bcollation);
675+
goto cleanup;
676+
}
677+
678+
mongoc_bulkwrite_updateoneopts_set_collation(opts, &bcollation);
679+
bson_destroy(&bcollation);
680+
}
681+
682+
if (php_array_existsc(zoptions, "hint")) {
683+
bson_value_t bhint = { 0 };
684+
685+
if (!phongo_bwc_parse_hint(php_array_fetchc_deref(zoptions, "hint"), &bhint)) {
686+
bson_value_destroy(&bhint);
687+
goto cleanup;
688+
}
689+
690+
mongoc_bulkwrite_updateoneopts_set_hint(opts, &bhint);
691+
bson_value_destroy(&bhint);
692+
}
693+
694+
if (php_array_existsc(zoptions, "upsert")) {
695+
mongoc_bulkwrite_updateoneopts_set_upsert(opts, php_array_fetchc_bool(zoptions, "upsert"));
696+
}
697+
}
698+
699+
if (!mongoc_bulkwrite_append_updateone(intern->bw, ns, &bfilter, &bupdate, opts, &error)) {
700+
phongo_throw_exception_from_bson_error_t(&error);
701+
goto cleanup;
702+
}
703+
704+
intern->num_ops++;
705+
706+
cleanup:
707+
bson_destroy(&bfilter);
708+
bson_destroy(&bupdate);
709+
mongoc_bulkwrite_updateoneopts_destroy(opts);
407710
}
408711

409712
/* MongoDB\Driver\BulkWriteCommand object handlers */

0 commit comments

Comments
 (0)