Skip to content

Conversation

jinzhu
Copy link
Member

@jinzhu jinzhu commented Sep 9, 2025

  • Do only one thing
  • Non breaking API changes
  • Tested

What did this pull request do?

User Case Description


Add Relation Field Helper Types and Association Support in Code Generation

This PR substantially extends GORM CMD's code generation capabilities by introducing first-class support for model associations (relations). It adds new generic relation field helpers (field.Struct[T], field.Slice[T]) to represent single and multiple associations within generated code. The code generator is refactored to automatically detect GORM association types (has one, has many, belongs to, many2many, polymorphic), generate the appropriate helpers, and attach association-aware APIs to models. Association field helpers expose methods for Create, Update, Delete, Unlink, and CreateInBatch that can be composed in parent-side update/mutation operations, including support for batch updates and conditional semantics. The PR also includes major refactoring of the generator internals, documentation overhaul, comprehensive readme updates, new and expanded tests for field and relation semantics, and a GORM dependency upgrade (v1.30.5 → v1.31.0) for full API compatibility.

Key Changes

• Introduced relation field helper types: field.Struct[T], field.Slice[T] in field/relation.go and new API methods in field/association.go
• Refactored code generation (internal/gen/generator.go, internal/gen/utils.go, internal/gen/template.go) to parse and generate association field helpers for all GORM-supported relations
• Removed legacy filtering that skipped association fields, now generates helpers for all detected associations unless excluded by config
• Generated field helpers for associations now expose Create, Update, Delete, Unlink, CreateInBatch, and Where methods, composable for parent-side mutations
• Expanded and updated test suite (examples/output/models_field_helpers_test.go, examples/output/models_relations_test.go) to validate field and association behavior, including CRUD, batch, and edge cases
• Major update and restructuring of documentation (README.md) to clarify association usage, field helper rules, and provide extensive code samples
• Upgrade of GORM dependency from v1.30.5 to v1.31.0 in go.mod and go.sum

Affected Areas

internal/gen/generator.go, internal/gen/template.go, internal/gen/utils.go (core generator logic, AST parsing, templates)
field/relation.go, field/association.go (helper types and association APIs)
examples/output/models_field_helpers_test.go, examples/output/models_relations_test.go (test coverage)
examples/output/models/user.go (generated models now include association helpers)
README.md (usage, semantics, and code example documentation)
go.mod, go.sum (GORM version bump)


This summary was automatically generated by @propel-code-bot

@propel-code-bot propel-code-bot bot changed the title fix parse package path and name Add relation field helper types and support for associations in codegen Sep 9, 2025
Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

Codex Review: Here are some suggestions.

About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you open a pull request for review, mark a draft as ready, or comment "@codex review". If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex fix this CI failure" or "@codex address that feedback".

Comment on lines 59 to +69
return ExtractedSQL{Raw: sql}
}

// ImplementsAllowedInterfaces reports whether typ or *typ implements any allowed interface.
func ImplementsAllowedInterfaces(typ types.Type) bool {
if ptr, ok := typ.(*types.Pointer); ok {
typ = ptr.Elem()
}
for _, t := range allowedInterfaces {
iface, _ := t.Underlying().(*types.Interface)
if types.Implements(typ, iface) || types.Implements(types.NewPointer(typ), iface) {

Choose a reason for hiding this comment

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

[P1] Guard nil entries in allowedInterfaces before calling Underlying

The global allowedInterfaces slice is initialized with the return values of four loadNamedType calls. If any of those packages fail to load (common when running the generator offline or before modules are downloaded), the slice will contain nil. ImplementsAllowedInterfaces iterates that slice and immediately calls t.Underlying() on each entry, which will panic on a nil pointer before the generator even starts. The previous implementation appended interfaces only when they were successfully loaded, so it degraded gracefully. Consider filtering out nils or adding a nil check before dereferencing to avoid panics when the dependency cannot be resolved.

Useful? React with 👍 / 👎.

@jinzhu jinzhu merged commit bce396f into master Sep 12, 2025
1 check passed
@jinzhu jinzhu deleted the relation_support branch September 12, 2025 08:13
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.

1 participant