-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(docs): Adding docs on how to use the package (#6)
* Adding docs on how to use the package * Updated examples * Updated examples
- Loading branch information
1 parent
b310493
commit 89b3ed9
Showing
5 changed files
with
423 additions
and
1 deletion.
There are no files selected for viewing
This file contains 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
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. |
This file contains 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
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) | ||
} |
This file contains 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
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) | ||
} | ||
|
||
``` |
Oops, something went wrong.