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: [#280] add wrap for sql #719

Merged
merged 5 commits into from
Nov 12, 2024
Merged

fix: [#280] add wrap for sql #719

merged 5 commits into from
Nov 12, 2024

Conversation

hwbrzzl
Copy link
Contributor

@hwbrzzl hwbrzzl commented Nov 9, 2024

📑 Description

Add wrap for table, column, index, etc:

-- create table goravel_users (id serial primary key not null, name varchar(100) null)
++ create table "goravel_users" ("id" serial primary key not null, "name" varchar(100) null)

Summary by CodeRabbit

  • New Features

    • Introduced a Wrap struct for managing SQL table and column naming conventions with a specified prefix.
    • Enhanced handling of foreign key definitions and index naming conventions.
  • Bug Fixes

    • Removed deprecated methods and adjusted related functionalities for better clarity and performance.
  • Tests

    • Expanded test coverage for PostgreSQL and SQLite grammar operations to validate new naming conventions and functionality.
  • Documentation

    • Updated initialization methods to include a table prefix, improving consistency across database schema operations.

✅ Checks

  • Added test cases for my code

Copy link
Contributor

coderabbitai bot commented Nov 9, 2024

Walkthrough

The pull request introduces significant modifications to the database schema management components, particularly affecting the Grammar interface and Blueprint struct. Key changes include the removal of the GetModifiers method, adjustments to foreign key and index naming conventions, and the introduction of a Wrap struct for managing SQL naming conventions with a specified table prefix. Additionally, various test suites have been updated or expanded to ensure compliance with the new naming conventions and functionality.

Changes

File Change Summary
contracts/database/schema/grammar.go Removed GetModifiers method from Grammar interface.
database/schema/blueprint.go Updated Foreign, GetTableName, and createIndexName methods to simplify foreign key and index naming.
database/schema/blueprint_test.go Adjusted tests for index name generation and removed TestGetTableName.
database/schema/grammars/postgres.go Added wrap field to Postgres, updated various methods to use the new wrapping logic.
database/schema/grammars/postgres_test.go Updated tests to include a prefix for PostgreSQL operations and added new tests for drop commands.
database/schema/grammars/sqlite.go Added tablePrefix and wrap fields to Sqlite, updated methods for name formatting.
database/schema/grammars/sqlite_test.go Updated tests to reflect new prefixing for SQLite operations and added new tests for foreign keys.
database/schema/grammars/utils.go Removed several utility functions related to SQL generation.
database/schema/grammars/utils_test.go Removed tests for deleted utility functions.
database/schema/grammars/wrap.go Introduced Wrap struct for managing SQL naming conventions with methods for formatting.
database/schema/grammars/wrap_test.go Added tests for Wrap functionality, covering various scenarios for name formatting.
database/schema/index.go Removed prefix field from ForeignKeyDefinition and updated related methods.
database/schema/postgres_schema_test.go Updated NewPostgresSchema instantiation to include a prefix in tests.
database/schema/schema.go Adjusted grammar initialization to include prefixes and simplified HasTable method logic.

Possibly related PRs

Suggested reviewers

  • kkumar-gcc

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

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

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

⚠️ Performance Alert ⚠️

Possible performance regression was detected for benchmark.
Benchmark result of this commit is worse than the previous benchmark result exceeding threshold 1.50.

Benchmark suite Current: 9edde4c Previous: ab4c85c Ratio
Benchmark_Fatal 2e-7 ns/op 0 B/op 0 allocs/op 1e-7 ns/op 0 B/op 0 allocs/op 2
Benchmark_Fatal - ns/op 2e-7 ns/op 1e-7 ns/op 2

This comment was automatically generated by workflow using github-action-benchmark.

Copy link

codecov bot commented Nov 9, 2024

Codecov Report

Attention: Patch coverage is 74.80916% with 33 lines in your changes missing coverage. Please review.

Project coverage is 69.73%. Comparing base (ab4c85c) to head (9edde4c).
Report is 1 commits behind head on master.

Files with missing lines Patch % Lines
database/schema/grammars/wrap.go 43.13% 24 Missing and 5 partials ⚠️
database/schema/grammars/postgres.go 93.93% 2 Missing ⚠️
database/schema/grammars/sqlite.go 93.10% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master     #719      +/-   ##
==========================================
+ Coverage   69.63%   69.73%   +0.10%     
==========================================
  Files         201      202       +1     
  Lines       15816    15875      +59     
==========================================
+ Hits        11013    11071      +58     
+ Misses       4205     4201       -4     
- Partials      598      603       +5     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@hwbrzzl hwbrzzl marked this pull request as ready for review November 10, 2024 02:14
@hwbrzzl hwbrzzl requested a review from a team as a code owner November 10, 2024 02:14
Copy link
Contributor

@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: 4

🧹 Outside diff range and nitpick comments (14)
database/schema/postgres_schema_test.go (1)

Line range hint 37-39: Consider implementing the TODO test case.

The TestGetTypes function is currently empty with a TODO comment. Since this PR modifies schema handling, it would be beneficial to implement this test to ensure type handling works correctly with the new identifier wrapping.

Would you like me to help implement the TestGetTypes test case or create a GitHub issue to track this task?

database/schema/grammars/wrap_test.go (1)

22-70: Consider adding more test cases for edge cases and negative scenarios.

While the current test coverage is good for basic scenarios, consider adding tests for:

  1. Edge cases:

    • Identifiers containing special characters
    • Reserved SQL keywords (e.g., "select", "where", "group")
    • Unicode characters in identifiers
  2. Negative test cases:

    • Invalid identifiers
    • SQL injection attempts
  3. Consider refactoring similar tests using table-driven tests for better maintainability.

Example of table-driven test approach:

func (s *WrapTestSuite) TestColumn() {
    tests := []struct {
        name     string
        input    string
        expected string
    }{
        {
            name:     "with alias",
            input:    "column as alias",
            expected: `"column" as "prefix_alias"`,
        },
        {
            name:     "without alias",
            input:    "column",
            expected: `"column"`,
        },
        {
            name:     "with reserved keyword",
            input:    "select",
            expected: `"select"`,
        },
        // Add more test cases
    }

    for _, tt := range tests {
        s.Run(tt.name, func() {
            result := s.wrap.Column(tt.input)
            s.Equal(tt.expected, result)
        })
    }
}
database/schema/grammars/wrap.go (2)

8-16: Add documentation for the Wrap type and constructor.

Consider adding GoDoc comments to explain the purpose of the Wrap type and its constructor. This will help other developers understand how to use this package correctly.

+// Wrap handles SQL identifier wrapping with optional table prefixing
 type Wrap struct {
 	tablePrefix string
 }

+// NewWrap creates a new Wrap instance with the specified table prefix
 func NewWrap(tablePrefix string) *Wrap {

42-52: Improve readability of the Segments method.

The method logic is correct, but variable names could be more descriptive.

 func (r *Wrap) Segments(segments []string) string {
-	for i, segment := range segments {
+	for i, identifier := range segments {
 		if i == 0 && len(segments) > 1 {
-			segments[i] = r.Table(segment)
+			segments[i] = r.Table(identifier)
 		} else {
-			segments[i] = r.Value(segment)
+			segments[i] = r.Value(identifier)
 		}
 	}
database/schema/schema.go (1)

44-54: Consider adding documentation about identifier wrapping.

Since this PR introduces significant changes in how SQL identifiers are wrapped, it would be helpful to add documentation comments explaining:

  • The new identifier wrapping behavior
  • How prefixes interact with wrapped identifiers
  • Any special considerations for different database drivers

Add documentation above the grammar initialization:

 switch driver {
 case contractsdatabase.DriverPostgres:
+    // NewPostgres creates a Postgres grammar that properly wraps table names,
+    // column names, and other identifiers with double quotes to handle special
+    // characters and reserved keywords. The prefix is prepended to table names
+    // before wrapping.
     schema := config.GetString(fmt.Sprintf("database.connections.%s.search_path", orm.Name()), "public")
database/schema/blueprint.go (2)

84-86: Consider implementing the Postgres schema support.

The TODO comment indicates missing Postgres schema support. This could be important for proper identifier quoting in schema-qualified table names.

Would you like me to help implement the Postgres schema support or create an issue to track this?


209-222: Consider enhancing the index name creation logic.

The changes correctly handle schema-qualified table names and prefix application. However, consider these improvements:

  1. Add documentation explaining the index name format and rules
  2. Make the string manipulation more robust using a helper function

Consider refactoring like this:

 func (r *Blueprint) createIndexName(ttype string, columns []string) string {
+    // Format: <schema>_<prefix>_<table>_<columns>_<type>
+    // Example: public_goravel_users_id_name_index
     var table string
     if strings.Contains(r.table, ".") {
         lastDotIndex := strings.LastIndex(r.table, ".")
         table = r.table[:lastDotIndex+1] + r.prefix + r.table[lastDotIndex+1:]
     } else {
         table = r.prefix + r.table
     }

     index := strings.ToLower(fmt.Sprintf("%s_%s_%s", table, strings.Join(columns, "_"), ttype))

-    index = strings.ReplaceAll(index, "-", "_")
-    index = strings.ReplaceAll(index, ".", "_")
+    // Replace invalid characters with underscore
+    replacer := strings.NewReplacer("-", "_", ".", "_")
+    index = replacer.Replace(index)

     return index
 }
database/schema/grammars/sqlite_test.go (4)

25-41: Consider adding edge cases to foreign key tests

While the current test cases cover basic foreign key functionality, consider adding tests for:

  • Table/column names containing spaces or special characters
  • Reserved SQL keywords as identifiers
  • Empty or invalid references

104-120: Consider reducing test duplication

The foreign key configurations in the test are nearly identical. Consider extracting the common configuration into a test helper or using table-driven tests to improve maintainability.

type foreignKeyTest struct {
    columns    []string
    on         string
    references []string
    onDelete   string
    onUpdate   string
}

testCases := []foreignKeyTest{
    {
        columns:    []string{"role_id", "permission_id"},
        on:         "roles",
        references: []string{"id"},
        onDelete:   "cascade",
        onUpdate:   "restrict",
    },
    // Add more test cases here
}

131-140: Consider expanding index test coverage

While the basic index creation is tested, consider adding tests for:

  • UNIQUE indexes
  • Descending indexes (column DESC)
  • Partial indexes with WHERE clauses
  • Concurrent index creation

142-162: Consider testing additional column types and constraints

The test covers basic column types well, but consider adding tests for:

  • JSON/JSONB columns
  • ENUM types
  • CHECK constraints
  • COLLATE clauses
  • GENERATED columns
database/schema/blueprint_test.go (1)

142-145: Enhance test coverage for schema-qualified tables

While the test case correctly verifies schema-qualified table names, consider adding more test cases to cover:

  1. Different schema names (not just "public")
  2. Edge cases with special characters in schema names
  3. Multiple dots in table names

Example addition:

 s.blueprint.table = "public.users"
 name = s.blueprint.createIndexName("index", []string{"id", "name-1", "name.2"})
 s.Equal("public_goravel_users_id_name_1_name_2_index", name)
+
+// Test custom schema
+s.blueprint.table = "custom_schema.users"
+name = s.blueprint.createIndexName("index", []string{"id"})
+s.Equal("custom_schema_goravel_users_id_index", name)
+
+// Test schema name with special characters
+s.blueprint.table = "my-schema.users"
+name = s.blueprint.createIndexName("index", []string{"id"})
+s.Equal("my_schema_goravel_users_id_index", name)
database/schema/grammars/postgres_test.go (1)

88-102: LGTM: Comprehensive drop operation test coverage

The new test methods thoroughly cover various PostgreSQL drop operations with proper identifier quoting and schema qualification.

Consider using a table-driven test to reduce code duplication across these similar drop operation tests. Example:

func (s *PostgresSuite) TestCompileDropAll() {
    tests := []struct {
        name     string
        method   func([]string) string
        command  string
        input    []string
        expected string
    }{
        {
            name:     "Domains",
            method:   s.grammar.CompileDropAllDomains,
            command:  "domain",
            input:    []string{"domain", "user.email"},
            expected: `drop domain "domain", "user"."email" cascade`,
        },
        // Add other cases...
    }
    
    for _, tt := range tests {
        s.Run(tt.name, func() {
            s.Equal(tt.expected, tt.method(tt.input))
        })
    }
}
database/schema/grammars/sqlite.go (1)

81-83: Verify wrapping of index names in CompileIndex

The CompileIndex method wraps the index name using r.wrap.Column(command.Index). Ensure that command.Index refers to a column name rather than an index name. If it's an index name, consider creating a dedicated wrap method for index names to maintain clarity and correctness.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between ab4c85c and 9edde4c.

⛔ Files ignored due to path filters (1)
  • mocks/database/schema/Grammar.go is excluded by !mocks/**
📒 Files selected for processing (14)
  • contracts/database/schema/grammar.go (0 hunks)
  • database/schema/blueprint.go (4 hunks)
  • database/schema/blueprint_test.go (2 hunks)
  • database/schema/grammars/postgres.go (5 hunks)
  • database/schema/grammars/postgres_test.go (5 hunks)
  • database/schema/grammars/sqlite.go (6 hunks)
  • database/schema/grammars/sqlite_test.go (3 hunks)
  • database/schema/grammars/utils.go (0 hunks)
  • database/schema/grammars/utils_test.go (0 hunks)
  • database/schema/grammars/wrap.go (1 hunks)
  • database/schema/grammars/wrap_test.go (1 hunks)
  • database/schema/index.go (2 hunks)
  • database/schema/postgres_schema_test.go (1 hunks)
  • database/schema/schema.go (2 hunks)
💤 Files with no reviewable changes (3)
  • contracts/database/schema/grammar.go
  • database/schema/grammars/utils.go
  • database/schema/grammars/utils_test.go
🔇 Additional comments (44)
database/schema/postgres_schema_test.go (1)

34-34: LGTM! Verify test coverage for prefix handling.

The change to include the "goravel_" prefix in schema initialization is consistent with the PR's objective to enhance SQL identifier handling.

Let's verify if all test cases properly handle the new prefix:

✅ Verification successful

Prefix handling is properly implemented and tested

The verification shows that:

  1. The "goravel_" prefix is consistently used in the test file and its implementation
  2. The test cases in TestParseSchemaAndTable correctly handle both prefixed and non-prefixed scenarios
  3. The grammar tests in grammars/postgres_test.go thoroughly verify prefix wrapping for all SQL operations
  4. All SQL identifiers are properly wrapped with quotes and prefixes in the test assertions
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check if there are any hardcoded table names in tests that might need updating
# for the new prefix system

# Search for table names in test assertions
rg -l 'Equal.*".*table' --type go

# Search for SQL statements in test files that might need wrapping
rg -l 'CREATE TABLE [^"]' --type go

Length of output: 539


Script:

#!/bin/bash
# Let's examine the actual test cases in postgres_schema_test.go to verify prefix handling
cat database/schema/postgres_schema_test.go

# Also check the implementation of NewPostgres to understand prefix usage
ast-grep --pattern 'func NewPostgres($$$) $$ {
  $$$
}'

# Check other schema test files for consistency
fd postgres.*test.go$ --exec cat {}

Length of output: 18124

database/schema/grammars/wrap_test.go (2)

1-8: LGTM! Clean package structure and imports.


1-70: Verify SQL compatibility with different database engines.

While the tests verify the wrapping syntax, it would be valuable to ensure the wrapped identifiers work correctly with different SQL databases, especially for edge cases.

Let's check if there are any integration tests that verify this:

database/schema/index.go (2)

11-14: LGTM! Verify impact on existing foreign key definitions.

The simplified constructor aligns with the PR objectives. However, we should verify that existing foreign key definitions are properly handled with this change.

✅ Verification successful

Let me gather more information about the foreign key definition usage to verify the impact.


Let me check one final aspect about the usage of foreign keys in the actual implementation.


Removal of prefix parameter is safe and correctly implemented

Based on the comprehensive analysis of the codebase:

  1. The ForeignKeyDefinition struct only contains a command field, with no prefix-related fields
  2. All foreign key methods (On, References, CascadeOnDelete, etc.) operate solely on the command object
  3. Test cases show foreign keys are created and used without any prefix dependencies
  4. The change aligns with the PR's objective of properly handling SQL identifiers
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for existing foreign key definitions that might be affected
# by the removal of prefix parameter

# Search for foreign key creation patterns
rg -A 3 "Foreign\(" 

# Search for potential custom foreign key handling
rg -l "ForeignKeyDefinition"

Length of output: 4625


Script:

#!/bin/bash
# Check the implementation of Foreign method and its usage of NewForeignKeyDefinition
ast-grep --pattern 'func $_($_ Blueprint) Foreign($$$) {
  $$$
  return NewForeignKeyDefinition($$$)
}'

# Check for any prefix-related code in foreign key definitions
rg -A 5 "prefix.*Foreign|Foreign.*prefix"

# Check the actual implementation of ForeignKeyDefinition struct
ast-grep --pattern 'type ForeignKeyDefinition struct {
  $$$
}'

Length of output: 553


Script:

#!/bin/bash
# Check the implementation of methods in ForeignKeyDefinition
ast-grep --pattern 'func ($_ *ForeignKeyDefinition) $_($$$) $$$'

# Check for any test cases that might show the usage pattern
rg -A 5 "NewForeignKeyDefinition|Foreign\(" database/schema/*_test.go

Length of output: 17411


29-32: Verify table name wrapping implementation.

The removal of prefix handling from the On method suggests that table name wrapping should be handled elsewhere. Please ensure:

  1. Table names are properly wrapped with quotes as per PR objectives
  2. Documentation is updated to reflect this behavioral change
✅ Verification successful

Let me generate additional scripts to verify the table name wrapping implementation.

The previous search showed a lot of mock calls but not the actual implementation. Let's look specifically at the schema package and foreign key related code to understand how table names are handled.


Let me search for more context around the foreign key and table name handling implementation.

I want to understand how table names are handled in the grammar implementations and if there are any tests that verify this behavior.


Let me check one more thing to understand how the table name wrapping is handled in the grammar implementations.

I want to verify how table names are wrapped and if there's proper handling in the grammar implementations.


Based on the code review, I can now provide a final response about the table name wrapping concern.

Table name wrapping is properly handled in the grammar layer

The review shows that:

  1. The table prefix is correctly applied in multiple layers:

    • In schema layer (database/schema/schema.go): NewBlueprint(r.prefix, table)
    • In specific database implementations (e.g. sqlite_schema.go, postgres_schema.go): table = r.prefix + table
  2. Foreign key references are properly wrapped with the prefix as shown in the SQLite test:

    references "goravel_roles"("id", "user_id")
    references "goravel_permissions"("id", "user_id")
  3. The removal of prefix handling from the On method is correct because:

    • Table name prefixing is handled at the grammar layer
    • The test cases demonstrate proper prefixing of both the main table and referenced tables
    • This aligns with the PR's objective to handle SQL identifiers at the grammar level

No documentation update is needed since this is an internal implementation detail and the behavior remains consistent from the user's perspective.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify table name wrapping implementation and usage

# Search for table name handling patterns
rg -A 3 '\.On\("' 

# Look for potential documentation that needs updating
fd -e md | xargs rg -l "foreign|table.*prefix"

Length of output: 381279


Script:

#!/bin/bash
# Search for table name wrapping implementation in schema package
ast-grep --pattern 'func $name($args) $ret {
  $$$
  $table = $prefix + $table
  $$$
}'

# Search for table name wrapping in foreign key related code
rg -A 5 'func.*On.*table.*string.*ForeignKeyDefinition' 

# Search for table name wrapping tests
rg -A 5 'Test.*ForeignKey.*On'

Length of output: 1356


Script:

#!/bin/bash
# Search for table name wrapping in grammar implementations
rg -A 10 'CompileForeign.*func'

# Look for table prefix handling in grammar files
rg -A 5 'prefix.*table' database/schema/

# Search for foreign key related tests
fd -e go | xargs rg -l 'TestForeignKey|Test.*Foreign.*Key'

Length of output: 5194


Script:

#!/bin/bash
# Look at the SQLite grammar test file for foreign key handling
cat database/schema/grammars/sqlite_test.go

# Check the grammar implementations for table wrapping
rg -A 10 'func.*wrap.*[Tt]able' database/schema/grammars/

# Look for table name handling in the base grammar
rg -A 10 'CompileForeign' database/schema/grammars/grammar.go

Length of output: 7573

database/schema/grammars/wrap.go (3)

1-6: LGTM! Clean package structure and imports.


68-74: LGTM! Correct identifier quoting implementation.

The method properly handles PostgreSQL identifier quoting rules, including proper escaping of double quotes and special handling of wildcards.


54-66: Verify handling of table names with multiple dots.

The current implementation assumes a simple schema.table format, but database objects can have more complex paths (e.g., catalog.schema.table).

database/schema/schema.go (2)

44-44: LGTM: Grammar initialization with prefix parameter.

The changes consistently pass the table prefix to both Postgres and SQLite grammar constructors, which is necessary for proper identifier wrapping in SQL statements.

Also applies to: 52-52


125-125: Verify table name handling edge cases.

While the simplified table name construction works for basic cases, we should verify:

  1. How special characters in prefix/name are handled
  2. If this approach is consistent with table name handling in other methods
  3. If the grammar's Wrap functionality is properly applied when executing the query

Let's verify the table name handling across the codebase:

✅ Verification successful

Based on the analysis of the shell script outputs, I can now provide a final response regarding the table name handling concern:

Direct concatenation of table prefix is safe and consistent

The codebase shows that:

  1. The prefix concatenation pattern is consistently used across the codebase (seen in schema.go, sqlite_schema.go, postgres_schema.go)
  2. Table names are properly escaped/wrapped before being used in SQL queries through the grammar's Wrap functionality (grammars/wrap.go)
  3. The table prefix handling is consistent with the ORM layer (database/gorm/query.go also uses prefix concatenation)

The direct concatenation approach is safe because:

  • Table names are always wrapped/escaped before being used in SQL queries
  • The grammar layer handles proper quoting and escaping of identifiers
  • The same pattern is used consistently across different database drivers
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check table name handling patterns and potential edge cases

# Test 1: Check for other direct prefix concatenations
echo "Checking for direct prefix concatenations..."
rg -A 2 "prefix \+ [a-zA-Z]" --type go

# Test 2: Check for Wrap method usage on table names
echo "Checking for Wrap method usage..."
ast-grep --pattern 'Wrap($table)'

# Test 3: Check for table name handling in tests
echo "Checking test cases for table name handling..."
fd -e go -E vendor --exec rg -l "prefix.*test.*table"

Length of output: 1335


Script:

#!/bin/bash
# Let's verify how table names are used in queries and if they're properly escaped

# Check for query building patterns
echo "Checking query building patterns..."
rg -A 3 "(?i)select.*from.*\b${?table" --type go
rg -A 3 "(?i)create.*table.*\b${?table" --type go

# Check for SQL injection prevention mechanisms
echo "Checking SQL safety mechanisms..."
ast-grep --pattern 'Quote($table)'
ast-grep --pattern 'QuoteIdentifier($table)'
ast-grep --pattern 'Escape($table)'

# Check for table name validation or sanitization
echo "Checking table name validation..."
rg -A 2 "ValidateTable|validateTable|SanitizeTable|sanitizeTable" --type go

# Check test files for prefix handling
echo "Checking test cases for prefix handling..."
fd "_test.go" --exec rg -l "prefix.*table"

Length of output: 175


Script:

#!/bin/bash
# Let's check how table names are handled in queries

# Check for query building patterns with table names
echo "Checking query patterns..."
rg -A 3 'SELECT.*FROM.*\$\{?table' --type go
rg -A 3 'CREATE.*TABLE.*\$\{?table' --type go

# Check grammar.go and related files for table name handling
echo "Checking grammar implementations..."
fd "grammar.*.go" --exec cat {}

# Check for table name related methods
echo "Checking table name methods..."
rg -A 3 "func.*Table" --type go

# Look for SQL builder patterns
echo "Checking SQL builder patterns..."
rg -A 3 "BuildQuery|CompileSelect|CompileCreate" --type go

Length of output: 65111

database/schema/blueprint.go (2)

Line range hint 1-222: Verify implementation of SQL identifier quoting.

While the changes in this file handle table name and index generation well, I don't see the implementation of SQL identifier quoting (wrapping identifiers in quotes) as mentioned in the PR objectives. This might be implemented in the Grammar implementations.

#!/bin/bash
# Description: Look for SQL identifier quoting implementation
# Expect: Find where identifiers are wrapped in quotes

# Search for potential SQL generation with quoted identifiers
rg -l 'fmt\.Sprintf.*"[^"]*".*"' --type go

# Search for Grammar implementations
fd -e go -x grep -l "CompileCreate"

67-67: LGTM! Verify foreign key definition handling.

The removal of prefix parameter from NewForeignKeyDefinition aligns with the architectural changes.

✅ Verification successful

Removal of prefix parameter from NewForeignKeyDefinition is correct

The verification shows that:

  1. NewForeignKeyDefinition takes only a Command parameter and always has
  2. The Command struct contains all necessary fields (Name, References, etc.) to handle foreign key definitions
  3. No prefix field exists in either Command or ForeignKeyDefinition structs

The removal of the prefix parameter is consistent with the codebase structure, as table name handling is managed through the Command struct fields.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify foreign key definition handling in tests
# Expect: Tests should cover the new foreign key definition behavior

rg -l "NewForeignKeyDefinition" --type go

Length of output: 704


Script:

#!/bin/bash
# Let's check the implementation and usage of NewForeignKeyDefinition
ast-grep --pattern 'func NewForeignKeyDefinition($$$) $$ {
  $$$
}'

# Also check for its usages
rg "NewForeignKeyDefinition" -A 3 -B 3

Length of output: 1673


Script:

#!/bin/bash
# Let's check the actual implementation of ForeignKeyDefinition to verify prefix handling
ast-grep --pattern 'type ForeignKeyDefinition struct {
  $$$
}'

# Also check the Command struct to understand how it handles table names
ast-grep --pattern 'type Command struct {
  $$$
}'

Length of output: 1387

database/schema/grammars/sqlite_test.go (3)

22-23: LGTM: Grammar initialization with prefix

The initialization of SQLite grammar with the "goravel_" prefix aligns with the PR's objective of enhancing SQL identifier handling.


58-58: LGTM: Proper identifier wrapping in alter table statement

The test correctly verifies that table names and column names are properly quoted in the alter table statement.


128-129: LGTM: Proper DROP TABLE statement verification

The test correctly verifies that the DROP TABLE statement includes both the table prefix and proper quoting.

database/schema/blueprint_test.go (2)

27-27: LGTM: Grammar initialization with prefix

The initialization of Postgres grammar with the "goravel_" prefix aligns with the PR's objective to enhance SQL syntax handling.


Line range hint 1-290: Verify prefix wrapping in all test methods

Let's ensure that all test methods consistently handle the new wrapping functionality with the "goravel_" prefix.

✅ Verification successful

Let me analyze the test coverage for prefix handling with one more verification to check the actual implementation:


Prefix handling is adequately tested across test methods

The verification shows that prefix handling is properly tested:

  • The prefix is consistently initialized in SetupTest for all test methods
  • Prefix concatenation is explicitly tested in TestCreateIndexName for both simple and schema-qualified tables
  • The implementation in Blueprint correctly handles prefix in all scenarios (simple table names and schema-qualified tables)
  • All test methods inherit the properly initialized prefix from SetupTest
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check if all test methods properly handle the prefix wrapping

# Look for test methods that might need prefix verification
rg -n "func.*Test.*" database/schema/blueprint_test.go

# Check for prefix usage in assertions
rg -n "\"goravel_" database/schema/blueprint_test.go

# Look for potential missing prefix checks
rg -n "s\.Equal\(.*\".*_.*\"" database/schema/blueprint_test.go

Length of output: 1346


Script:

#!/bin/bash
# Check the Blueprint implementation to understand prefix handling
ast-grep --pattern 'func NewBlueprint($_, $_) *Blueprint {
  $$$
}'

# Check for any other prefix-related methods
rg -n "prefix" database/schema/blueprint.go

Length of output: 320

database/schema/grammars/postgres_test.go (7)

22-22: LGTM: Grammar initialization with prefix

The initialization of PostgreSQL grammar with the "goravel_" prefix is correctly implemented and aligns with the PR's objective of standardizing table naming.


41-41: LGTM: Proper identifier quoting in ALTER TABLE statement

The test correctly validates that table and column names are properly quoted in the ALTER TABLE statement.


84-85: LGTM: Proper identifier quoting in CREATE TABLE statement

The test correctly validates that all identifiers (table name and column names) are properly quoted in the CREATE TABLE statement.


128-144: LGTM: Comprehensive foreign key constraint testing

The test cases properly validate foreign key constraints with:

  • Multiple column support
  • Proper identifier quoting
  • Optional ON DELETE/UPDATE clauses

158-198: LGTM: Well-structured index creation tests

The test cases thoroughly validate index creation with:

  • Optional USING clause for index algorithm
  • Proper identifier quoting
  • Multiple column support

200-207: LGTM: Primary key constraint test

The test correctly validates composite primary key creation with proper identifier quoting.


209-232: LGTM: Comprehensive column definition tests

The test thoroughly validates column definition generation with:

  • Serial columns for auto-increment
  • VARCHAR with length specification
  • Default values
  • NULL/NOT NULL constraints
  • Proper identifier quoting
database/schema/grammars/sqlite.go (10)

15-16: Addition of tablePrefix and wrap fields enhances SQL wrapping functionality

The introduction of tablePrefix and wrap fields into the Sqlite struct allows for consistent and flexible wrapping of table and column names with the specified prefix throughout the SQL generation process.


36-36: Ensure r.getColumn handles modifiers correctly

In CompileAdd, after wrapping the table name and getting the column definition, confirm that r.getColumn applies all necessary modifiers to the column definition to generate accurate SQL statements.


41-41: Correct usage of r.wrap.Table in CompileCreate

Using r.wrap.Table(blueprint.GetTableName()) ensures that the table name is properly quoted, adhering to the goal of wrapping identifiers to prevent SQL errors with reserved keywords.


68-68: Proper wrapping of table name in drop statement

In CompileDropIfExists, the table name is correctly wrapped with r.wrap.Table, ensuring that the generated SQL handles table names with special characters or reserved words appropriately.


180-181: Correctly wrapping primary key columns

In addPrimaryKeys, using r.wrap.Columns(command.Columns) ensures that all primary key columns are properly quoted, which aligns with the new wrapping functionality for SQL identifiers.


183-189: Efficient column retrieval with getColumns method

The new getColumns method improves code readability and modularity by centralizing the logic for generating column definitions. This change facilitates easier maintenance and potential future enhancements.


192-199: Accurate construction of column definitions in getColumn

The getColumn method systematically constructs each column's SQL definition, including the application of modifiers. This ensures that all aspects of the column, such as type, default values, and constraints, are correctly reflected in the generated SQL.


204-206: Proper wrapping in foreign key constraints

In the getForeignKey method, using r.wrap to quote table and column names in foreign key definitions ensures that references are accurate and immune to SQL syntax issues related to naming conflicts or reserved words.


19-24: ⚠️ Potential issue

Update constructor NewSqlite to include tablePrefix parameter

The NewSqlite function now requires a tablePrefix argument. Ensure that all instantiations of Sqlite are updated to pass the appropriate tablePrefix to prevent compilation errors and maintain expected behavior.

You can run the following script to identify any calls to NewSqlite that may need updating:

✅ Verification successful

Let me check the actual implementation and usage context of these matches to verify if they are related to the same NewSqlite function.


Review comment is incorrect - different NewSqlite functions

The matches found are for a different NewSqlite function in the processors package (database/schema/processors/sqlite.go), which is unrelated to the NewSqlite constructor in database/schema/grammars/sqlite.go. Let's verify all usages of the grammar's NewSqlite function.


All usages of NewSqlite grammar constructor are properly updated

The only usage of the grammar's NewSqlite constructor is in database/schema/schema.go where it's already being called with the prefix parameter: sqliteGrammar := grammars.NewSqlite(prefix). The other matches found in the previous search were for a different NewSqlite function in the processors package. All code is properly aligned with the constructor's new signature.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Find all usages of NewSqlite without the new parameter
# Expected result: No matches or all usages include the required parameter

rg 'NewSqlite\(\)'

Length of output: 221


Script:

#!/bin/bash
# Check the content of files containing NewSqlite matches
echo "=== database/schema/sqlite_schema.go ==="
cat database/schema/sqlite_schema.go

echo -e "\n=== database/schema/processors/sqlite_test.go ==="
cat database/schema/processors/sqlite_test.go

echo -e "\n=== database/schema/processors/sqlite.go ==="
cat database/schema/processors/sqlite.go

# Also check the imports in these files to ensure we're looking at the right NewSqlite
echo -e "\n=== Checking imports ==="
rg "^import" -A 5 database/schema/sqlite_schema.go database/schema/processors/sqlite_test.go database/schema/processors/sqlite.go

Length of output: 5980


Script:

#!/bin/bash
# Find usages of grammars.NewSqlite
rg "grammars\.NewSqlite" -B 2 -A 2

# Also check for any direct imports and usage of the sqlite grammar
rg '"github.com/goravel/framework/database/schema/grammars"' -B 2 -A 2

Length of output: 2527


88-88: Review replacement of dots in table names

Replacing dots with double underscores using strings.ReplaceAll(table, ".", "__") in CompileIndexes may not be necessary and could lead to incorrect table references. Verify whether this transformation is required, and if so, document the rationale to aid future maintainability.

You can check for table names containing dots with the following script:

✅ Verification successful

The context shows that the dot replacement in table names is specific to SQLite's index compilation, and there's a clear reason for this transformation. Let me generate the final response:

Dot replacement in SQLite table names is necessary and correct

The transformation of dots to double underscores in CompileIndexes is a required SQLite-specific handling. SQLite uses dots for namespacing in its schema queries (as seen in sqlite_master queries), so table names containing dots need to be escaped for proper index creation.

  • The replacement is used only in the SQLite grammar implementation, not in other database drivers
  • It's specifically scoped to index compilation, where table name escaping is critical
  • The codebase shows consistent handling of SQLite table names across schema operations
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Find table names containing dots to assess the need for replacement
# Expected result: List of table names with dots, if any

rg 'create table ["]?\w+[.]\w+["]?'

Length of output: 37


Script:

#!/bin/bash
# Let's search for any usage of table names with dots in the codebase
rg -g '*.go' '"\w+\.\w+"' -A 2 -B 2

# Also search for any other instances where table names with dots are handled
rg -g '*.go' 'ReplaceAll\(.+\"\.\".+\)'

# Let's also check the implementation context of this method
ast-grep --pattern 'func (r $_) CompileIndexes($$$) {
  $$$
}'

Length of output: 132281


Script:

#!/bin/bash
# Let's check the implementation of CompileIndexes and surrounding context
ast-grep --pattern 'func ($r $_) CompileIndexes($table string, $blueprint $_) string {
  $$$
}'

# Let's also check for any other instances where table names with dots are handled in schema-related code
rg -g '*.go' -B 2 -A 2 'strings\.ReplaceAll.*table.*\.'

# And check for any schema-related tests that might provide context
rg -g '*_test.go' 'CompileIndexes.*table'

Length of output: 527


Script:

#!/bin/bash
# Let's check how SQLite tables are handled in the codebase
rg -g '*.go' -B 5 -A 5 'type Sqlite struct'

# Check for any SQLite-specific table handling tests
rg -g '*_test.go' -B 3 -A 3 'sqlite.*table'

# Look for any documentation or comments about SQLite table naming
rg -g '*.go' -A 3 'SQLite.*table|sqlite.*table' -i

# Check for any other instances of table name transformations in SQLite code
ast-grep --pattern 'func ($r *Sqlite) $_($table string, $$$) {
  $$$
}'

Length of output: 6406

database/schema/grammars/postgres.go (10)

16-16: Addition of wrap field to Postgres struct

The inclusion of the wrap field enhances the Postgres struct by encapsulating the logic for wrapping table and column names, improving code organization and maintainability.


35-35: Use wrap methods in CompileAdd for consistent identifier wrapping

The update to use r.wrap.Table() and r.getColumn() in CompileAdd ensures that table and column names are properly quoted, preventing issues with reserved keywords and improving cross-database compatibility.


39-39: Use wrap methods in CompileCreate for consistent identifier wrapping

Applying r.wrap.Table() and r.getColumns() in CompileCreate aligns with the goal of correctly quoting table and column names, enhancing SQL syntax compatibility.


43-43: Consistent use of wrap methods in drop and alter statements

The methods CompileDropAllDomains, CompileDropAllTables, CompileDropAllTypes, CompileDropAllViews, and CompileDropIfExists now utilize r.wrap methods to properly quote identifiers, enhancing SQL syntax correctness and preventing potential conflicts with reserved words.

Also applies to: 47-47, 51-51, 55-55, 59-59


64-68: Verify wrapping of constraint and index names in CompileForeign

While wrapping table and column names is necessary, wrapping constraint and index names (e.g., command.Index) using r.wrap.Column() may not be appropriate. Quoting constraint names could lead to syntax issues in some SQL dialects. Please verify if wrapping constraint names is compatible with the target database systems.

To check for potential issues, review the generated SQL statements for foreign key constraints and test them against your supported databases.


86-89: Assess wrapping of index names in CompileIndex

Wrapping the index name using r.wrap.Column(command.Index) may not be necessary and could cause issues, as index names are identifiers that typically do not require quoting. Verify whether wrapping index names is appropriate and consistent with SQL standards across different databases.

Consider testing the generated index creation statements to ensure they execute successfully on your target database systems.


106-107: Confirm proper usage of r.wrap.Quote() in CompileIndexes

The use of r.wrap.Quote(table) and r.wrap.Quote(schema) ensures that table and schema names are properly quoted in the SQL query. Verify that r.wrap.Quote() handles these names correctly and does not introduce any issues in the context of PostgreSQL.


112-112: Use wrap methods in CompilePrimary for consistent identifier wrapping

Updating CompilePrimary to use r.wrap.Table() and r.wrap.Columns() ensures that identifiers are correctly quoted, aligning with the objective to enhance SQL compatibility by properly wrapping identifiers.


206-224: Addition of getColumns and getColumn methods to centralize column definition logic

The introduction of getColumns and getColumn methods improves code maintainability by centralizing the logic for generating column definitions. This change enhances readability and simplifies future modifications.


19-19: Update NewPostgres constructor to accept tablePrefix parameter

The NewPostgres constructor now requires a tablePrefix parameter and initializes the wrap field with it. Ensure that all instances where NewPostgres is called have been updated to include this new parameter to prevent potential runtime errors.

Run the following script to find all usages of NewPostgres without the tablePrefix argument:

Also applies to: 23-23

✅ Verification successful

Let me verify if these matches are related to the NewPostgres constructor in question by checking the imports and context.


From the results, I can see that the NewPostgres() matches are for a different type in the processors package, not the grammars.NewPostgres constructor we're concerned about. Let me search specifically for usages of the grammar's NewPostgres constructor.


All usages of NewPostgres constructor have been updated with the required tablePrefix parameter

The verification shows that all instances where grammars.NewPostgres is called already include the tablePrefix parameter:

  • schema.go: grammars.NewPostgres(prefix)
  • postgres_schema_test.go: grammars.NewPostgres("goravel_")
  • blueprint_test.go: grammars.NewPostgres("goravel_")

The earlier matches we found were for a different NewPostgres() function in the processors package, not the grammar constructor we're concerned about.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Find all calls to NewPostgres without parameters.

# Test: Search for calls to NewPostgres without any arguments.
rg --fixed-strings 'NewPostgres()' --glob '!database/schema/grammars/postgres.go'

Length of output: 371


Script:

#!/bin/bash
# Check imports and context of the found matches
echo "=== Checking postgres_schema.go ==="
rg -B5 -A5 'NewPostgres\(\)' database/schema/postgres_schema.go

echo -e "\n=== Checking imports in postgres_schema.go ==="
rg '^import \($|^\)' -A 20 database/schema/postgres_schema.go

echo -e "\n=== Checking processors/postgres.go ==="
rg -B5 -A5 'NewPostgres\(\)' database/schema/processors/postgres.go

echo -e "\n=== Checking processors/postgres_test.go ==="
rg -B5 -A5 'NewPostgres\(\)' database/schema/processors/postgres_test.go

Length of output: 2452


Script:

#!/bin/bash
# Search for imports and usages of grammars.NewPostgres
echo "=== Searching for grammars.NewPostgres usage ==="
rg "grammars\.NewPostgres" -B2 -A2

echo -e "\n=== Searching for NewPostgres with package alias ==="
# First find potential package aliases
rg '^\s*"github\.com/goravel/framework/database/schema/grammars"(\s+as\s+(\w+))?' -A1

Length of output: 2377

database/schema/grammars/wrap_test.go Show resolved Hide resolved
database/schema/grammars/wrap.go Show resolved Hide resolved
database/schema/grammars/wrap.go Show resolved Hide resolved
database/schema/grammars/wrap.go Show resolved Hide resolved
Copy link
Member

@kkumar-gcc kkumar-gcc left a comment

Choose a reason for hiding this comment

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

LGTM

@hwbrzzl hwbrzzl merged commit 4f99d56 into master Nov 12, 2024
11 of 12 checks passed
@hwbrzzl hwbrzzl deleted the bowen/#280-19 branch November 12, 2024 14:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants