-
Notifications
You must be signed in to change notification settings - Fork 208
PHPC-314: Implement type map syntax for documents within field paths #793
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
PHPC-314: Implement type map syntax for documents within field paths #793
Conversation
625d3c4
to
67328be
Compare
parent::__construct($data); | ||
} | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like this was always dead code. Correct?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes.
var_dump(is_array($documents[0]->array)); | ||
var_dump($documents[0]->object instanceof MyArrayObject); | ||
var_dump(is_array($documents[0]->object['string'])); | ||
var_dump(is_array($documents[0]->object->string)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't this more of a test of ArrayObject::ARRAY_AS_PROPS
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See above.
$document2 = [ | ||
'_id' => 2, | ||
'array' => [4, 5, 6], | ||
'object' => ['associative' => ['elementen', 'elements' ]] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I understand correctly, this test is verifying that the Cursor's type map can be overridden and that the default behavior applies if a field path does not match. I think it'd be clearer to use names like "array1" and "array2" instead of "string" and "associative" for these BSON arrays, though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This test was originally to see if we could set the typemap twice without leaking or memory issues.
But I added a functional bit to test that a bit better, and might ended up having just a test for PROPS_AS_ARRAY. Because of the memory issue/doubble setting, I would like to keep it though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm still not sure how ARRAY_AS_PROPS
relates to the double setting of a type map, but no objections if you'd like to keep this in place.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It doesn't — ARRAY_AS_PROPS
was just added to make the asserts a little easier to write.
tests/bson/typemap-004.phpt
Outdated
} | ||
|
||
$documents = $cursor->toArray(); | ||
return $documents; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suppose these lines can be consolidated into return $cursor->toArray()
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, will fix that. I probably had a debug statement in between at some point.... which might still be useful in case an IDE is used though?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't follow the relation to an IDE. If you're referring to an IDE indicating the type information for a $documents
variable on these two lines, I don't think that's useful.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, if there is no variable, an IDE can't inspect its contents, as it can't see the direct return values of a function.
$documents = fetch($manager); | ||
var_dump($documents[0] instanceof stdClass); | ||
var_dump(is_array($documents[0]->array0)); | ||
var_dump(is_object($documents[0]->array1)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems redundant in light of the instanceof
assertion that follows.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps, but I'm just being thorough.
src/bson.c
Outdated
if (map->field_paths.allocated < map->field_paths.size + 1) { | ||
map->field_paths.allocated += PHONGO_FIELD_PATH_EXPANSION; | ||
map->field_paths.map = erealloc(map->field_paths.map, sizeof(php_phongo_field_path_map_element) * map->field_paths.allocated); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we have an "ensure" function for this, or is this really the only place we need to increase allocation?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's the only place, and we always add to the end. Which is not the case when we build the current conversion field path for error messages and mapping, as there we leave nested sections as often as we go into them. I'll add a comment.
{ | ||
php_phongo_field_path_map_element* tmp = ecalloc(1, sizeof(php_phongo_field_path_map_element)); | ||
|
||
tmp->entry = php_phongo_field_path_alloc(true); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In this case, the element names should always be estrdup()
-ed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, and they will be through https://github.com/mongodb/mongo-php-driver/pull/793/files#diff-f7d29a680148f52d6601f59ed787f577R139 if true
is used.
src/bson.c
Outdated
return tmp; | ||
} | ||
|
||
bool php_phongo_bson_state_add_field_path(php_phongo_bson_typemap* map, char* field_path_original, php_phongo_bson_typemap_types type, zend_class_entry* ce TSRMLS_DC) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If field_path_map_element_set_info()
doesn't need TSRMLS_DC
, does this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doesn't look like it, will remove it.
src/bson.c
Outdated
|
||
/* Loop over all the segments. A segment is delimited by a "." */ | ||
element = php_strtok_r(field_path_str, ".", &saveptr); | ||
while (element) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a case where we don't enter the while
loop on the first iteration?
It may be good to have error tests for field paths such as "..."
, ".foo"
, and ""
so we can test how that is handled.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we won't ever enter, but I will add test cases. I know that strtok
handles ...
as .
for example.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sigh, strtok_r is pretty useless, as it can't handle empty elements (like in foo..bar
), so I've had to write this, which also means that we needed to keep some TSRMLS_[DC]C
things around.
return false; | ||
} | ||
|
||
if (!php_phongo_bson_state_add_field_path(map, ZSTR_VAL(string_key), map_type, map_ce TSRMLS_CC)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
php_phongo_bson_state_add_field_path()
always returns true. In the event a failure case is introduced, I suppose we'll want to ensure it throws an exception. Correct?
Is that why you're preemptively passing in TSRMLS_CC
here (consistency with php_phongo_bson_state_parse_type()
)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd wish to say that I added TSRMLS_CC
because of that, but that's not true :-) But yes, perhaps we should leave it as long as the strtok loop can create failure notifications with the three cases that you suggested.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Aye, let's revisit this if you decide to add exceptions for tokenization errors.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Which I've now just done :-).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've updated the PR with changes related to your comments - except for the ones that you didn't comment on after my first reply.
src/bson.c
Outdated
field_path->elements = erealloc(field_path->elements, sizeof(char**) * field_path->allocated_levels); | ||
field_path->allocated = field_path->size + PHONGO_FIELD_PATH_EXPANSION; | ||
field_path->elements = erealloc(field_path->elements, sizeof(char**) * field_path->allocated); | ||
field_path->element_types = erealloc(field_path->element_types, sizeof(php_phongo_bson_field_path_item_types*) * field_path->allocated); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[Narrator: It did]
src/bson.c
Outdated
|
||
/* Loop over all the segments. A segment is delimited by a "." */ | ||
element = php_strtok_r(field_path_str, ".", &saveptr); | ||
while (element) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sigh, strtok_r is pretty useless, as it can't handle empty elements (like in foo..bar
), so I've had to write this, which also means that we needed to keep some TSRMLS_[DC]C
things around.
return false; | ||
} | ||
|
||
if (!php_phongo_bson_state_add_field_path(map, ZSTR_VAL(string_key), map_type, map_ce TSRMLS_CC)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Which I've now just done :-).
$document2 = [ | ||
'_id' => 2, | ||
'array' => [4, 5, 6], | ||
'object' => ['associative' => ['elementen', 'elements' ]] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It doesn't — ARRAY_AS_PROPS
was just added to make the asserts a little easier to write.
tests/bson/typemap-004.phpt
Outdated
} | ||
|
||
$documents = $cursor->toArray(); | ||
return $documents; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, if there is no variable, an IDE can't inspect its contents, as it can't see the direct return values of a function.
tests/bson/typemap-006.phpt
Outdated
var_dump($documents[0] instanceof stdClass); | ||
var_dump(is_array($documents[0]->array)); | ||
var_dump($documents[0]->array[0] instanceof MyWildCardArrayObject); | ||
var_dump($documents[0]->array[1] instanceof MyArrayObject); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hah!::
class MyWildcardArrayObject extends MyArrayObject {};
So of course it matches :-) I will get rid of the extends, and repeat the MyArrayObject
implementation.
Luckily the implementation was fine, just not the test.
tests/bson/typemap-006.phpt
Outdated
var_dump($documents[0] instanceof stdClass); | ||
var_dump(is_object($documents[0]->object)); | ||
var_dump($documents[0]->object->one instanceof MyArrayObject); | ||
var_dump($documents[0]->object->two instanceof MyWildCardArrayObject); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as above.
tests/bson/typemap-007.phpt
Outdated
} | ||
} | ||
|
||
class MyWildCardArrayObject extends MyArrayObject {}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[Narrator: They were changed to MyWildcardArrayObject anyway]
tests/bson/typemap-007.phpt
Outdated
echo "\nSetting 'object.parent1.$' path to 'MyWildCardArrayObject' and 'object.$.$' to 'MyArrayObject'\n"; | ||
$documents = fetch($manager, ["fieldPaths" => [ | ||
'object.parent1.$' => "MyWildCardArrayObject", | ||
'object.$.$' => "MyArrayObject", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done, added this.
$cursor->setTypeMap($typeMap); | ||
}, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; | ||
|
||
echo "\n"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
500db06
to
7fba7f5
Compare
|
||
if (field_path_original[strlen(field_path_original) - 1] == '.') { | ||
phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT TSRMLS_CC, "A 'fieldPaths' key may not end with a '.'"); | ||
return false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Assuming both of these cases are handled by the "empty segment" error below, I'd propose allowing that to catch this. IMO, ".foo"
, "foo..bar"
, and "foo."
all contain empty segments.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had that first, but thought it better we have more precise error messages. This one is also faster to check as nothing has been allocated yet.
@@ -0,0 +1,67 @@ | |||
--TEST-- | |||
Cursor::setTypeMap(): fieldPaths must be an array, with single key/string elements |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
and it tests the same thing as the error-001 and error-002 tests, so it should be the same here — and not as toPHP_error
Not sure I follow. My suggestion was that once we finalize these tests for Cursor::setTypeMap()
we copy them for toPHP()
to ensure that function passes as well.
Separate from this, can we have all of the current tests organized under cursor/cursor-setTypeMap*
? Any other tests that get copied can then go under bson/bson-toPHP*
EDIT: Just saw your reply in #793 (comment) about wanting to keep things under bson/typemap*
. Point noted, but will we have tests for toPHP()
or do you think that's superfluous?
tests/bson/bson-toPHP-007.phpt
Outdated
--TEST-- | ||
MongoDB\BSON\toPHP(): fieldPath typemaps without server | ||
--SKIPIF-- | ||
<?php require __DIR__ . "/../utils/basic-skipif.inc"; ?> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Server-less tests shouldn't import this, as it ultimately requires PHONGO-SERVERS.json
to exist. The extension check in basic-skipif.inc
isn't very helpful anyway.
I suggest just omitting SKIPIF
here, as is done in other server-less tests.
99394d7
to
d0e8318
Compare
strtok_r() can't handle empty elements :-/
d0e8318
to
da8853a
Compare
First step of implementing the fieldPath syntax. It doesn't do wild cards yet, or typemaps for scalar types.