Skip to content

Commit

Permalink
feat(fxorm): Provided module
Browse files Browse the repository at this point in the history
  • Loading branch information
ekkinox committed Jan 12, 2024
1 parent 74979af commit 739411b
Show file tree
Hide file tree
Showing 14 changed files with 1,528 additions and 0 deletions.
1 change: 1 addition & 0 deletions .github/workflows/coverage.yml
Expand Up @@ -34,6 +34,7 @@ jobs:
- "fxhealthcheck"
- "fxlog"
- "fxmetrics"
- "fxorm"
- "fxtrace"
steps:
- name: Checkout
Expand Down
31 changes: 31 additions & 0 deletions .github/workflows/fxorm-ci.yml
@@ -0,0 +1,31 @@
name: "fxorm-ci"

on:
push:
branches:
- "feat**"
- "fix**"
- "hotfix**"
- "chore**"
paths:
- "fxorm/**.go"
- "fxorm/go.mod"
- "fxorm/go.sum"
pull_request:
types:
- opened
- synchronize
- reopened
branches:
- main
paths:
- "fxorm/**.go"
- "fxorm/go.mod"
- "fxorm/go.sum"

jobs:
ci:
uses: ./.github/workflows/common-ci.yml
secrets: inherit
with:
module: "fxorm"
1 change: 1 addition & 0 deletions README.md
Expand Up @@ -27,6 +27,7 @@ Yokai's `Fx modules` are the plugins for your Yokai application.
| [fxhealthcheck](fxhealthcheck) | Fx module for [healthcheck](healthcheck) |
| [fxlog](fxlog) | Fx module for [log](log) |
| [fxmetrics](fxmetrics) | Fx module for [prometheus](https://github.com/prometheus/client_golang) |
| [fxorm](fxorm) | Fx module for [orm](orm) |
| [fxtrace](fxtrace) | Fx module for [trace](trace) |

They can also be used in any [Fx](https://github.com/uber-go/fx) based Go application.
Expand Down
63 changes: 63 additions & 0 deletions fxorm/.golangci.yml
@@ -0,0 +1,63 @@
run:
timeout: 5m
concurrency: 8

linters:
enable:
- asasalint
- asciicheck
- bidichk
- bodyclose
- containedctx
- contextcheck
- decorder
- dogsled
- durationcheck
- errcheck
- errchkjson
- errname
- errorlint
- forbidigo
- forcetypeassert
- gocognit
- goconst
- gocritic
- gocyclo
- godot
- godox
- gofmt
- goheader
- gomoddirectives
- gomodguard
- goprintffuncname
- gosec
- gosimple
- govet
- grouper
- importas
- ineffassign
- interfacebloat
- logrlint
- maintidx
- makezero
- misspell
- nestif
- nilerr
- nilnil
- nlreturn
- nolintlint
- nosprintfhostport
- prealloc
- predeclared
- promlinter
- reassign
- staticcheck
- tenv
- thelper
- tparallel
- typecheck
- unconvert
- unparam
- unused
- usestdlibvars
- whitespace
244 changes: 244 additions & 0 deletions fxorm/README.md
@@ -0,0 +1,244 @@
# Fx ORM Module

[![ci](https://github.com/ankorstore/yokai/actions/workflows/fxorm-ci.yml/badge.svg)](https://github.com/ankorstore/yokai/actions/workflows/fxorm-ci.yml)
[![go report](https://goreportcard.com/badge/github.com/ankorstore/yokai/fxorm)](https://goreportcard.com/report/github.com/ankorstore/yokai/fxorm)
[![codecov](https://codecov.io/gh/ankorstore/yokai/graph/badge.svg?token=ghUBlFsjhR&flag=fxorm)](https://app.codecov.io/gh/ankorstore/yokai/tree/main/fxorm)
[![Deps](https://img.shields.io/badge/osi-deps-blue)](https://deps.dev/go/github.com%2Fankorstore%2Fyokai%2Ffxorm)
[![PkgGoDev](https://pkg.go.dev/badge/github.com/ankorstore/yokai/fxorm)](https://pkg.go.dev/github.com/ankorstore/yokai/fxorm)

> [Fx](https://uber-go.github.io/fx/) module for [orm](https://github.com/ankorstore/yokai/tree/main/orm).
<!-- TOC -->
* [Installation](#installation)
* [Documentation](#documentation)
* [Dependencies](#dependencies)
* [Loading](#loading)
* [Configuration](#configuration)
* [Auto migrations](#auto-migrations)
* [Performance](#performance)
* [Disable Default Transaction](#disable-default-transaction)
* [Cache Prepared Statement](#cache-prepared-statement)
* [Override](#override)
<!-- TOC -->

## Installation

```shell
go get github.com/ankorstore/yokai/fxorm
```

## Documentation

### Dependencies

This module is intended to be used alongside:

- the [fxconfig](https://github.com/ankorstore/yokai/tree/main/fxconfig) module
- the [fxlog](https://github.com/ankorstore/yokai/tree/main/fxlog) module
- the [fxtrace](https://github.com/ankorstore/yokai/tree/main/fxtrace) module

### Loading

To load the module in your Fx application:

```go
package main

import (
"github.com/ankorstore/yokai/fxconfig"
"github.com/ankorstore/yokai/fxlog"
"github.com/ankorstore/yokai/fxorm"
"github.com/ankorstore/yokai/fxtrace"
"go.uber.org/fx"
"gorm.io/gorm"
)

type Model struct {
Name string
}

func main() {
fx.New(
fxconfig.FxConfigModule, // load the module dependencies
fxlog.FxLogModule,
fxtrace.FxTraceModule,
fxorm.FxOrmModule, // load the module
fx.Invoke(func(db *gorm.DB) { // invoke the orm
db.Create(&Model{Name: "some name"})
}),
).Run()
}
```

### Configuration

This module provides the possibility to configure the ORM `driver`:

- `sqlite` for SQLite databases
- `mysql` for MySQL databases
- `postgres` for PostgreSQL databases
- `sqlserver` for SQL Server databases

You can also provide to the ORM the database`dsn`, some `config`, and configure SQL queries `logging` and `tracing`.

```yaml
# ./configs/config.yaml
app:
name: app
env: dev
version: 0.1.0
debug: false
modules:
orm:
driver: mysql # driver to use
dsn: user:pass@tcp(127.0.0.1:3306)/dbname?parseTime=True" # database DSN to connect to
config:
dry_run: false # disabled by default
skip_default_transaction: false # disabled by default
full_save_associations: false # disabled by default
prepare_stmt: false # disabled by default
disable_automatic_ping: false # disabled by default
disable_foreign_key_constraint_when_migrating: false # disabled by default
ignore_relationships_when_migrating: false # disabled by default
disable_nested_transaction: false # disabled by default
allow_global_update: false # disabled by default
query_fields: false # disabled by default
translate_error: false # disabled by default
log:
enabled: true # to log SQL queries, disabled by default
level: info # with a minimal level
values: true # by adding or not clear SQL queries parameters values in logs, disabled by default
trace:
enabled: true # to trace SQL queries, disabled by default
values: true # by adding or not clear SQL queries parameters values in trace spans, disabled by default
```

See [Gorm Config](https://github.com/go-gorm/gorm/blob/master/gorm.go) for more details about the configuration.

### Auto migrations

This module provides the possibility to run automatically your [schemas migrations](https://gorm.io/docs/migration.html)
with `RunFxOrmAutoMigrate()`:

```go
package main

import (
"github.com/ankorstore/yokai/fxconfig"
"github.com/ankorstore/yokai/fxlog"
"github.com/ankorstore/yokai/fxorm"
"github.com/ankorstore/yokai/fxtrace"
"go.uber.org/fx"
"gorm.io/gorm"
)

type Model struct {
Name string
}

func main() {
fx.New(
fxconfig.FxConfigModule, // load the module dependencies
fxlog.FxLogModule,
fxtrace.FxTraceModule,
fxorm.FxOrmModule, // load the module
fxorm.RunFxOrmAutoMigrate(&Model{}), // run auto migration for Model
fx.Invoke(func(db *gorm.DB) { // invoke the orm
db.Create(&Model{Name: "some name"})
}),
).Run()
}
```

### Performance

See [Gorm performance recommendations](https://gorm.io/docs/performance.html).

#### Disable Default Transaction

Gorm performs write (create/update/delete) operations by default inside a transaction to ensure data consistency, which
is not optimized for performance.

You can disable it in the configuration:

```yaml
# ./configs/config.yaml
app:
name: app
env: dev
version: 0.1.0
debug: false
modules:
orm:
driver: mysql # driver to use
dsn: user:pass@tcp(127.0.0.1:3306)/dbname?parseTime=True" # database DSN to connect to
config:
skip_default_transaction: true # disable default transaction
```

#### Cache Prepared Statement

To create a prepared statement when executing any SQL (and cache them to speed up future calls):

```yaml
# ./configs/config.yaml
app:
name: app
env: dev
version: 0.1.0
debug: false
modules:
orm:
driver: mysql # driver to use
dsn: user:pass@tcp(127.0.0.1:3306)/dbname?parseTime=True" # database DSN to connect to
config:
prepare_stmt: true # enable prepared statements
```

### Override

By default, the `gorm.DB` is created by
the [DefaultOrmFactory](https://github.com/ankorstore/yokai/blob/main/orm/factory.go).

If needed, you can provide your own factory and override the module:

```go
package main

import (
"github.com/ankorstore/yokai/fxconfig"
"github.com/ankorstore/yokai/fxlog"
"github.com/ankorstore/yokai/fxorm"
"github.com/ankorstore/yokai/fxtrace"
"github.com/ankorstore/yokai/orm"
"go.uber.org/fx"
"gorm.io/gorm"
)

type CustomOrmFactory struct{}

func NewCustomOrmFactory() orm.OrmFactory {
return &CustomOrmFactory{}
}

func (f *CustomOrmFactory) Create(options ...orm.OrmOption) (*gorm.DB, error) {
return &gorm.DB{...}, nil
}

type Model struct {
Name string
}

func main() {
fx.New(
fxconfig.FxConfigModule, // load the module dependencies
fxlog.FxLogModule,
fxtrace.FxTraceModule,
fxorm.FxOrmModule, // load the module
fx.Decorate(NewCustomOrmFactory), // override the module with a custom factory
fx.Invoke(func(customDb *gorm.DB) { // invoke the custom ORM
customDb.Create(&Model{Name: "custom"})
}),
).Run()
}
```

0 comments on commit 739411b

Please sign in to comment.