Feat: optimize performance on hot paths and reduce allocations#51
Merged
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
1-runtime:
- Avoid Interface dispatch on hot paths, use a struct embedded in the Queries struct, and flattened-out props
- Replace Dialect interface with a struct, holding dialect sepecific functions and keywords for an easily-extensible workflow
- Define WriteQuotedIdent(), WritePlaceholder() reciever methods on Dialect, zero alloc, writes directly in the string builder
- Define Quote, BindVar(), FormatLimitOffset() methods on Dialect
- define BuildConflictClause() as Dialect method using field-based conflict keywords
2-client:
- define a mutex on the Queries struct, stmtCache, to prepare and cache sql queries, dialect sepcific quoteChar, and placeholderFmt to prevent interface dispatch on hot paths (should be made into a dialect struct embedded in the Queries struct for future extensibility)
- define Prepare() with Rlocks/unlocks, use it in query() and queryRow()
- remove postgresDialect/sqliteDialect types and old Queries.dialect field
3- builders_create:
-remove generic executeInsert, executeCreateMany/AndReturn, remove groupRowMapsByKeys() and partitionRowMaps(), that takes a []map[string]any as it is model-specific now
4- builders_query:
- remove generic executeFindOne/FindMany, executeSingle/ManyWithRelations
5- model_create:
- inline executeCreate, executeCreateMany/AndReturn, early return direct d.runCreate path when no extensions, closure onion when extensions present
- define runCreate, runCreateFallback, runCreateMany, runCreateManyAndReturn (model-specific SQL execution)
- define buildBulkInsertSQL using run-time colMask union (no generic []map[string]any)
- define partitionXXInputs using colMask (dialect-aware, no generics)
- remove pkCols inline slice literal, use package-level {{ lowercase .Model.Name }}PKCols
6- model_query:
- add early return check on executeFindUnique/FindFirst/FindMany for if no extensions were present in the exec functions, it executes the underlying exec function, or define a closure, handles extensions (onion pattern), then execute the underlying exec function if there were any extensions present
- define shared queryOne() and queryMany() for single and bulk ops without duplication
7- relations_runtime.gotpl:
- remove generic buildBulkInsertSQL, mapToColsVals
- buildSingleInsertSQL uses Dialect.WriteQuotedIdent/WritePlaceholder/BuildConflictClause
8-model_structs:
- define colMask() that returns a bit mask of columns that are set, prevents extra allocation for no reason
- move PKCols to be a package level var instead of re-defining on each query for bulk ops, saves some alloc
9- generator/helpers:
- fix isKnownDefaultFunc to skip empty-string entries