liam icon indicating copy to clipboard operation
liam copied to clipboard

Feat/support for many_to_many relationship

Open prakha opened this issue 9 months ago • 12 comments

Issue

  • resolve:

Why is this change needed?

What would you like reviewers to focus on?

Testing Verification

What was done

🤖 Generated by PR Agent at aa9db584831d2cff5311e2499ea9bf0c65f8adf9

  • Added support for detecting and processing many-to-many relationships.
  • Implemented utilities for creating implicit join tables and relationships.
  • Enhanced schema parsing to handle many-to-many relations effectively.
  • Added comprehensive test cases for many-to-many relationship handling.

Detailed Changes

Relevant files
Tests
index.test.ts
Added test case for many-to-many relationships                     

frontend/packages/db-structure/src/parser/prisma/index.test.ts

  • Added test case for implicit many-to-many relationships.
  • Validated schema parsing for many-to-many relationships.
  • Ensured expected database structure matches parsed output.
  • +121/-0 
    Enhancement
    parser.ts
    Enhanced schema parser for many-to-many relationships       

    frontend/packages/db-structure/src/parser/prisma/parser.ts

  • Added logic to detect and store many-to-many relationships.
  • Implemented utilities for creating join tables and relationships.
  • Enhanced schema parsing to process many-to-many relations.
  • Added helper functions for primary key and relationship handling.
  • +277/-22
    factories.ts
    Added override support for relationships in factories       

    frontend/packages/db-structure/src/schema/factories.ts

  • Updated aDBStructure to support overriding relationships and table
    groups.
  • +2/-2     

    Additional Notes


    Need help?
  • Type /help how to ... in the comments thread for any questions about Qodo Merge usage.
  • Check out the documentation for more information.
  • prakha avatar Apr 09 '25 04:04 prakha

    🦋 Changeset detected

    Latest commit: b18ac2091174984f334e81850672f37feffad4b7

    The changes in this PR will be included in the next version bump.

    This PR includes changesets to release 2 packages
    Name Type
    @liam-hq/db-structure Patch
    @liam-hq/cli Patch

    Not sure what this means? Click here to learn what changesets are.

    Click here if you're a maintainer who wants to add another changeset to this PR

    changeset-bot[bot] avatar Apr 09 '25 04:04 changeset-bot[bot]

    @prakha is attempting to deploy a commit to the ROUTE06 Core Team on Vercel.

    A member of the Team first needs to authorize it.

    vercel[bot] avatar Apr 09 '25 04:04 vercel[bot]

    PR Reviewer Guide 🔍

    Here are some key observations to aid the review process:

    ⏱️ Estimated effort to review: 3 🔵🔵🔵⚪⚪
    🧪 PR contains tests
    🔒 No security concerns identified
    ⚡ Recommended focus areas for review

    Null Safety

    The code doesn't properly handle cases where model1PrimaryKeyInfo or model2PrimaryKeyInfo could be null. While there's a check before using them, the convertToPostgresColumnType function is called unconditionally which could lead to runtime errors.

    if (model1PrimaryKeyInfo && model2PrimaryKeyInfo) {
      const model1PrimaryKeyColumnType = convertToPostgresColumnType(
        model1PrimaryKeyInfo.type,
        null,
        null,
      )
      const model2PrimaryKeyColumnType = convertToPostgresColumnType(
        model2PrimaryKeyInfo.type,
        null,
        null,
      )
    
      const joinTableName = createManyToManyJoinTableName(
        relation.model1,
        relation.model2,
      )
      // Create join table
      tables[joinTableName] = createManyToManyJoinTable(
        joinTableName,
        model1PrimaryKeyColumnType,
        model2PrimaryKeyColumnType,
      )
    
      // Add relationships for the join table
      const joinTableRelationships = createManyToManyRelationships(
        joinTableName,
        relation.model1,
        model1PrimaryKeyInfo.name,
        relation.model2,
        model2PrimaryKeyInfo.name,
      )
      // Add the relationships to the global relationships object
      Object.assign(relationships, joinTableRelationships)
    }
    
    Error Handling

    The function getPrimaryKeyInfo returns null in error cases, but there's no error logging or handling when primary key information can't be found, which could lead to silent failures in many-to-many relationship processing.

    function getPrimaryKeyInfo(table: Table, models: readonly DMMF.Model[]) {
      const tableName = table?.name
      const model = models.find((m) => m.name === tableName)
    
      if (!model) {
        return null // or throw an error if model is required
      }
    
      const tableIndexes = table?.indexes
      const primaryKeyIndex = tableIndexes[`${tableName}_pkey`]
      const primaryKeyColumnName = primaryKeyIndex?.columns[0]
    
      if (!primaryKeyColumnName) {
        return null // no primary key found
      }
    
      // Find the field in the model that matches the primary key column name
      const primaryKeyField = model.fields.find(
        (field) =>
          field.name === primaryKeyColumnName ||
          field.dbName === primaryKeyColumnName,
      )
    
      return primaryKeyField
    }
    

    PR Code Suggestions ✨

    Explore these optional code suggestions:

    CategorySuggestion                                                                                                                                    Impact
    Possible issue
    Check both tables exist
    Suggestion Impact:The commit implements the suggestion's intent by checking if both model1PrimaryKeyInfo and model2PrimaryKeyInfo exist before proceeding with creating join tables and relationships. This is functionally equivalent to checking if table_A and table_B exist.

    code diff:

    +    if (model1PrimaryKeyInfo && model2PrimaryKeyInfo) {
    

    The code only checks if both tables are undefined before continuing, but doesn't
    handle the case where one table exists and the other doesn't. This could lead to
    errors when trying to create relationships with non-existent tables. Add a check
    to ensure both tables exist before proceeding.

    frontend/packages/db-structure/src/parser/prisma/parser.ts [188-196]

     // Get primary key info for model1 if table_A exists
     const model1PrimaryKeyInfo = table_A
       ? getPrimaryKeyInfo(table_A, dmmf.datamodel.models)
       : null
     
     // Get primary key info for model2 if table_B exists
     const model2PrimaryKeyInfo = table_B
       ? getPrimaryKeyInfo(table_B, dmmf.datamodel.models)
       : null
    +  
    +// Skip if either table is undefined
    +if (!table_A || !table_B) continue
    

    [Suggestion has been applied]

    Suggestion importance[1-10]: 8

    __

    Why: This suggestion addresses a critical issue where the code only checks if both tables are undefined but doesn't handle cases where one table exists and the other doesn't. This could lead to runtime errors when trying to create relationships with non-existent tables.

    Medium
    Ensure consistent join table naming
    Suggestion Impact:The commit implemented the suggestion's intent by refactoring the code to use sorted model names for consistent join table naming. The commit introduces a new getSortedModelPair function (lines 263-265) that sorts model names, and uses this in the storeManyToManyRelation function.

    code diff:

    +function getSortedModelPair(model1: string, model2: string): [string, string] {
    +  return model1.localeCompare(model2) < 0 ? [model1, model2] : [model2, model1]
    +}
    

    The code creates a join table name using the model names in the order they
    appear in the relation, but this can lead to inconsistent naming. Since you're
    already sorting model names when creating the relation ID, you should use the
    same sorted order when creating the join table name to ensure consistency.

    frontend/packages/db-structure/src/parser/prisma/parser.ts [198-213]

     if (model1PrimaryKeyInfo && model2PrimaryKeyInfo) {
       const model1PrimaryKeyColumnType = convertToPostgresColumnType(
         model1PrimaryKeyInfo.type,
         null,
         null,
       )
       const model2PrimaryKeyColumnType = convertToPostgresColumnType(
         model2PrimaryKeyInfo.type,
         null,
         null,
       )
     
    +  // Use sorted model names for consistent join table naming
    +  const sortedModelNames = [relation.model1, relation.model2].sort()
       const joinTableName = createManyToManyJoinTableName(
    -    relation.model1,
    -    relation.model2,
    +    sortedModelNames[0],
    +    sortedModelNames[1],
       )
    

    [Suggestion has been applied]

    Suggestion importance[1-10]: 7

    __

    Why: The suggestion correctly identifies a potential inconsistency in join table naming. Using sorted model names would ensure that the same relationship always produces the same join table name regardless of which side initiates the relationship, preventing potential bugs and data inconsistencies.

    Medium
    • [ ] Update <!-- /improve --more_suggestions=true -->

    Screenshot 2025-04-09 at 10 12 54 AM

    @MH4GF columnType and columnName are added and visible in the UI

    prakha avatar Apr 09 '25 04:04 prakha

    The latest updates on your projects. Learn more about Vercel for Git ↗︎

    Name Status Preview Comments Updated (UTC)
    liam-app ✅ Ready (Inspect) Visit Preview 💬 Add feedback Apr 21, 2025 3:15am
    liam-erd-sample ✅ Ready (Inspect) Visit Preview Apr 21, 2025 3:15am
    1 Skipped Deployment
    Name Status Preview Comments Updated (UTC)
    liam-docs ⬜️ Ignored (Inspect) Visit Preview Apr 21, 2025 3:15am

    vercel[bot] avatar Apr 09 '25 08:04 vercel[bot]

    @prakha I created changeset, I'll merge now!

    MH4GF avatar Apr 11 '25 00:04 MH4GF

    @prakha It's like CI is failed due to the latest main changes. Could you please check?

    MH4GF avatar Apr 11 '25 00:04 MH4GF

    @MH4GF i am travelling today, not free today.

    prakha avatar Apr 11 '25 06:04 prakha

    @prakha OK ✈️

    MH4GF avatar Apr 11 '25 06:04 MH4GF

    @MH4GF i have update the branch also, but still the error is coming.

    prakha avatar Apr 13 '25 14:04 prakha

    @prakha Please check this PR: https://github.com/liam-hq/liam/pull/1168

    MH4GF avatar Apr 14 '25 04:04 MH4GF

    @MH4GF i have solved the issue.

    prakha avatar Apr 20 '25 10:04 prakha