Skip to content

Commit

Permalink
feat(docs): Adding docs on how to use the package (#6)
Browse files Browse the repository at this point in the history
* Adding docs on how to use the package

* Updated examples

* Updated examples
  • Loading branch information
Jacobbrewer1 authored Oct 4, 2024
1 parent b310493 commit 89b3ed9
Show file tree
Hide file tree
Showing 5 changed files with 423 additions and 1 deletion.
96 changes: 95 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,97 @@
# Patcher

Patcher is a GO library that provides a simple way to generate and SQL patches from structs.
Patcher is a GO library that provides a simple way to generate and SQL patches from structs. The library was built out
of the need to generate patches for a database; when a new field is added to a struct, this would result in a bunch of
new `if` checks to be created in the codebase. This library aims to solve that problem by generating the SQL patches for
you.

## Usage

To use the library, you need to create a struct that represents the table you want to generate patches for. The struct
should have the following tags:

- `db:"column_name"`: This tag is used to specify the column name in the database.

Example:

```go
package main

import (
"encoding/json"
"fmt"

"github.com/Jacobbrewer1/patcher"
)

type Person struct {
ID *int `db:"id"`
Name *string `db:"name"`
Age *int `db:"age"`
}

type PersonWhere struct {
ID *int `db:"id"`
}

func NewPersonWhere(id int) *PersonWhere {
return &PersonWhere{
ID: &id,
}
}

func (p *PersonWhere) Where() (string, []any) {
return "id = ?", []any{*p.ID}
}

func main() {
const jsonStr = `{"name": "John", "age": 25}`

person := new(Person)
if err := json.Unmarshal([]byte(jsonStr), person); err != nil {
panic(err)
}

condition := NewPersonWhere(1)

sqlStr, args, err := patcher.GenerateSQL(
person,
patcher.WithTable("people"),
patcher.WithWhere(condition),
)
if err != nil {
panic(err)
}

fmt.Println(sqlStr)
fmt.Println(args)
}
```

This will output:

```sql
UPDATE people
SET name = ?,
age = ?
WHERE 1
AND id = ?
```

with the args:

```
["John", 25, 1]
```

### Joins

To generate a join, you need to create a struct that represents the join. This struct should implement
the [Joiner](./joiner.go) interface.

Once you have the join struct, you can pass it to the `GenerateSQL` function using the `WithJoin` option. You can add as
many of these as you would like.

# Examples

You can find examples of how to use this library in the [examples](./examples) directory.
50 changes: 50 additions & 0 deletions examples/basic/basic.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package main

import (
"encoding/json"
"fmt"

"github.com/Jacobbrewer1/patcher"
)

type Person struct {
ID *int `db:"id"`
Name *string `db:"name"`
}

type PersonWhere struct {
ID *int `db:"id"`
}

func NewPersonWhere(id int) *PersonWhere {
return &PersonWhere{
ID: &id,
}
}

func (p *PersonWhere) Where() (string, []any) {
return "id = ?", []any{*p.ID}
}

func main() {
const jsonStr = `{"id": 1, "name": "john"}`

person := new(Person)
if err := json.Unmarshal([]byte(jsonStr), person); err != nil {
panic(err)
}

condition := NewPersonWhere(*person.ID)

sqlStr, args, err := patcher.GenerateSQL(
person,
patcher.WithTable("people"),
patcher.WithWhere(condition),
)
if err != nil {
panic(err)
}

fmt.Println(sqlStr)
fmt.Println(args)
}
190 changes: 190 additions & 0 deletions examples/joiner/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
# Joiner

For this example assume that you have two tables in the database `people` and `contacts`.

## People

| id | name | age |
|----|------|-----|
| 1 | Ben | 25 |
| 2 | John | 30 |

## Contacts

| id | person_id | email |
|----|-----------|---------------------|
| 1 | 1 | [email protected] |
| 2 | 2 | [email protected] |

# Example

Moving forwards with the example, lets assume that you are updating the person and you have received their email as the
key on the data. You can use the `Joiner` interface to join the two tables and update the person.

```go
package main

import (
"encoding/json"
"fmt"

"github.com/Jacobbrewer1/patcher"
)

type Person struct {
ID *int `db:"id"`
Name *string `db:"name"`
Age *int `db:"age"`
Email *string `db:"email"`
}

type PersonWhere struct {
ID *int
}

func NewPersonWhere(id int) *PersonWhere {
return &PersonWhere{
ID: &id,
}
}

func (p *PersonWhere) Where() (string, []interface{}) {
return "id = ?", []interface{}{*p.ID}
}

type ContactWhere struct {
Email *string
}

func NewContactWhere(email string) *ContactWhere {
return &ContactWhere{
Email: &email,
}
}

func (c *ContactWhere) Where() (string, []interface{}) {
return "email = ?", []interface{}{*c.Email}
}

type PersonContactJoiner struct{}

func NewPersonContactJoiner() *PersonContactJoiner {
return &PersonContactJoiner{}
}

func (p *PersonContactJoiner) Join() (string, []any) {
return "JOIN contacts c ON c.person_id = p.id", nil
}

func main() {
jsonStr := `{"name": "john", "age": 25, "email": "[email protected]"}`

person := new(Person)
if err := json.Unmarshal([]byte(jsonStr), person); err != nil {
panic(err)
}

condition := NewPersonWhere(1)
joiner := NewPersonContactJoiner()

sqlStr, args, err := patcher.GenerateSQL(
person,
patcher.WithTable("people"),
patcher.WithWhere(condition),
patcher.WithJoin(joiner),
)
if err != nil {
panic(err)
}

fmt.Println(sqlStr)
fmt.Println(args)
}

```

```go
package main

import (
"encoding/json"
"fmt"

"github.com/Jacobbrewer1/patcher"
)

type Person struct {
ID *int `db:"id"`
Name *string `db:"name"`
Age *int `db:"age"`
Email *string `db:"email"`
}

type PersonWhere struct {
ID *int `db:"id"`
}

func NewPersonWhere(id int) *PersonWhere {
return &PersonWhere{
ID: &id,
}
}

func (p *PersonWhere) Where() (string, []interface{}) {
return "id = ?", []interface{}{*p.ID}
}

type ContactWhere struct {
Email *string
}

func NewContactWhere(email string) *ContactWhere {
return &ContactWhere{
Email: &email,
}
}

func (c *ContactWhere) Where() (string, []interface{}) {
return "email = ?", []interface{}{*c.Email}
}

type PersonContactJoiner struct {
Email *string
}

func NewPersonContactJoiner(email string) *PersonContactJoiner {
return &PersonContactJoiner{
Email: &email,
}
}

func (p *PersonContactJoiner) Join() (string, []any) {
return "JOIN contacts c ON c.person_id = p.id AND c.email = ?", []any{*p.Email}
}

func main() {
jsonStr := `{"name": "john", "age": 25, "email": "[email protected]"}`

person := new(Person)
if err := json.Unmarshal([]byte(jsonStr), person); err != nil {
panic(err)
}

condition := NewPersonWhere(1)
joiner := NewPersonContactJoiner(*person.Email)

sqlStr, args, err := patcher.GenerateSQL(
person,
patcher.WithTable("people"),
patcher.WithWhere(condition),
patcher.WithJoin(joiner),
)
if err != nil {
panic(err)
}

fmt.Println(sqlStr)
fmt.Println(args)
}

```
Loading

0 comments on commit 89b3ed9

Please sign in to comment.