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

feat(prisma): introduce CreateOrUpdate function #1455

Merged
merged 1 commit into from
Jan 17, 2025

Conversation

ynden
Copy link
Contributor

@ynden ynden commented Jan 16, 2025

Description

UpsertOne is a convenient function when we want to create a record if it doesn't exist, or update it when it does exist. All without having to handle the logic to check whether, or not the record exists. To use it we call this way:

actual, err := client.Post.UpsertOne(
	Post.ID.Equals("upsert"),
	).Create(
		Post.Title.Set("title"),
		Post.Views.Set(1),
	).Update(
		Post.Views.Set(2),
	).Exec(ctx)

However, sometimes we might have the same fields in Create and Update, so we need to use:

actual, err := client.Post.UpsertOne(
	Post.ID.Equals("upsert"),
	).Create(
		Post.Title.Set("title"),
		Post.Views.Set(1),
	).Update(
                 Post.Title.Set("title"),
		Post.Views.Set(1),
	).Exec(ctx)

This now becomes verbose, so we need a way to make it less verbose. This should close #489.

Changelog

  • Introduced new CreateOrUpdate chain that goes with UpsertOne.
  • Configured new test case to handle CreateOrUpdate when record exists, and don't exist.
  • Limited the usage of that function to SQL only (we don't generate the CreateOrUpdate for mongo)

New behaviour

We now can use UpsertOne this way:

actual, err := client.Post.UpsertOne(
	Post.ID.Equals("upsert"),
).CreateOrUpdate(
	Post.Title.Set("title"),
	Post.Views.Set(2),
).Exec(ctx)

This will now automatically create the record if it doesn't exist, otherwise, it'll update the specific record pointed by the where parameter value.

Important note

@steebchen
The current logic makes it that if we pass in a primary key like an ID to Update, it'll fail for mongo database as specified in #1446, hence why we panic for mongo when using CreateOrUpdate

Summary by CodeRabbit

  • New Features

    • Added CreateOrUpdate method for database operations
    • Introduced optional description field for Post model
  • Tests

    • Enhanced test coverage for upsert functionality
    • Added new test cases for CreateOrUpdate method across different database types

Copy link

coderabbitai bot commented Jan 16, 2025

Walkthrough

The pull request introduces a new CreateOrUpdate method in the code generation template for database operations. This method allows for simplified upsert functionality across different database providers (except MongoDB). The changes include updating the Prisma schema to add an optional description field to the Post model and expanding test cases to validate the new CreateOrUpdate method's behavior across different database types.

Changes

File Change Summary
generator/templates/actions/upsert.gotpl Added CreateOrUpdate method to generate upsert functionality for database operations
test/features/upsert/schema.prisma Added optional description String? field to Post model
test/features/upsert/upsert_test.go Added new test cases for CreateOrUpdate method, introduced Databases variable

Assessment against linked issues

Objective Addressed Explanation
Simplify upsert with single data set [#489]

Possibly related PRs

Finishing Touches

  • 📝 Generate Docstrings (Beta)

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 generate docstrings to generate docstrings for this PR. (Beta)
  • @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: 3

🧹 Nitpick comments (2)
test/features/upsert/upsert_test.go (1)

94-153: Add negative test cases.

The test suite should include:

  1. MongoDB provider rejection test
  2. Required field validation test
  3. Error cases (e.g., database errors)

Example test case to add:

{
  name: "CreateOrUpdate with MongoDB should return error",
  run: func(t *testing.T, client *PrismaClient, ctx cx) {
    // Mock MongoDB provider
    client.Engine = &mockMongoEngine{}
    
    _, err := client.Post.UpsertOne(
      Post.ID.Equals("upsert"),
    ).CreateOrUpdate(
      Post.Title.Set("title"),
      Post.Views.Set(0),
    ).Exec(ctx)
    
    if err == nil {
      t.Fatal("expected error for MongoDB provider")
    }
  },
}
test/features/upsert/schema.prisma (1)

14-17: Add field documentation.

Consider adding documentation comments to describe the purpose and constraints of each field, especially the new description field.

 model Post {
-  id          String @id @default(cuid()) @map("_id")
-  title       String
-  views       Int
-  description String?
+  /// Unique identifier for the post
+  id          String  @id @default(cuid()) @map("_id")
+  /// Post title
+  title       String
+  /// Number of post views
+  views       Int
+  /// Optional post description
+  description String?
 }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3e8e069 and 33f4f9d.

📒 Files selected for processing (5)
  • generator/templates/_header.gotpl (1 hunks)
  • generator/templates/actions/upsert.gotpl (1 hunks)
  • generator/templates/client.gotpl (1 hunks)
  • test/features/upsert/schema.prisma (1 hunks)
  • test/features/upsert/upsert_test.go (3 hunks)
✅ Files skipped from review due to trivial changes (1)
  • generator/templates/_header.gotpl
⏰ Context from checks skipped due to timeout of 90000ms (4)
  • GitHub Check: integration-macos
  • GitHub Check: integration-windows
  • GitHub Check: test
  • GitHub Check: lint
🔇 Additional comments (1)
generator/templates/client.gotpl (1)

8-8: Consider handling multiple datasources.

The providerName constant assumes a single datasource by accessing index 0. While this works for the current use case, it might need revision if multiple datasources are supported in the future.

Let's check if multiple datasources are supported or planned:

✅ Verification successful

Accessing first datasource is consistent with current implementation

The codebase consistently uses only the first datasource (Datasources[0]) across multiple files, suggesting this is an intentional design choice rather than an oversight. While the data structure supports multiple datasources, the current implementation expects exactly one datasource.

  • generator/generator.go: Uses r.Datasources[0] in multiple locations
  • generator/templates/client.gotpl: References first datasource
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check if multiple datasources are mentioned in docs or tests
rg -i "multiple.?datasources?" -g "!{vendor,node_modules}/*"

Length of output: 62


Script:

#!/bin/bash
# Check for datasources array definition and usage
ast-grep --pattern 'type $_ struct {
  $$$
  Datasources $$$
  $$$
}'

# Look for array operations on datasources
rg "\.Datasources\[" -A 2

# Find template files that might use datasources
fd "\.gotpl$" --exec grep -l "Datasources"

Length of output: 1379

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

♻️ Duplicate comments (2)
generator/templates/actions/upsert.gotpl (2)

121-123: ⚠️ Potential issue

Consider returning an error instead of panicking.

For better error handling and API design, consider returning an error when MongoDB is detected instead of panicking. This allows API consumers to handle the error gracefully.


112-120: ⚠️ Potential issue

Add validation for required fields.

The method should validate that all required fields are provided and not nil before proceeding with the operation.

🧹 Nitpick comments (1)
test/features/upsert/upsert_test.go (1)

94-116: Add negative test cases.

While the current test cases cover the happy path, consider adding tests for:

  • Invalid/missing required fields
  • MongoDB provider to verify error handling
  • Concurrent upsert operations

Also applies to: 117-153

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 33f4f9d and 39e912b.

📒 Files selected for processing (5)
  • generator/templates/_header.gotpl (1 hunks)
  • generator/templates/actions/upsert.gotpl (1 hunks)
  • generator/templates/client.gotpl (1 hunks)
  • test/features/upsert/schema.prisma (1 hunks)
  • test/features/upsert/upsert_test.go (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • generator/templates/_header.gotpl
  • generator/templates/client.gotpl
  • test/features/upsert/schema.prisma
⏰ Context from checks skipped due to timeout of 90000ms (4)
  • GitHub Check: integration-macos
  • GitHub Check: integration-windows
  • GitHub Check: lint
  • GitHub Check: test
🔇 Additional comments (3)
generator/templates/actions/upsert.gotpl (1)

138-146: LGTM! Efficient field reuse.

The implementation efficiently reuses the same fields for both create and update operations, which aligns well with the PR's objective of reducing verbosity in upsert operations.

test/features/upsert/upsert_test.go (2)

14-18: LGTM! Clear database support definition.

The explicit list of supported databases helps users understand which databases are compatible with the feature.


194-225: LGTM! Comprehensive transaction testing.

The transaction test case properly validates the CreateOrUpdate functionality within a transaction context.

Copy link
Owner

@steebchen steebchen left a comment

Choose a reason for hiding this comment

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

thanks for this!

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

🧹 Nitpick comments (3)
test/features/upsert/upsert_test.go (3)

94-116: LGTM! Good test coverage for creation scenario.

The test properly validates the creation flow and handles generated IDs correctly.

Consider adding edge cases:

  • Empty string values
  • Maximum field lengths
  • Special characters in fields

117-154: LGTM! Comprehensive test for update scenario.

The test thoroughly validates the update flow, including optional fields.

Consider adding test cases for:

  • Updating only a subset of fields
  • Removing optional fields (setting to null)

195-229: LGTM! Good transaction test for CreateOrUpdate.

The test properly validates transaction behavior with CreateOrUpdate.

Consider adding test cases for:

  • Transaction rollback scenarios
  • Concurrent transactions
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 39e912b and bf2dad7.

📒 Files selected for processing (3)
  • generator/templates/actions/upsert.gotpl (1 hunks)
  • test/features/upsert/schema.prisma (1 hunks)
  • test/features/upsert/upsert_test.go (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • test/features/upsert/schema.prisma
  • generator/templates/actions/upsert.gotpl
⏰ Context from checks skipped due to timeout of 90000ms (4)
  • GitHub Check: integration-macos
  • GitHub Check: integration-windows
  • GitHub Check: lint
  • GitHub Check: test
🔇 Additional comments (3)
test/features/upsert/upsert_test.go (3)

192-193: LGTM! Added missing assertion.

Good addition of result validation for the transaction test.


236-236: LGTM! Proper test runner configuration.

The test runner correctly uses the new database configuration while maintaining proper test isolation.


14-18: LGTM! Database configuration aligns with PR objectives.

The database list correctly excludes MongoDB, which aligns with the PR's stated limitation that CreateOrUpdate should panic for MongoDB.

Let's verify that MongoDB is not accidentally used elsewhere:

✅ Verification successful

Verification successful: MongoDB is properly excluded from upsert operations

The codebase correctly handles MongoDB exclusion:

  • The generator template (upsert.gotpl) explicitly excludes MongoDB through conditional statements
  • Test configuration properly omits MongoDB from upsert tests
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for any MongoDB-related configurations or tests
rg -i "mongodb|mongo" .

Length of output: 5043

@steebchen steebchen merged commit b3fa8b4 into steebchen:main Jan 17, 2025
14 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.

allow updating all fields in upsert without re-declaring
2 participants