Skip to content
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

PHPLIB-1122: Support Document and PackedArray objects in public APIs #1077

Merged
merged 12 commits into from May 26, 2023

Conversation

jmikola
Copy link
Member

@jmikola jmikola commented May 23, 2023

https://jira.mongodb.org/browse/PHPLIB-1122

Excluding tests, most changes were concentrated in functions.php. A document_to_array() function was introduced to make it easier to access document values as arrays. This is mainly used by other utility functions (e.g. checking for dollar prefixed keys) but also ended up being used in the Find operation for handling the "modifiers" option.

Adds tests for using Document and PackedArray objects in operations.

Beyond handling of document/array types, this also filled gaps in test coverage for:

  • Validation for IndexInput key/name options
  • Passing a MongoDB\Driver\Command directly to DatabaseCommand
  • is_last_pipeline_operator_write()

Addressed

Most changes were made to internal functions, which are used by many operations/classes. The following is a summary of test coverage changes in FunctionsTest:

  • document_to_array(): various types for $document argument. This is used by many other internal functions and the Find operation.
  • is_first_key_operator(): various types for $document argument. This is used by operations that peform updates (e.g. BulkWrite, FindOneAndUpdate, Update).
  • is_last_pipeline_operator_write(): testing more inputs and using a variety of types for stage documents. This is used by Aggregate (operation and helpers) and indirectly by the Watch operation.
  • is_mapreduce_output_inline(): various types for $out argument. This is used by MapReduce.
  • is_pipeline(): various types for $pipeline argument and stage documents within. This is used for validating update values for update and findAndModify commands.

The following is a summary of added test coverage for various operations/classes. When an argument/option is listed without additional details, that means we've added test coverage for expressing the document in various forms (i.e. array, stdClass, Serializable, Document):

  • CountFunctionalTest:
    • Count: $filter
  • CountDocumentsFunctionalTest
    • CountDocuments: $filter
  • CreateIndexesTest:
    • IndexInput: order validation for key option. Additionally filled gaps in test coverage for validating key and name options (unrelated to documents)
  • CreateIndexesFunctionalTest:
    • CreateIndexes: key option
    • IndexInput: generating name option from key option
  • DatabaseCommand
    • DatabaseCommand: $command. Additionally added test coverage for passing a MongoDB\Driver\Command object constructed from various document types.
  • DeleteFunctionalTest
    • DeleteMany: $filter
    • DeleteOne: $filter
  • DistinctFunctionalTest
    • Distinct: $filter
  • FindFunctionalTest
    • Find: $filter, modifiers option
    • FindOne: $filter, modifiers option
  • FindAndModifyFunctionalTest
    • FindAndModify: filter and query options
    • FindOneAndDelete: $filter
    • FindOneAndReplace: $filter, $replacement
    • FindOneAndUpdate: $filter, $update
  • FindOneAndReplaceTest
    • FindOneAndReplace: $replacement validation
  • FindOneAndUpdateTest
    • FindOneAndUpdate: $update validation
  • InsertManyFunctionalTest
    • InsertMany: encoding $documents elements and _id generation/access
  • InsertOneFunctionalTest
    • InsertOne: encoding $document and _id generation/access
  • ReplaceOneTest
    • ReplaceOneTest: $replacement validation
  • UpdateTest
    • Update: $update validation based on multi option
  • UpdateFunctionalTest
    • Update: $filter, $update
    • ReplaceOne: $filter, $replacement
    • UpdateMany: $filter, $update
    • UpdateOne: $filter, $update
  • UpdateManyTest
    • UpdateMany: $update validation
  • UpdateOneTest
    • UpdateOne: $update validation

Omitted

The following are notable parts of PHPLIB that were not touched by this PR:

  • apply_type_map_to_document(): only used in GridFS on stdClass objects
  • GridFS metadata document: not used beyond type validation as an "array or object"

@jmikola jmikola requested review from alcaeus and GromNaN May 23, 2023 05:19
Copy link
Member

@alcaeus alcaeus left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a lot of tests being added, and it looks like you've covered all of the new use cases for packed arrays and documents. I left a few suggestions that should also help with getting psalm to play nice with these changes.

src/functions.php Outdated Show resolved Hide resolved
src/functions.php Outdated Show resolved Hide resolved
src/functions.php Show resolved Hide resolved
src/functions.php Show resolved Hide resolved
/* Nested documents and arrays are intentionally left as BSON. We avoid
* iterator_to_array() since Document and PackedArray iteration returns
* all values as MongoDB\BSON\Value instances. */
return $document->toPHP([
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I remember playing around with psalm return types based on the $typeMap parameter, but IIRC there were some issues comparing against the array keys. I've created PHPC-2227 to track adding stubs to psalm to ensure Psalm understands these classes.

In the meantime, consider adding these two errors to the baseline or storing the result of the toPHP call and using @var to let Psalm know that this will be an array.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. I found a few more errors as well and fixed all but one (see the commit for the regenerated baseline).

tests/Operation/FindOneAndReplaceTest.php Show resolved Hide resolved
tests/TestCase.php Show resolved Hide resolved
tests/Operation/FindOneAndReplaceTest.php Show resolved Hide resolved
src/functions.php Show resolved Hide resolved
src/functions.php Outdated Show resolved Hide resolved
src/functions.php Outdated Show resolved Hide resolved
src/functions.php Show resolved Hide resolved
src/functions.php Show resolved Hide resolved
Copy link
Member

@GromNaN GromNaN left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Take my approval for what it is worth. SGTM.

@jmikola jmikola force-pushed the phplib-1122 branch 2 times, most recently from 51ba28d to 80d88d5 Compare May 26, 2023 03:00
jmikola added 12 commits May 26, 2023 11:32
Excluding tests, most changes were concentrated in functions.php. A document_to_array() function was introduced to make it easier to access document values as arrays. This is mainly used by other utility functions (e.g. checking for dollar prefixed keys) but also ended up being used in the Find operation for handling the "modifiers" option.

Adds tests for using Document and PackedArray objects in operations.

Beyond handling of document/array types, this also filled gaps in test coverage for:

 * Validation for IndexInput key/name options
 * Passing a MongoDB\Driver\Command directly to DatabaseCommand
 * is_last_pipeline_operator_write()
Processing a Document and PackedArray will yield an array, so we can avoid a redundant Serializable check by using elseif.
…operator()

This introduces a dependency on symfony/polyfill-php73 and bumps both polyfill packages to the latest minor version for consistency.

The doc block for is_first_key_operator() was revised to note its additional purpose for validating pipeline stages.
This suppresses a new error in BulkWrite pertaining to a variable previously checked by is_first_key_operator() and is_pipeline().

```
ERROR: MixedArgument - src/Operation/BulkWrite.php:341:45 - Argument 2 of MongoDB\Driver\BulkWrite::update cannot be mixed, expecting array<array-key, mixed>|object (see https://psalm.dev/030)
                    $bulk->update($args[0], $args[1], $args[2]);

  The type of $args[1] is sourced from here - vendor/vimeo/psalm/stubs/CoreGenericFunctions.phpstub:154:12
 * @return (TArray is array<empty,empty> ? false : (TArray is non-empty-array ? TValue : TValue|false))
```

Other changes to the baseline are removals for obsolete errors.
Copy link
Member

@alcaeus alcaeus left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. I've rebased this PR on master, and as long as the psalm check is happy, I'm happy. While the baseline contains lots of changes, I believe most of those are from a previous generation on PHP 8+ (I believe I last regenerated the baseline on PHP 8.2).

@jmikola
Copy link
Member Author

jmikola commented May 26, 2023

CI failures are related to CSFLE QEv2 protocol changes, and two timeouts in CSFLE tests on Debian 9.2 (unrelated to this PR). I'll proceed with merging.

@jmikola jmikola merged commit 789368a into mongodb:master May 26, 2023
24 of 31 checks passed
@jmikola jmikola deleted the phplib-1122 branch May 26, 2023 11:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants