Skip to content

Commit fd9227a

Browse files
authored
feat(fxorm): Provided module (ankorstore#36)
1 parent 74979af commit fd9227a

File tree

14 files changed

+1528
-0
lines changed

14 files changed

+1528
-0
lines changed

.github/workflows/coverage.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ jobs:
3434
- "fxhealthcheck"
3535
- "fxlog"
3636
- "fxmetrics"
37+
- "fxorm"
3738
- "fxtrace"
3839
steps:
3940
- name: Checkout

.github/workflows/fxorm-ci.yml

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
name: "fxorm-ci"
2+
3+
on:
4+
push:
5+
branches:
6+
- "feat**"
7+
- "fix**"
8+
- "hotfix**"
9+
- "chore**"
10+
paths:
11+
- "fxorm/**.go"
12+
- "fxorm/go.mod"
13+
- "fxorm/go.sum"
14+
pull_request:
15+
types:
16+
- opened
17+
- synchronize
18+
- reopened
19+
branches:
20+
- main
21+
paths:
22+
- "fxorm/**.go"
23+
- "fxorm/go.mod"
24+
- "fxorm/go.sum"
25+
26+
jobs:
27+
ci:
28+
uses: ./.github/workflows/common-ci.yml
29+
secrets: inherit
30+
with:
31+
module: "fxorm"

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ Yokai's `Fx modules` are the plugins for your Yokai application.
2727
| [fxhealthcheck](fxhealthcheck) | Fx module for [healthcheck](healthcheck) |
2828
| [fxlog](fxlog) | Fx module for [log](log) |
2929
| [fxmetrics](fxmetrics) | Fx module for [prometheus](https://github.com/prometheus/client_golang) |
30+
| [fxorm](fxorm) | Fx module for [orm](orm) |
3031
| [fxtrace](fxtrace) | Fx module for [trace](trace) |
3132

3233
They can also be used in any [Fx](https://github.com/uber-go/fx) based Go application.

fxorm/.golangci.yml

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
run:
2+
timeout: 5m
3+
concurrency: 8
4+
5+
linters:
6+
enable:
7+
- asasalint
8+
- asciicheck
9+
- bidichk
10+
- bodyclose
11+
- containedctx
12+
- contextcheck
13+
- decorder
14+
- dogsled
15+
- durationcheck
16+
- errcheck
17+
- errchkjson
18+
- errname
19+
- errorlint
20+
- forbidigo
21+
- forcetypeassert
22+
- gocognit
23+
- goconst
24+
- gocritic
25+
- gocyclo
26+
- godot
27+
- godox
28+
- gofmt
29+
- goheader
30+
- gomoddirectives
31+
- gomodguard
32+
- goprintffuncname
33+
- gosec
34+
- gosimple
35+
- govet
36+
- grouper
37+
- importas
38+
- ineffassign
39+
- interfacebloat
40+
- logrlint
41+
- maintidx
42+
- makezero
43+
- misspell
44+
- nestif
45+
- nilerr
46+
- nilnil
47+
- nlreturn
48+
- nolintlint
49+
- nosprintfhostport
50+
- prealloc
51+
- predeclared
52+
- promlinter
53+
- reassign
54+
- staticcheck
55+
- tenv
56+
- thelper
57+
- tparallel
58+
- typecheck
59+
- unconvert
60+
- unparam
61+
- unused
62+
- usestdlibvars
63+
- whitespace

fxorm/README.md

Lines changed: 244 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,244 @@
1+
# Fx ORM Module
2+
3+
[![ci](https://github.com/ankorstore/yokai/actions/workflows/fxorm-ci.yml/badge.svg)](https://github.com/ankorstore/yokai/actions/workflows/fxorm-ci.yml)
4+
[![go report](https://goreportcard.com/badge/github.com/ankorstore/yokai/fxorm)](https://goreportcard.com/report/github.com/ankorstore/yokai/fxorm)
5+
[![codecov](https://codecov.io/gh/ankorstore/yokai/graph/badge.svg?token=ghUBlFsjhR&flag=fxorm)](https://app.codecov.io/gh/ankorstore/yokai/tree/main/fxorm)
6+
[![Deps](https://img.shields.io/badge/osi-deps-blue)](https://deps.dev/go/github.com%2Fankorstore%2Fyokai%2Ffxorm)
7+
[![PkgGoDev](https://pkg.go.dev/badge/github.com/ankorstore/yokai/fxorm)](https://pkg.go.dev/github.com/ankorstore/yokai/fxorm)
8+
9+
> [Fx](https://uber-go.github.io/fx/) module for [orm](https://github.com/ankorstore/yokai/tree/main/orm).
10+
11+
<!-- TOC -->
12+
* [Installation](#installation)
13+
* [Documentation](#documentation)
14+
* [Dependencies](#dependencies)
15+
* [Loading](#loading)
16+
* [Configuration](#configuration)
17+
* [Auto migrations](#auto-migrations)
18+
* [Performance](#performance)
19+
* [Disable Default Transaction](#disable-default-transaction)
20+
* [Cache Prepared Statement](#cache-prepared-statement)
21+
* [Override](#override)
22+
<!-- TOC -->
23+
24+
## Installation
25+
26+
```shell
27+
go get github.com/ankorstore/yokai/fxorm
28+
```
29+
30+
## Documentation
31+
32+
### Dependencies
33+
34+
This module is intended to be used alongside:
35+
36+
- the [fxconfig](https://github.com/ankorstore/yokai/tree/main/fxconfig) module
37+
- the [fxlog](https://github.com/ankorstore/yokai/tree/main/fxlog) module
38+
- the [fxtrace](https://github.com/ankorstore/yokai/tree/main/fxtrace) module
39+
40+
### Loading
41+
42+
To load the module in your Fx application:
43+
44+
```go
45+
package main
46+
47+
import (
48+
"github.com/ankorstore/yokai/fxconfig"
49+
"github.com/ankorstore/yokai/fxlog"
50+
"github.com/ankorstore/yokai/fxorm"
51+
"github.com/ankorstore/yokai/fxtrace"
52+
"go.uber.org/fx"
53+
"gorm.io/gorm"
54+
)
55+
56+
type Model struct {
57+
Name string
58+
}
59+
60+
func main() {
61+
fx.New(
62+
fxconfig.FxConfigModule, // load the module dependencies
63+
fxlog.FxLogModule,
64+
fxtrace.FxTraceModule,
65+
fxorm.FxOrmModule, // load the module
66+
fx.Invoke(func(db *gorm.DB) { // invoke the orm
67+
db.Create(&Model{Name: "some name"})
68+
}),
69+
).Run()
70+
}
71+
```
72+
73+
### Configuration
74+
75+
This module provides the possibility to configure the ORM `driver`:
76+
77+
- `sqlite` for SQLite databases
78+
- `mysql` for MySQL databases
79+
- `postgres` for PostgreSQL databases
80+
- `sqlserver` for SQL Server databases
81+
82+
You can also provide to the ORM the database`dsn`, some `config`, and configure SQL queries `logging` and `tracing`.
83+
84+
```yaml
85+
# ./configs/config.yaml
86+
app:
87+
name: app
88+
env: dev
89+
version: 0.1.0
90+
debug: false
91+
modules:
92+
orm:
93+
driver: mysql # driver to use
94+
dsn: user:pass@tcp(127.0.0.1:3306)/dbname?parseTime=True" # database DSN to connect to
95+
config:
96+
dry_run: false # disabled by default
97+
skip_default_transaction: false # disabled by default
98+
full_save_associations: false # disabled by default
99+
prepare_stmt: false # disabled by default
100+
disable_automatic_ping: false # disabled by default
101+
disable_foreign_key_constraint_when_migrating: false # disabled by default
102+
ignore_relationships_when_migrating: false # disabled by default
103+
disable_nested_transaction: false # disabled by default
104+
allow_global_update: false # disabled by default
105+
query_fields: false # disabled by default
106+
translate_error: false # disabled by default
107+
log:
108+
enabled: true # to log SQL queries, disabled by default
109+
level: info # with a minimal level
110+
values: true # by adding or not clear SQL queries parameters values in logs, disabled by default
111+
trace:
112+
enabled: true # to trace SQL queries, disabled by default
113+
values: true # by adding or not clear SQL queries parameters values in trace spans, disabled by default
114+
```
115+
116+
See [Gorm Config](https://github.com/go-gorm/gorm/blob/master/gorm.go) for more details about the configuration.
117+
118+
### Auto migrations
119+
120+
This module provides the possibility to run automatically your [schemas migrations](https://gorm.io/docs/migration.html)
121+
with `RunFxOrmAutoMigrate()`:
122+
123+
```go
124+
package main
125+
126+
import (
127+
"github.com/ankorstore/yokai/fxconfig"
128+
"github.com/ankorstore/yokai/fxlog"
129+
"github.com/ankorstore/yokai/fxorm"
130+
"github.com/ankorstore/yokai/fxtrace"
131+
"go.uber.org/fx"
132+
"gorm.io/gorm"
133+
)
134+
135+
type Model struct {
136+
Name string
137+
}
138+
139+
func main() {
140+
fx.New(
141+
fxconfig.FxConfigModule, // load the module dependencies
142+
fxlog.FxLogModule,
143+
fxtrace.FxTraceModule,
144+
fxorm.FxOrmModule, // load the module
145+
fxorm.RunFxOrmAutoMigrate(&Model{}), // run auto migration for Model
146+
fx.Invoke(func(db *gorm.DB) { // invoke the orm
147+
db.Create(&Model{Name: "some name"})
148+
}),
149+
).Run()
150+
}
151+
```
152+
153+
### Performance
154+
155+
See [Gorm performance recommendations](https://gorm.io/docs/performance.html).
156+
157+
#### Disable Default Transaction
158+
159+
Gorm performs write (create/update/delete) operations by default inside a transaction to ensure data consistency, which
160+
is not optimized for performance.
161+
162+
You can disable it in the configuration:
163+
164+
```yaml
165+
# ./configs/config.yaml
166+
app:
167+
name: app
168+
env: dev
169+
version: 0.1.0
170+
debug: false
171+
modules:
172+
orm:
173+
driver: mysql # driver to use
174+
dsn: user:pass@tcp(127.0.0.1:3306)/dbname?parseTime=True" # database DSN to connect to
175+
config:
176+
skip_default_transaction: true # disable default transaction
177+
```
178+
179+
#### Cache Prepared Statement
180+
181+
To create a prepared statement when executing any SQL (and cache them to speed up future calls):
182+
183+
```yaml
184+
# ./configs/config.yaml
185+
app:
186+
name: app
187+
env: dev
188+
version: 0.1.0
189+
debug: false
190+
modules:
191+
orm:
192+
driver: mysql # driver to use
193+
dsn: user:pass@tcp(127.0.0.1:3306)/dbname?parseTime=True" # database DSN to connect to
194+
config:
195+
prepare_stmt: true # enable prepared statements
196+
```
197+
198+
### Override
199+
200+
By default, the `gorm.DB` is created by
201+
the [DefaultOrmFactory](https://github.com/ankorstore/yokai/blob/main/orm/factory.go).
202+
203+
If needed, you can provide your own factory and override the module:
204+
205+
```go
206+
package main
207+
208+
import (
209+
"github.com/ankorstore/yokai/fxconfig"
210+
"github.com/ankorstore/yokai/fxlog"
211+
"github.com/ankorstore/yokai/fxorm"
212+
"github.com/ankorstore/yokai/fxtrace"
213+
"github.com/ankorstore/yokai/orm"
214+
"go.uber.org/fx"
215+
"gorm.io/gorm"
216+
)
217+
218+
type CustomOrmFactory struct{}
219+
220+
func NewCustomOrmFactory() orm.OrmFactory {
221+
return &CustomOrmFactory{}
222+
}
223+
224+
func (f *CustomOrmFactory) Create(options ...orm.OrmOption) (*gorm.DB, error) {
225+
return &gorm.DB{...}, nil
226+
}
227+
228+
type Model struct {
229+
Name string
230+
}
231+
232+
func main() {
233+
fx.New(
234+
fxconfig.FxConfigModule, // load the module dependencies
235+
fxlog.FxLogModule,
236+
fxtrace.FxTraceModule,
237+
fxorm.FxOrmModule, // load the module
238+
fx.Decorate(NewCustomOrmFactory), // override the module with a custom factory
239+
fx.Invoke(func(customDb *gorm.DB) { // invoke the custom ORM
240+
customDb.Create(&Model{Name: "custom"})
241+
}),
242+
).Run()
243+
}
244+
```

0 commit comments

Comments
 (0)