Skip to content

Commit

Permalink
Added ContextualMods, moved Hooks and QueryModFunc to base package
Browse files Browse the repository at this point in the history
  • Loading branch information
stephenafamo committed Oct 18, 2024
1 parent 97e2d81 commit d21c6fc
Show file tree
Hide file tree
Showing 42 changed files with 400 additions and 316 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- Added error constants for matching against both specific and generic unique constraint errors raised by the underlying database driver. (thanks @mbezhanov)
- Added support for regular expressions in the `only` and `except` table filters. (thanks @mbezhanov)
- Added `ContextualMods` which are similar to regular mods but take a context argument. They are applied whenever the query is built.
This makes it cleaner to do certain things, like populating the select columns of a model if none was explicitly added.
The previous way this was done was unreliable since using `q.MustBuild()` would not add the columns while `bob.MustBuild(q)` will add them correctly.

### Changed

Expand All @@ -53,6 +56,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- The `Name()` and `NameAs()` methods of Views/Tables no longer need the context argument since the context will be passed when writing the expression. The API then becomes cleaner.
- Preloading mods no longer need to store a context internally. `SetLoadContext()` and `GetLoadContext()` have removed.
- The `ToExpr` field in `orm.RelSide` which was used for preloading is no longer needed and has been removed.
- Moved `orm.Hooks` to `bob.Hooks` since it should not be limited to only ORM queries.
- Moved `mods.QueryModFunc` to `bob.ModFunc` since it should be available to all packages.

### Removed

Expand Down
75 changes: 37 additions & 38 deletions dialect/mysql/dialect/hints.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (
"strings"

"github.com/stephenafamo/bob"
"github.com/stephenafamo/bob/mods"
)

type hints struct {
Expand All @@ -26,259 +25,259 @@ type hintable interface{ AppendHint(string) }

func QBName[Q hintable](name string) bob.Mod[Q] {
hint := fmt.Sprintf("QB_NAME(%s)", name)
return mods.QueryModFunc[Q](func(q Q) {
return bob.ModFunc[Q](func(q Q) {
q.AppendHint(hint)
})
}

func SetVar[Q hintable](statement string) bob.Mod[Q] {
hint := fmt.Sprintf("SET_VAR(%s)", statement)
return mods.QueryModFunc[Q](func(q Q) {
return bob.ModFunc[Q](func(q Q) {
q.AppendHint(hint)
})
}

func MaxExecutionTime[Q hintable](n int) bob.Mod[Q] {
hint := fmt.Sprintf("MAX_EXECUTION_TIME(%d)", n)
return mods.QueryModFunc[Q](func(q Q) {
return bob.ModFunc[Q](func(q Q) {
q.AppendHint(hint)
})
}

func ResourceGroup[Q hintable](name string) bob.Mod[Q] {
hint := fmt.Sprintf("RESOURCE_GROUP(%s)", name)
return mods.QueryModFunc[Q](func(q Q) {
return bob.ModFunc[Q](func(q Q) {
q.AppendHint(hint)
})
}

func BKA[Q hintable](tables ...string) bob.Mod[Q] {
hint := fmt.Sprintf("BKA(%s)", strings.Join(tables, ", "))
return mods.QueryModFunc[Q](func(q Q) {
return bob.ModFunc[Q](func(q Q) {
q.AppendHint(hint)
})
}

func NoBKA[Q hintable](tables ...string) bob.Mod[Q] {
hint := fmt.Sprintf("NO_BKA(%s)", strings.Join(tables, ", "))
return mods.QueryModFunc[Q](func(q Q) {
return bob.ModFunc[Q](func(q Q) {
q.AppendHint(hint)
})
}

func BNL[Q hintable](tables ...string) bob.Mod[Q] {
hint := fmt.Sprintf("BNL(%s)", strings.Join(tables, ", "))
return mods.QueryModFunc[Q](func(q Q) {
return bob.ModFunc[Q](func(q Q) {
q.AppendHint(hint)
})
}

func NoBNL[Q hintable](tables ...string) bob.Mod[Q] {
hint := fmt.Sprintf("NO_BNL(%s)", strings.Join(tables, ", "))
return mods.QueryModFunc[Q](func(q Q) {
return bob.ModFunc[Q](func(q Q) {
q.AppendHint(hint)
})
}

func DerivedConditionPushdown[Q hintable](tables ...string) bob.Mod[Q] {
hint := fmt.Sprintf("DERIVED_CONDITION_PUSHDOWN(%s)", strings.Join(tables, ", "))
return mods.QueryModFunc[Q](func(q Q) {
return bob.ModFunc[Q](func(q Q) {
q.AppendHint(hint)
})
}

func NoDerivedConditionPushdown[Q hintable](tables ...string) bob.Mod[Q] {
hint := fmt.Sprintf("NO_DERIVED_CONDITION_PUSHDOWN(%s)", strings.Join(tables, ", "))
return mods.QueryModFunc[Q](func(q Q) {
return bob.ModFunc[Q](func(q Q) {
q.AppendHint(hint)
})
}

func HashJoin[Q hintable](tables ...string) bob.Mod[Q] {
hint := fmt.Sprintf("HASH_JOIN(%s)", strings.Join(tables, ", "))
return mods.QueryModFunc[Q](func(q Q) {
return bob.ModFunc[Q](func(q Q) {
q.AppendHint(hint)
})
}

func NoHashJoin[Q hintable](tables ...string) bob.Mod[Q] {
hint := fmt.Sprintf("NO_HASH_JOIN(%s)", strings.Join(tables, ", "))
return mods.QueryModFunc[Q](func(q Q) {
return bob.ModFunc[Q](func(q Q) {
q.AppendHint(hint)
})
}

func Merge[Q hintable](tables ...string) bob.Mod[Q] {
hint := fmt.Sprintf("MERGE(%s)", strings.Join(tables, ", "))
return mods.QueryModFunc[Q](func(q Q) {
return bob.ModFunc[Q](func(q Q) {
q.AppendHint(hint)
})
}

func NoMerge[Q hintable](tables ...string) bob.Mod[Q] {
hint := fmt.Sprintf("NO_MERGE(%s)", strings.Join(tables, ", "))
return mods.QueryModFunc[Q](func(q Q) {
return bob.ModFunc[Q](func(q Q) {
q.AppendHint(hint)
})
}

func Index[Q hintable](tables ...string) bob.Mod[Q] {
hint := fmt.Sprintf("INDEX(%s)", strings.Join(tables, ", "))
return mods.QueryModFunc[Q](func(q Q) {
return bob.ModFunc[Q](func(q Q) {
q.AppendHint(hint)
})
}

func NoIndex[Q hintable](tables ...string) bob.Mod[Q] {
hint := fmt.Sprintf("NO_INDEX(%s)", strings.Join(tables, ", "))
return mods.QueryModFunc[Q](func(q Q) {
return bob.ModFunc[Q](func(q Q) {
q.AppendHint(hint)
})
}

func GroupIndex[Q hintable](tables ...string) bob.Mod[Q] {
hint := fmt.Sprintf("GROUP_INDEX(%s)", strings.Join(tables, ", "))
return mods.QueryModFunc[Q](func(q Q) {
return bob.ModFunc[Q](func(q Q) {
q.AppendHint(hint)
})
}

func NoGroupIndex[Q hintable](tables ...string) bob.Mod[Q] {
hint := fmt.Sprintf("NO_GROUP_INDEX(%s)", strings.Join(tables, ", "))
return mods.QueryModFunc[Q](func(q Q) {
return bob.ModFunc[Q](func(q Q) {
q.AppendHint(hint)
})
}

func JoinIndex[Q hintable](tables ...string) bob.Mod[Q] {
hint := fmt.Sprintf("JOIN_INDEX(%s)", strings.Join(tables, ", "))
return mods.QueryModFunc[Q](func(q Q) {
return bob.ModFunc[Q](func(q Q) {
q.AppendHint(hint)
})
}

func NoJoinIndex[Q hintable](tables ...string) bob.Mod[Q] {
hint := fmt.Sprintf("NO_JOIN_INDEX(%s)", strings.Join(tables, ", "))
return mods.QueryModFunc[Q](func(q Q) {
return bob.ModFunc[Q](func(q Q) {
q.AppendHint(hint)
})
}

func OrderIndex[Q hintable](tables ...string) bob.Mod[Q] {
hint := fmt.Sprintf("ORDER_INDEX(%s)", strings.Join(tables, ", "))
return mods.QueryModFunc[Q](func(q Q) {
return bob.ModFunc[Q](func(q Q) {
q.AppendHint(hint)
})
}

func NoOrderIndex[Q hintable](tables ...string) bob.Mod[Q] {
hint := fmt.Sprintf("NO_ORDER_INDEX(%s)", strings.Join(tables, ", "))
return mods.QueryModFunc[Q](func(q Q) {
return bob.ModFunc[Q](func(q Q) {
q.AppendHint(hint)
})
}

func IndexMerge[Q hintable](tables ...string) bob.Mod[Q] {
hint := fmt.Sprintf("INDEX_MERGE(%s)", strings.Join(tables, ", "))
return mods.QueryModFunc[Q](func(q Q) {
return bob.ModFunc[Q](func(q Q) {
q.AppendHint(hint)
})
}

func NoIndexMerge[Q hintable](tables ...string) bob.Mod[Q] {
hint := fmt.Sprintf("NO_INDEX_MERGE(%s)", strings.Join(tables, ", "))
return mods.QueryModFunc[Q](func(q Q) {
return bob.ModFunc[Q](func(q Q) {
q.AppendHint(hint)
})
}

func MRR[Q hintable](tables ...string) bob.Mod[Q] {
hint := fmt.Sprintf("MRR(%s)", strings.Join(tables, ", "))
return mods.QueryModFunc[Q](func(q Q) {
return bob.ModFunc[Q](func(q Q) {
q.AppendHint(hint)
})
}

func NoMRR[Q hintable](tables ...string) bob.Mod[Q] {
hint := fmt.Sprintf("NO_MRR(%s)", strings.Join(tables, ", "))
return mods.QueryModFunc[Q](func(q Q) {
return bob.ModFunc[Q](func(q Q) {
q.AppendHint(hint)
})
}

func NoICP[Q hintable](tables ...string) bob.Mod[Q] {
hint := fmt.Sprintf("NO_ICP(%s)", strings.Join(tables, ", "))
return mods.QueryModFunc[Q](func(q Q) {
return bob.ModFunc[Q](func(q Q) {
q.AppendHint(hint)
})
}

func NoRangeOptimazation[Q hintable](tables ...string) bob.Mod[Q] {
hint := fmt.Sprintf("NO_RANGE_OPTIMAZATION(%s)", strings.Join(tables, ", "))
return mods.QueryModFunc[Q](func(q Q) {
return bob.ModFunc[Q](func(q Q) {
q.AppendHint(hint)
})
}

func SkipScan[Q hintable](tables ...string) bob.Mod[Q] {
hint := fmt.Sprintf("SKIP_SCAN(%s)", strings.Join(tables, ", "))
return mods.QueryModFunc[Q](func(q Q) {
return bob.ModFunc[Q](func(q Q) {
q.AppendHint(hint)
})
}

func NoSkipScan[Q hintable](tables ...string) bob.Mod[Q] {
hint := fmt.Sprintf("NO_SKIP_SCAN(%s)", strings.Join(tables, ", "))
return mods.QueryModFunc[Q](func(q Q) {
return bob.ModFunc[Q](func(q Q) {
q.AppendHint(hint)
})
}

func Semijoin[Q hintable](strategy ...string) bob.Mod[Q] {
hint := fmt.Sprintf("SEMIJOIN(%s)", strings.Join(strategy, ", "))
return mods.QueryModFunc[Q](func(q Q) {
return bob.ModFunc[Q](func(q Q) {
q.AppendHint(hint)
})
}

func NoSemijoin[Q hintable](strategy ...string) bob.Mod[Q] {
hint := fmt.Sprintf("NO_SEMIJOIN(%s)", strings.Join(strategy, ", "))
return mods.QueryModFunc[Q](func(q Q) {
return bob.ModFunc[Q](func(q Q) {
q.AppendHint(hint)
})
}

func Subquery[Q hintable](strategy string) bob.Mod[Q] {
hint := fmt.Sprintf("SUBQUERY(%s)", strategy)
return mods.QueryModFunc[Q](func(q Q) {
return bob.ModFunc[Q](func(q Q) {
q.AppendHint(hint)
})
}

func JoinFixedOrder[Q hintable](name string) bob.Mod[Q] {
hint := fmt.Sprintf("JOIN_FIXED_ORDER(%s)", name)
return mods.QueryModFunc[Q](func(q Q) {
return bob.ModFunc[Q](func(q Q) {
q.AppendHint(hint)
})
}

func JoinOrder[Q hintable](tables ...string) bob.Mod[Q] {
hint := fmt.Sprintf("JOIN_ORDER(%s)", strings.Join(tables, ", "))
return mods.QueryModFunc[Q](func(q Q) {
return bob.ModFunc[Q](func(q Q) {
q.AppendHint(hint)
})
}

func JoinPrefix[Q hintable](tables ...string) bob.Mod[Q] {
hint := fmt.Sprintf("JOIN_PREFIX(%s)", strings.Join(tables, ", "))
return mods.QueryModFunc[Q](func(q Q) {
return bob.ModFunc[Q](func(q Q) {
q.AppendHint(hint)
})
}

func JoinSuffix[Q hintable](tables ...string) bob.Mod[Q] {
hint := fmt.Sprintf("JOIN_SUFFIX(%s)", strings.Join(tables, ", "))
return mods.QueryModFunc[Q](func(q Q) {
return bob.ModFunc[Q](func(q Q) {
q.AppendHint(hint)
})
}
2 changes: 1 addition & 1 deletion dialect/mysql/dialect/mods.go
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ func (f FromChain[Q]) ForceIndexForGroupBy(first string, others ...string) FromC
}

func Partition[Q interface{ AppendPartition(...string) }](partitions ...string) bob.Mod[Q] {
return mods.QueryModFunc[Q](func(q Q) {
return bob.ModFunc[Q](func(q Q) {
q.AppendPartition(partitions...)
})
}
Expand Down
5 changes: 5 additions & 0 deletions dialect/mysql/dialect/select.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ type SelectQuery struct {
clause.Offset
clause.For
bob.Load
bob.ContextualModdable[*SelectQuery]
}

func (s *SelectQuery) SetInto(i any) {
Expand All @@ -39,6 +40,10 @@ func (s SelectQuery) WriteSQL(ctx context.Context, w io.Writer, d bob.Dialect, s
var args []any
var err error

if ctx, err = s.RunContextualMods(ctx, &s); err != nil {
return nil, err
}

withArgs, err := bob.ExpressIf(ctx, w, d, start+len(args), s.With,
len(s.With.CTEs) > 0, "\n", "")
if err != nil {
Expand Down
10 changes: 5 additions & 5 deletions dialect/mysql/dm/qm.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,25 +16,25 @@ func Recursive(r bool) bob.Mod[*dialect.DeleteQuery] {
}

func LowPriority() bob.Mod[*dialect.DeleteQuery] {
return mods.QueryModFunc[*dialect.DeleteQuery](func(i *dialect.DeleteQuery) {
return bob.ModFunc[*dialect.DeleteQuery](func(i *dialect.DeleteQuery) {
i.AppendModifier("LOW_PRIORITY")
})
}

func Quick() bob.Mod[*dialect.DeleteQuery] {
return mods.QueryModFunc[*dialect.DeleteQuery](func(i *dialect.DeleteQuery) {
return bob.ModFunc[*dialect.DeleteQuery](func(i *dialect.DeleteQuery) {
i.AppendModifier("QUICK")
})
}

func Ignore() bob.Mod[*dialect.DeleteQuery] {
return mods.QueryModFunc[*dialect.DeleteQuery](func(i *dialect.DeleteQuery) {
return bob.ModFunc[*dialect.DeleteQuery](func(i *dialect.DeleteQuery) {
i.AppendModifier("IGNORE")
})
}

func From(name any, partitions ...string) bob.Mod[*dialect.DeleteQuery] {
return mods.QueryModFunc[*dialect.DeleteQuery](func(u *dialect.DeleteQuery) {
return bob.ModFunc[*dialect.DeleteQuery](func(u *dialect.DeleteQuery) {
u.Tables = append(u.Tables, clause.Table{
Expression: name,
Partitions: partitions,
Expand All @@ -43,7 +43,7 @@ func From(name any, partitions ...string) bob.Mod[*dialect.DeleteQuery] {
}

func FromAs(name any, alias string, partitions ...string) bob.Mod[*dialect.DeleteQuery] {
return mods.QueryModFunc[*dialect.DeleteQuery](func(u *dialect.DeleteQuery) {
return bob.ModFunc[*dialect.DeleteQuery](func(u *dialect.DeleteQuery) {
u.Tables = append(u.Tables, clause.Table{
Expression: name,
Alias: alias,
Expand Down
Loading

0 comments on commit d21c6fc

Please sign in to comment.