Skip to content

Commit

Permalink
feat(sql): Provided module (#217)
Browse files Browse the repository at this point in the history
  • Loading branch information
ekkinox committed May 8, 2024
1 parent c61e6f0 commit 3c643e7
Show file tree
Hide file tree
Showing 47 changed files with 4,642 additions and 0 deletions.
1 change: 1 addition & 0 deletions .github/workflows/coverage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ jobs:
- "httpserver"
- "log"
- "orm"
- "sql"
- "trace"
- "worker"
- "fxcore"
Expand Down
31 changes: 31 additions & 0 deletions .github/workflows/sql-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
name: "sql-ci"

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

jobs:
ci:
uses: ./.github/workflows/common-ci.yml
secrets: inherit
with:
module: "sql"
5 changes: 5 additions & 0 deletions release-please-config.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@
"component": "orm",
"tag-separator": "/"
},
"sql": {
"release-type": "go",
"component": "sql",
"tag-separator": "/"
},
"trace": {
"release-type": "go",
"component": "trace",
Expand Down
65 changes: 65 additions & 0 deletions sql/.golangci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
run:
timeout: 5m
concurrency: 8

linters:
enable:
- asasalint
- asciicheck
- bidichk
- bodyclose
- containedctx
- contextcheck
- cyclop
- decorder
- dogsled
- durationcheck
- errcheck
- errchkjson
- errname
- errorlint
- exhaustive
- 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
199 changes: 199 additions & 0 deletions sql/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
# SQL Module

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

> SQL module based on [database/sql](https://pkg.go.dev/database/sql).
<!-- TOC -->
* [Installation](#installation)
* [Documentation](#documentation)
* [Usage](#usage)
* [Hooks](#hooks)
* [Log hook](#log-hook)
* [Trace hook](#trace-hook)
* [Custom hook](#custom-hook)
* [Healthcheck](#healthcheck)
<!-- TOC -->

## Installation

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

## Documentation

This module provides a [Driver](driver.go), decorating `database/sql` compatible drivers, with a [hooking mechanism](hook.go).

### Usage

The following database systems are [supported](system.go):

- `mysql` with [go-sql-driver/mysql](https://github.com/go-sql-driver/mysql)
- `postgres` with [lib/pq](https://github.com/lib/pq)
- `sqlite` with [mattn/go-sqlite3](https://github.com/mattn/go-sqlite3)

To create a `*sql.DB` with the [tracing](hook/trace/hook.go) and [logging](hook/log/hook.go) hooks:

```go
package main

import (
"database/sql"

yokaisql "github.com/ankorstore/yokai/sql"
"github.com/ankorstore/yokai/sql/hook/log"
"github.com/ankorstore/yokai/sql/hook/trace"
)

func main() {
// MySQL
driver, _ := yokaisql.Register("mysql", trace.NewTraceHook(), log.NewLogHook())
db, _ := sql.Open(driver, "user:password@tcp(localhost:3306)/db?parseTime=true")

// Postgres
driver, _ := yokaisql.Register("postgres", trace.NewTraceHook(), log.NewLogHook())
db, _ := sql.Open(driver, "host=host port=5432 user=user password=password dbname=db sslmode=disable")

// SQLite
driver, _ := yokaisql.Register("sqlite", trace.NewTraceHook(), log.NewLogHook())
db, _ := sql.Open(driver, ":memory:")
}
```

See [database/sql](https://pkg.go.dev/database/sql) documentation for more details.

### Hooks

This module provides a [hooking mechanism](hook.go) to add logic around the [SQL operations](operation.go).

#### Log hook

This module provides an [LogHook](hook/log/hook.go), that you can use to automatically `log` the [SQL operations](operation.go):

```go
package main

import (
"database/sql"

yokaisql "github.com/ankorstore/yokai/sql"
"github.com/ankorstore/yokai/sql/hook/log"
"github.com/rs/zerolog"
)

func main() {

logHook := log.NewLogHook(
log.WithLevel(zerolog.DebugLevel), // SQL logs level, debug by default
log.WithArguments(true), // SQL logs with SQL arguments, false by default
log.WithExcludedOperations( // SQL operations to exclude from logging, empty by default
yokaisql.ConnectionPingOperation,
yokaisql.ConnectionResetSessionOperation,
),
)

driver, _ := yokaisql.Register("sqlite", logHook)
db, _ := sql.Open(driver, ":memory:")
}
```

#### Trace hook

This module provides an [TraceHook](hook/trace/hook.go), that you can use to automatically `trace` the [SQL operations](operation.go):

```go
package main

import (
"database/sql"

yokaisql "github.com/ankorstore/yokai/sql"
"github.com/ankorstore/yokai/sql/hook/log"
"github.com/ankorstore/yokai/sql/hook/trace"
"github.com/rs/zerolog"
)

func main() {

traceHook := trace.NewTraceHook(
trace.WithArguments(true), // SQL traces with SQL arguments, false by default
trace.WithExcludedOperations( // SQL operations to exclude from tracing, empty by default
yokaisql.ConnectionPingOperation,
yokaisql.ConnectionResetSessionOperation,
),
)

driver, _ := yokaisql.Register("sqlite", traceHook)
db, _ := sql.Open(driver, ":memory:")
}
```

#### Custom hook

This module provides a [Hook](hook.go) interface, that you can implement to extend the logic around [SQL operations](operation.go):

```go
package main

import (
"context"
"database/sql"

yokaisql "github.com/ankorstore/yokai/sql"
"github.com/ankorstore/yokai/sql/hook/log"
"github.com/ankorstore/yokai/sql/hook/trace"
"github.com/rs/zerolog"
)

type CustomHook struct{}

func (h *CustomHook) Before(ctx context.Context, event *yokaisql.HookEvent) context.Context {
// your custom logic before SQL operation

return ctx
}

func (h *CustomHook) After(ctx context.Context, event *yokaisql.HookEvent) {
// your custom logic after SQL operation
}

func main() {
driver, _ := yokaisql.Register("sqlite", &CustomHook{})
db, _ := sql.Open(driver, ":memory:")
}
```

### Healthcheck

This module provides an [SQLProbe](healthcheck/probe.go), compatible with
the [healthcheck module](https://github.com/ankorstore/yokai/tree/main/healthcheck):

```go
package main

import (
"context"

yokaihc "github.com/ankorstore/yokai/healthcheck"
yokaisql "github.com/ankorstore/yokai/sql"
"github.com/ankorstore/yokai/sql/healthcheck"
)

func main() {
driver, _ := yokaisql.Register("sqlite")
db, _ := sql.Open(driver, ":memory:")

checker, _ := yokaihc.NewDefaultCheckerFactory().Create(
yokaihc.WithProbe(healthcheck.NewSQLProbe(db)),
)

checker.Check(context.Background(), yokaihc.Readiness)
}
```

This probe performs a `ping` to the configured database connection.
25 changes: 25 additions & 0 deletions sql/configuration.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package sql

// Configuration is the SQL components (driver, connector, connection, etc) configuration.
type Configuration struct {
system System
hooks []Hook
}

// NewConfiguration returns a new Configuration.
func NewConfiguration(system System, hooks ...Hook) *Configuration {
return &Configuration{
system: system,
hooks: hooks,
}
}

// System returns the Configuration System.
func (c *Configuration) System() System {
return c.system
}

// Hooks returns the Configuration list of Hook.
func (c *Configuration) Hooks() []Hook {
return c.hooks
}
24 changes: 24 additions & 0 deletions sql/configuration_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package sql_test

import (
"testing"

"github.com/ankorstore/yokai/sql"
"github.com/ankorstore/yokai/sql/hook/log"
"github.com/ankorstore/yokai/sql/hook/trace"
"github.com/stretchr/testify/assert"
)

func TestNewConfiguration(t *testing.T) {
t.Parallel()

hooks := []sql.Hook{
trace.NewTraceHook(),
log.NewLogHook(),
}

config := sql.NewConfiguration(sql.SqliteSystem, hooks...)

assert.Equal(t, sql.SqliteSystem, config.System())
assert.Equal(t, hooks, config.Hooks())
}

0 comments on commit 3c643e7

Please sign in to comment.