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

Remove specific encoder for Group and DollarGroup, use property name map #1540

Merged
merged 3 commits into from
Dec 2, 2024

Conversation

GromNaN
Copy link
Member

@GromNaN GromNaN commented Nov 27, 2024

For every Operator class, we add a PROPERTIES constant that contains a map of PHP property name to the operator name.
This allows to remove 2 specific encoders:

  • $group stage is now [ '_id' => '_id', 'field' => null ]. This means every property for the field object are encoded as properties of the operator object.
  • $near operator is now ['geometry' => null, 'maxDistance' => '$maxDistance', 'minDistance' => '$minDistance']. The property $geometry of the geometry object is set to the operator object properties. And the name of the other properties get the $ prefix.

@GromNaN GromNaN requested a review from a team as a code owner November 27, 2024 16:57
@GromNaN GromNaN requested a review from alcaeus November 27, 2024 16:57
@GromNaN GromNaN changed the title Remove specific encoder for Group and DollarGroup, use property name map Remove specific encoder for Group and DollarGroup, use property name map Nov 27, 2024
Comment on lines 6 to 12
encode: object
description: |
Selects geometries that intersect with a GeoJSON geometry. The 2dsphere index supports $geoIntersects.
arguments:
-
name: geometry
noName: true
Copy link
Member Author

Choose a reason for hiding this comment

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

This change was not required. But this is for consistency with other geo operators.

@@ -55,7 +46,8 @@ private function encodeAsArray(OperatorInterface $value): stdClass
{
$result = [];
/** @var mixed $val */
foreach (get_object_vars($value) as $val) {
foreach ($value::PROPERTIES as $prop => $name) {
Copy link
Member Author

Choose a reason for hiding this comment

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

Loops over existing array instead of converting object to array with get_object_vars. Must be more performant.

src/Builder/Encoder/OperatorEncoder.php Dismissed Show dismissed Hide dismissed
src/Builder/Encoder/OperatorEncoder.php Dismissed Show dismissed Hide dismissed
src/Builder/Encoder/OperatorEncoder.php Dismissed Show dismissed Hide dismissed
src/Builder/Encoder/OperatorEncoder.php Dismissed Show dismissed Hide dismissed
src/Builder/Encoder/OperatorEncoder.php Dismissed Show dismissed Hide dismissed
src/Builder/Encoder/OperatorEncoder.php Dismissed Show dismissed Hide dismissed
src/Builder/Encoder/OperatorEncoder.php Dismissed Show dismissed Hide dismissed
src/Builder/Encoder/OperatorEncoder.php Dismissed Show dismissed Hide dismissed
src/Builder/Encoder/OperatorEncoder.php Dismissed Show dismissed Hide dismissed
src/Builder/Encoder/OperatorEncoder.php Dismissed Show dismissed Hide dismissed
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.

Nice way of cleaning up some more confusing encoding types, I like it. I have a few smaller suggestions around wording and logic encapsulation.

| `variadic` | `string` | If sent, the argument is variadic. Defines the format `array` for a list or `object` for a map |
| `variadicMin` | `integer` | The minimum number of arguments for a variadic parameter. |
| `default` | `scalar` or `array` | The default value for the argument. |
| `noName` | `bool` | Default `false`. If `true`, the value must be an object and the properties of the value object are merged into the parent operator. `$group` stage uses it for the fields. |
Copy link
Member

Choose a reason for hiding this comment

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

I'll let @jmikola add his thoughts as well, but "pulling to the top" is usually called "hoisting". An example of this would be JavaScript Hoisting, where variable declarations are hoisted to the top of the block they appear in. Both noName and hoist would need explanations here, but I feel like noName is more ambiguous than hoist.

A different alternative is mergeToTopLevel, referring to the "merge" wording you used in the field description in the JSON schema.

Copy link
Member Author

Choose a reason for hiding this comment

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

hoist is too unfamiliar to me. I'll change to mergeObject.

Copy link
Member

Choose a reason for hiding this comment

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

I'm fine with mergeObject or mergeUp. I read the "JavaScript Hoisting" article, putting aside my historic disdain for W3Fools, but it didn't seem entirely relevant as it was talking about variable declarations and scopes.

### Arguments

| Field | Type | Description |
| `name` | `string` | The name of the argument. It can start with `$`. |
Copy link
Member

Choose a reason for hiding this comment

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

I suppose a leading $ is used when the parameter in the aggregation operator needs it, but it is not part of the name used in the generated factory? In that case, I would recommend specifying the last part, as it is important to know for people re-using these files.

Copy link
Member Author

Choose a reason for hiding this comment

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

Added

Comment on lines 69 to 70
$argName = ltrim($argument->name, '$');
$encodeNames[$argName] = $argument->noName ? null : $argument->name;
Copy link
Member

Choose a reason for hiding this comment

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

How about adding methods to the argument class for these:

  • name would return the name as-is
  • getParameterName would return the name as used in factories, properties, etc.
  • getEncodedName would return the name, or null if noName has been set.

This would avoid duplicating the logic in various generator classes.

Copy link
Member Author

Choose a reason for hiding this comment

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

Added $propName property.

generator/src/OperatorClassGenerator.php Show resolved Hide resolved
@@ -9,8 +9,11 @@
*/
interface OperatorInterface
{
/** To be overridden by implementing classes */
/** @var Encode */
public const ENCODE = Encode::Undefined;
Copy link
Member

Choose a reason for hiding this comment

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

I was wondering why we didn't use a typed class constant, until I saw that they were only added in PHP 8.3.

Copy link
Member

@jmikola jmikola left a comment

Choose a reason for hiding this comment

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

Two small comments, but defer to you to address.

| Field | Type | Description |
| `name` | `string` | The name of the argument. It can start with `$` when the aggregation operator needs it, but it will be trimmed from the class property name. |
| `type` | list of `string` | The list of accepted types |
| `description` | `string` | The description of the argument from MongoDB's documentation. |
Copy link
Member

Choose a reason for hiding this comment

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

For single-phrase descriptions, I think you can omit the trailing period. Periods make sense when there are multiple sentences in a description.

I'll refrain from commenting on the other lines here, but there are some inconsistencies.

Also, this is a very minor nit.

Copy link
Member Author

Choose a reason for hiding this comment

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

Updated.

// Skip optional arguments. If they have a default value, it is resolved by the server.
if ($val === Optional::Undefined) {
continue;
}

$result->{$key} = $this->recursiveEncode($val);
if ($name === null) {
Copy link
Member

Choose a reason for hiding this comment

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

Assuming this is the place where mergeObject: true is handled, a comment here would be helpful.

Copy link
Member Author

Choose a reason for hiding this comment

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

👍🏻 Comment added.

@GromNaN GromNaN enabled auto-merge (squash) December 2, 2024 20:42
@GromNaN GromNaN requested review from alcaeus and removed request for alcaeus December 2, 2024 21:01
@GromNaN GromNaN disabled auto-merge December 2, 2024 21:02
@GromNaN GromNaN enabled auto-merge (squash) December 2, 2024 21:03
@GromNaN GromNaN merged commit 2106092 into mongodb:v1.x Dec 2, 2024
29 checks passed
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.

3 participants