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

[ FIX ] Support top-level And Condition in where query #335

Closed

Conversation

posaune0423
Copy link
Contributor

@posaune0423 posaune0423 commented Nov 24, 2024

Closes #

Introduced changes

  • modify and add test cases so that And conditions in where query logically works
  • add hasOnlyAndCondition not to make root Composite logical operator fixed to Or
  • remove unnecessary console.log and type import

Checklist

  • Linked relevant issue
  • Updated relevant documentation
  • Added relevant tests
  • Add a dedicated CI job for new examples
  • Performed self-review of the code

Summary by CodeRabbit

Summary by CodeRabbit

  • New Features

    • Enhanced query handling with support for complex conditions and nested structures.
    • Introduced new test cases to validate the updated logic for the convertQueryToClause function.
  • Bug Fixes

    • Adjusted expected outputs in test cases to align with new logic and structure.
  • Documentation

    • Updated method signatures to clarify return types for improved understanding of functionality.

Copy link

coderabbitai bot commented Nov 24, 2024

Walkthrough

The changes involve significant updates to the convertQueryToClause function and its associated test cases. The test cases in convertQueryToClause.test.ts have been modified to reflect new expected output structures, including the introduction of nested composite conditions. The function itself has been enhanced to better track composite operators and streamline the handling of member clauses. Additionally, method signatures have been updated to accurately represent the function return types.

Changes

File Path Change Summary
packages/sdk/src/tests/convertQueryToClause.test.ts Removed unused import for SchemaType. Updated test cases for the convertQueryToClause function to reflect new expected output structures, including nested Composite conditions and added a new test case for top-level And conditions.
packages/sdk/src/convertQuerytoClause.ts Introduced hasOnlyAndCondition variable to track composite operators. Updated logic for determining operators, flattening clauses, and streamlining the buildWhereClause function. Method signatures updated to reflect new return types.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant QueryProcessor
    participant ClauseBuilder

    User->>QueryProcessor: Send query
    QueryProcessor->>ClauseBuilder: Convert query to clause
    ClauseBuilder->>ClauseBuilder: Evaluate conditions
    ClauseBuilder->>ClauseBuilder: Determine composite operator
    ClauseBuilder-->>QueryProcessor: Return generated clauses
    QueryProcessor-->>User: Return results
Loading

🐇 "In the land of code where changes bloom,
New clauses arise, dispelling the gloom.
With Ands and Ors, they dance in delight,
Testing the logic, making it right.
A hop and a skip, through functions we prance,
Celebrating the changes, let's give them a chance!" 🐇

Warning

Rate limit exceeded

@posaune0423 has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 25 minutes and 54 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 2918c87 and e9806bd.


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Outside diff range and nitpick comments (4)
packages/sdk/src/__tests__/convertQueryToClause.test.ts (2)

Line range hint 193-263: Well-structured test case for top-level AND conditions.

The test case effectively validates the PR's main objective of supporting top-level And conditions. It provides good coverage with a mix of:

  • Simple equality conditions
  • Numeric comparisons
  • Nested Or conditions

Consider adding these additional test cases to improve coverage:

  1. Empty And condition array
  2. Single condition in And array
  3. Multiple nested And conditions
  4. Mixed And/Or conditions at the same level

Example structure:

it("should handle edge cases in AND conditions", () => {
    const cases = [
        { And: [] },  // empty array
        { And: [{ score: { $gt: 100 } }] },  // single condition
        { And: [{ And: [...] }, { And: [...] }] },  // nested And
        { And: [...], Or: [...] }  // mixed at same level
    ];
    // ... test implementation
});

Line range hint 1-263: Consider implementing a test helper for complex query structures.

As the query structures become more complex with nested conditions, consider creating a test helper function to build these structures. This would:

  1. Reduce duplication in test cases
  2. Make test cases more readable
  3. Make it easier to add new test cases

Example helper structure:

function buildQueryWithConditions(conditions: Condition[]) {
    return {
        world: {
            player: {
                $: {
                    where: {
                        And: conditions
                    }
                }
            }
        }
    };
}
packages/sdk/src/convertQuerytoClause.ts (2)

23-23: Clarify the purpose of skipping 'entityIds' namespace

The line if (namespace === "entityIds") continue; skips processing for the "entityIds" namespace. To improve code readability, please add a comment explaining why "entityIds" is being skipped.


Line range hint 157-218: Consider standardizing the return type of buildWhereClause function

The buildWhereClause function currently returns torii.Clause | torii.Clause[] | undefined, which leads to additional type checks and complexity in the consuming code. To simplify the logic and improve maintainability, consider refactoring buildWhereClause to always return an array of torii.Clause (even if empty).

Suggested changes:

  • Update the function signature to consistently return an array:

    -function buildWhereClause(
    +function buildWhereClause(
        namespaceModel: string,
        where: Record<string, any>
    -): torii.Clause | torii.Clause[] | undefined {
    +): torii.Clause[] {
  • Modify return statements within buildWhereClause to return arrays:

    -    if (subClauses.length === 0) return undefined;
    -    if (subClauses.length === 1) return subClauses[0];
    +    if (subClauses.length === 0) return [];
        return subClauses;
  • Adjust the calling code to handle the array of clauses without checking for single clauses or undefined values:

    In the processModels function:

    -if (clause) {
    -    if (Array.isArray(clause)) {
    -        clauses.push(...clause);
    -    } else {
    -        clauses.push(clause);
    -    }
    -}
    +clauses.push(...clause);

    And similarly in other places where buildWhereClause is called.

This refactor will reduce complexity and make the codebase more consistent.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between b47c945 and 877bb1c.

📒 Files selected for processing (2)
  • packages/sdk/src/__tests__/convertQueryToClause.test.ts (4 hunks)
  • packages/sdk/src/convertQuerytoClause.ts (5 hunks)
🔇 Additional comments (4)
packages/sdk/src/__tests__/convertQueryToClause.test.ts (2)

7-7: LGTM! Import changes are appropriate.

The removal of unused SchemaType import and addition of QueryType import aligns with the actual types being used in the test cases.


141-189: Test case properly validates nested composite conditions.

The updated test case effectively covers:

  • Nested And/Or composite conditions
  • Multiple clauses within each composite
  • Proper model and member field handling

Let's verify the corresponding implementation matches this test case:

✅ Verification successful

Test case aligns with implementation's composite condition handling

The implementation in convertQuerytoClause.ts correctly supports the test case's nested composite conditions through:

  • The buildWhereClause function that handles nested And/Or operators
  • Proper construction of composite clauses with multiple conditions
  • Support for Member clauses with various operators and primitive values
  • Correct handling of hierarchical structure matching the test case format
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for the implementation of composite condition handling
ast-grep --pattern 'function convertQueryToClause($_) {
  $$$
  Composite: {
    operator: $_,
    clauses: $_
  }
  $$$
}'

Length of output: 125


Script:

#!/bin/bash
# Let's try a different approach to find the implementation
# First, let's locate the convertQueryToClause implementation file
fd "convertQueryToClause" --type f

# Then let's examine its content
rg -A 10 "function convertQueryToClause" --type ts

Length of output: 965


Script:

#!/bin/bash
# Let's examine the full implementation of convertQueryToClause
cat packages/sdk/src/convertQuerytoClause.ts

Length of output: 9368

packages/sdk/src/convertQuerytoClause.ts (2)

28-37: Verify the logic for determining hasOnlyAndCondition

The logic that sets hasOnlyAndCondition to false when any clause does not meet the 'Composite' with 'And' operator condition may not handle all scenarios correctly. Please verify that this logic accurately reflects the intended behavior, especially when dealing with mixed operators or nested composite clauses.


46-46: LGTM

The operator selection logic using hasOnlyAndCondition correctly sets the top-level operator to "And" or "Or" based on the clauses.

@posaune0423 posaune0423 changed the title [ FIX ] Support top-level And Condition in query [ FIX ] Support top-level And Condition in where query Nov 24, 2024
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Outside diff range and nitpick comments (2)
packages/sdk/src/convertQuerytoClause.ts (2)

28-37: Simplify the complex condition check for better readability

The nested condition check for determining hasOnlyAndCondition can be simplified using a helper function.

Consider refactoring to:

-if (
-    !modelClauses.every(
-        (clause) =>
-            clause &&
-            "Composite" in clause &&
-            clause.Composite.operator === "And"
-    )
-) {
-    hasOnlyAndCondition = false;
-}
+const isAndCompositeClause = (clause: torii.Clause) => 
+    clause && "Composite" in clause && clause.Composite.operator === "And";
+
+if (!modelClauses.every(isAndCompositeClause)) {
+    hasOnlyAndCondition = false;
+}

Line range hint 152-218: Consider breaking down the complex buildWhereClause function

The function has grown to handle multiple responsibilities:

  1. Logical operator processing
  2. Member clause generation
  3. Array result handling

This complexity makes it harder to maintain and test.

Consider splitting into smaller, focused functions:

+function buildLogicalClause(
+    namespaceModel: string,
+    operator: torii.LogicalOperator,
+    conditions: Array<Record<string, any>>
+): torii.Clause | undefined {
+    const subClauses = conditions
+        .map(condition => buildWhereClause(namespaceModel, condition))
+        .filter((clause): clause is torii.Clause => clause !== undefined);
+
+    if (subClauses.length === 0) return undefined;
+    if (subClauses.length === 1) return subClauses[0];
+
+    return {
+        Composite: {
+            operator,
+            clauses: subClauses,
+        },
+    };
+}
+
+function buildMemberClauses(
+    namespaceModel: string,
+    where: Record<string, any>
+): torii.Clause[] {
+    return Object.entries(where)
+        .flatMap(([member, memberValue]) => {
+            if (typeof memberValue !== 'object' || memberValue === null) return [];
+            
+            return Object.entries(memberValue)
+                .filter(([op]) => op.startsWith('$'))
+                .map(([op, val]) => ({
+                    Member: {
+                        model: namespaceModel,
+                        member,
+                        operator: convertOperator(op),
+                        value: convertToPrimitive(val),
+                    },
+                }));
+        });
+}

 function buildWhereClause(
     namespaceModel: string,
     where: Record<string, any>
 ): torii.Clause | torii.Clause[] | undefined {
     const logicalOperators: Record<string, torii.LogicalOperator> = {
         And: "And",
         Or: "Or",
     };

     const logicalKey = Object.keys(where).find((key) => key in logicalOperators);
     if (logicalKey) {
-        // Handle explicit And/Or conditions
-        const operator = logicalOperators[logicalKey];
-        const conditions = where[logicalKey] as Array<Record<string, any>>;
-
-        const subClauses: torii.Clause[] = [];
-        for (const condition of conditions) {
-            const clause = buildWhereClause(namespaceModel, condition);
-            if (clause) {
-                if (Array.isArray(clause)) {
-                    subClauses.push(...clause);
-                } else {
-                    subClauses.push(clause);
-                }
-            }
-        }
-
-        if (subClauses.length === 0) return undefined;
-        if (subClauses.length === 1) return subClauses[0];
-
-        return {
-            Composite: {
-                operator: operator,
-                clauses: subClauses,
-            },
-        };
+        return buildLogicalClause(
+            namespaceModel,
+            logicalOperators[logicalKey],
+            where[logicalKey] as Array<Record<string, any>>
+        );
     }

-    // If no logical operator, build Member clauses
-    const memberClauses: torii.Clause[] = [];
-
-    for (const [member, memberValue] of Object.entries(where)) {
-        if (typeof memberValue === "object" && memberValue !== null) {
-            for (const [op, val] of Object.entries(memberValue)) {
-                if (!op.startsWith("$")) continue;
-                memberClauses.push({
-                    Member: {
-                        model: namespaceModel,
-                        member,
-                        operator: convertOperator(op),
-                        value: convertToPrimitive(val),
-                    },
-                });
-            }
-        }
-    }
-
-    if (memberClauses.length === 0) return undefined;
-    if (memberClauses.length === 1) return memberClauses[0];
-
-    return memberClauses;
+    const memberClauses = buildMemberClauses(namespaceModel, where);
+    return memberClauses.length === 0 ? undefined :
+           memberClauses.length === 1 ? memberClauses[0] :
+           memberClauses;
 }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 877bb1c and a1eaf8c.

📒 Files selected for processing (1)
  • packages/sdk/src/convertQuerytoClause.ts (5 hunks)
🔇 Additional comments (2)
packages/sdk/src/convertQuerytoClause.ts (2)

125-126: Add type checking before spreading array elements

While spreading array elements from buildWhereClause, ensure all elements are valid clauses.

Consider adding runtime type checks:

-if (Array.isArray(clause)) {
-    clauses.push(...clause);
+if (Array.isArray(clause)) {
+    const validClauses = clause.filter((c): c is torii.Clause => c !== undefined);
+    clauses.push(...validClauses);

Let's verify the usage of array spreading in the codebase:


Line range hint 1-218: Verify handling of nested conditions

The implementation supports top-level "And" conditions as intended. However, let's verify the handling of deeply nested conditions.

Run this script to check for potential edge cases in the test suite:

✅ Verification successful

Nested conditions are properly handled and tested

The test suite demonstrates comprehensive coverage of nested conditions, including:

  • Complex nested AND/OR combinations in "should handle complex conditions with multiple operators"
  • Deep nesting with mixed operators in "should handle top level AND conditions"
  • Various edge cases and combinations of conditions

The implementation correctly processes:

  • Top-level AND conditions
  • Nested AND within OR conditions
  • Multiple levels of nesting with different operators
  • Mixed conditions across different models and namespaces
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check test coverage for nested conditions

# Search for test cases with nested conditions
rg --type typescript 'describe|test|it.*nested.*condition' -A 5 -g '*test*'

# Search for complex query objects in test files
ast-grep --pattern 'const $_ = {
  $$$
  And: [
    $$$
    {
      $$$
      And: [$$$]
      $$$
    }
    $$$
  ]
  $$$
}'

Length of output: 240


Script:

#!/bin/bash
# Let's try a different approach to find test cases and nested conditions

# Search for test files related to query conversion
fd -e ts -e js "test|spec" | grep -i "query\|clause"

# Look for nested condition patterns in test files
rg "And.*\[.*And.*\]" --type ts --type js

# Search for test cases with multiple conditions
rg "test|it\(" -A 10 --type ts --type js | grep -A 10 "operator.*And"

# Look for actual usage of convertQueryToClause with nested structures
ast-grep --pattern 'convertQueryToClause({
  $$$
  And: [
    $$$
  ]
  $$$
})'

Length of output: 374


Script:

#!/bin/bash
# Let's examine the test file content directly

# Display the content of the test file
cat packages/sdk/src/__tests__/convertQueryToClause.test.ts

# Also check the entity key clauses test as it might contain relevant test cases
cat packages/sdk/src/__tests__/convertQueryToEntityKeyClauses.test.ts

Length of output: 16762

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Outside diff range and nitpick comments (1)
packages/sdk/src/__tests__/convertQueryToClause.test.ts (1)

Line range hint 193-262: Comprehensive test case for top-level AND conditions

The new test case effectively validates the main PR objective with a good mix of conditions. Consider adding edge cases to strengthen the test suite:

  • Empty AND array
  • Single condition in AND array
  • Deeply nested AND/OR combinations

Would you like me to provide example test cases for these scenarios?

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 2918c87 and e9806bd.

📒 Files selected for processing (1)
  • packages/sdk/src/__tests__/convertQueryToClause.test.ts (3 hunks)
🔇 Additional comments (3)
packages/sdk/src/__tests__/convertQueryToClause.test.ts (3)

7-7: LGTM! Clean import statements

The removal of unused SchemaType import and retention of only necessary imports improves code cleanliness.


141-189: Well-structured test expectations for complex conditions

The updated test expectations effectively validate:

  • Nested composite conditions (AND within OR)
  • Multiple field conditions (score and name)
  • Multiple model conditions (player and item)
  • Various operators (Gt, Eq, Lt)

Line range hint 1-262: Verify test coverage for the new functionality

Let's ensure we have comprehensive test coverage for the new AND condition handling.

✅ Verification successful

Test coverage appears comprehensive for AND condition handling

Looking at the implementation and test cases, the test coverage for AND conditions is thorough:

  • The test "should handle complex conditions with multiple operators" covers nested AND conditions with OR combinations
  • The test "should handle top level AND conditions" specifically tests the new AND condition handling
  • The implementation correctly processes both top-level and nested AND conditions in buildWhereClause function
  • All operator cases including AND/OR compositions are properly tested with various combinations
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check test coverage for convertQueryToClause
npx vitest run --coverage packages/sdk/src/__tests__/convertQueryToClause.test.ts | grep -A 5 "Coverage summary"

Length of output: 208


Script:

#!/bin/bash
# Let's analyze the test coverage by examining the test cases and implementation
# First, let's check the implementation of convertQueryToClause
ast-grep --pattern 'export function convertQueryToClause' -A 10

# Then, let's check all test cases
rg "it\(" packages/sdk/src/__tests__/convertQueryToClause.test.ts -A 2

Length of output: 834


Script:

#!/bin/bash
# Let's examine the implementation file to understand what functionality needs to be tested
rg -l "convertQueryToClause" --type ts

# Then get the content of the implementation file
fd "convertQuerytoClause.ts" --type f --exec cat {}

Length of output: 9958

@MartianGreed
Copy link
Collaborator

Thank's for contribution ser, would you mind create fill in a PR in the book to document how query should be built ?

@posaune0423
Copy link
Contributor Author

posaune0423 commented Nov 24, 2024

@MartianGreed
Thank you for your response. Apologies for not being able to communicate properly after creating this PR, as I had to catch a flight right away.

I realized that the implementation approach in this PR was slightly mistaken, so I have made new fixes in this PR. Could you please take a look at it?
And I'll create new PR to update doc as well!

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.

2 participants