Skip to content

Add WhereHas and WhereDoesntHave helpers for relationship filtering#7642

Open
vzaica wants to merge 10 commits intogo-gorm:masterfrom
vzaica:feature/where-has
Open

Add WhereHas and WhereDoesntHave helpers for relationship filtering#7642
vzaica wants to merge 10 commits intogo-gorm:masterfrom
vzaica:feature/where-has

Conversation

@vzaica
Copy link
Copy Markdown

@vzaica vzaica commented Nov 7, 2025

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

This PR covers #3871 feature request.

What did this pull request do?

This PR adds two new query helper methods — WhereHas and WhereDoesntHave.
These methods make it possible to filter query results based on related models, similar to how this is done in frameworks like Laravel Eloquent.

Problem

Currently, GORM lacks convenient methods for filtering records by the existence (or absence) of related entities.
For example, there is no built-in way to express queries like:

DB.WhereHas("Toys", DB.Where("type = ?", "car")).Find(&users)

or the inverse case using WhereDoesntHave.

As a result, developers must write verbose raw joins or subqueries, which reduces readability and reusability.

Solution

This PR introduces:

  • WhereHas(association string, args ...interface{}).
    Filters parent records that have related models matching the scope.
  • WhereDoesntHave(association string, args ...interface{})
    Filters parent records that do not have related models matching the scope.

These methods apply only to query building (e.g., SELECT) and do not affect update/insert logic.

Implementation notes

  • Implemented as query scopes that inject appropriate subqueries into WHERE EXISTS (...) or WHERE NOT EXISTS (...) clauses.
  • Tested against nested associations and multiple joins.
  • Does not modify core model update/insert logic.

User Case Description

Assume the following model structure:

type User struct {
	gorm.Model
	Name      string
	Pets      []*Pet
	Toys      []Toy   `gorm:"polymorphic:Owner"`
}

type Pet struct {
	gorm.Model
	UserID *uint
	Name   string
	Toy    Toy `gorm:"polymorphic:Owner;"`
}

type Toy struct {
	gorm.Model
	Name      string
	Type      string
	OwnerID   string
	OwnerType string
}

1. Basic WhereHas

Find all users who have pets:

var users []User
DB.WhereHas("Pets").Find(&users)

2. Basic WhereDoesntHave

Find all users who don’t have pets:

var users []User
DB.WhereDoesntHave("Pets").Find(&users)

3. Conditional WhereHas

Find all users who have toys of a specific type:

var users []User
DB.WhereHas("Toys", DB.Where("type = ?", "car")).Find(&users)

4. Nested WhereHas

Find all users who have pets without toys:

var users []User
DB.WhereHas("Pets", DB.WhereDoesntHave("Toy")).Find(&users)

@propel-code-bot
Copy link
Copy Markdown
Contributor

propel-code-bot bot commented Nov 7, 2025

These helpers hook directly into GORM’s chainable API by recording per-statement relationship predicates that are materialized as EXISTS/NOT EXISTS subqueries for every association type, including polymorphic chains, while cloning/merging safeguards and metadata checks ensure the scopes remain stable across nested queries and dry-run flows validated by the new regression suite.

Affected Areas

chainable_api.go query builder surface
statement.go state management and cloning
where_has.go new relation subquery builder
callbacks/query.go SQL build pipeline
tests/query_where_has_test.go integration tests

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

@propel-code-bot propel-code-bot bot changed the title add whereHas/whereDoesntHave methods for Query Add WhereHas and WhereDoesntHave relational filters to query API Nov 7, 2025
@propel-code-bot propel-code-bot bot changed the title Add WhereHas and WhereDoesntHave relational filters to query API Add WhereHas and WhereDoesntHave helpers for relationship filtering Nov 9, 2025
@vzaica vzaica marked this pull request as draft February 15, 2026 09:29
@vzaica vzaica marked this pull request as ready for review February 15, 2026 10:18
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