Skip to content

Commit

Permalink
Merge pull request #15 from aldy505/docs/examples
Browse files Browse the repository at this point in the history
docs: examples
  • Loading branch information
aldy505 committed Dec 10, 2021
2 parents 63c3535 + 10bad34 commit 6402e24
Show file tree
Hide file tree
Showing 5 changed files with 219 additions and 45 deletions.
26 changes: 0 additions & 26 deletions .github/workflows/build.yml

This file was deleted.

11 changes: 7 additions & 4 deletions .github/workflows/coverage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,24 @@ name: Test and coverage
on: [push, pull_request]

jobs:
build:
check:
name: Check
runs-on: ubuntu-latest
needs: build
steps:
- name: Checkout code
uses: actions/checkout@v2
with:
fetch-depth: 2

- name: Install Go
uses: actions/setup-go@v2
with:
go-version: 1.17.x

- name: Vet check
run: go vet -v

- name: Run coverage
run: go test -v -race -coverprofile=coverage.out -covermode=atomic -failfast

- name: Upload coverage to Codecov
uses: codecov/codecov-action@v1
uses: codecov/codecov-action@v1
73 changes: 58 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,51 @@
# Bob - SQL Query Builder

[![Go Reference](https://pkg.go.dev/badge/github.com/aldy505/bob.svg)](https://pkg.go.dev/github.com/aldy505/bob) [![Go Report Card](https://goreportcard.com/badge/github.com/aldy505/bob)](https://goreportcard.com/report/github.com/aldy505/bob) ![GitHub](https://img.shields.io/github/license/aldy505/bob) [![CodeFactor](https://www.codefactor.io/repository/github/aldy505/bob/badge)](https://www.codefactor.io/repository/github/aldy505/bob) [![codecov](https://codecov.io/gh/aldy505/bob/branch/master/graph/badge.svg?token=Noeexg5xEJ)](https://codecov.io/gh/aldy505/bob) [![Codacy Badge](https://app.codacy.com/project/badge/Grade/9b78970127c74c1a923533e05f65848d)](https://www.codacy.com/gh/aldy505/bob/dashboard?utm_source=github.com&utm_medium=referral&utm_content=aldy505/bob&utm_campaign=Badge_Grade) [![Build test](https://github.com/aldy505/bob/actions/workflows/build.yml/badge.svg)](https://github.com/aldy505/bob/actions/workflows/build.yml) [![Test and coverage](https://github.com/aldy505/bob/actions/workflows/coverage.yml/badge.svg)](https://github.com/aldy505/bob/actions/workflows/coverage.yml)
[![Go Reference](pkg-go-dev-badge)](pkg-go-dev-link)
[![Go Report Card](go-report-badge)](go-report-link)
![GitHub](license-badge)
[![CodeFactor](codefactor-badge)](codefactor-link)
[![codecov](codecov-badge)](codecov-link)
[![Codacy Badge](codacy-badge)](codacy-link)
[![Test and coverage](actions-badge)](actions-link)

Bob is an SQL builder library initially made as an extension for [Squirrel](squirrel-url)
with functionality like [Knex](knex-url) (from the Node.js world). Squirrel itself
doesn't provide other types of queries for creating a table, upsert,
and some other things. Bob is meant to fill those gaps.

The different between Bob and Squirrel is that Bob is solely a query builder.
The users have to execute and manage the SQL connection themself.
Meaning there are no ExecWith() function implemented on Bob, as you can
find it on Squirrel.

The purpose of an SQL query builder is to prevent any typo or mistypes
on the SQL queries. Although also with that reason, Bob might not always
have the right query for you, depending on what you are doing with the
SQL query. It might sometimes be better for you to write the SQL query
yourself, if your problem is specific and needs some micro-tweaks.

With that being said, I hope you enjoy using Bob and consider starring or
reporting any issues regarding the usage of Bob in your projects.

Oh, and of course, heavily inspired by [Bob the Builder](bob-wikipedia).

Think of this as an extension of [Squirrel](https://github.com/Masterminds/squirrel) with functionability like [Knex](https://knexjs.org/). I still use Squirrel for other types of queries (insert, select, and all that), but I needed some SQL builder for create table and some other stuffs. Including database creation & upsert.

Oh, and of course, heavily inspired by [Bob the Builder](https://en.wikipedia.org/wiki/Bob_the_Builder).
## Usage

```go
import "github.com/aldy505/bob"
```

## Usage
Like any other Go projects when you're using Go modules, just put that
text right there on the top of your projects, do `go mod tidy` and
you are good to go.

It's not ready for large-scale production yet (although I've already using it on one of my projects). But, the API is probably close to how you'd do things on Squirrel.
Either way, I'm not 100% confident enough to say that this thing is
production ready. But, the way I see it, it's good enough to be used
on a production-level applications. In fact, I'm using it on one of my
current projects that's getting around 100-200 hits per day.

If you have any feature request or improvement ideas for the project,
please kindly open an issue

### Create a table

Expand Down Expand Up @@ -177,7 +210,7 @@ func main() {
Key("email").
Replace("age", 40).
ToSql()

// One more time, for MSSQL / SQL Server.
sql, args, err = bob.
Upsert("users", bob.MSSQL).
Expand Down Expand Up @@ -276,7 +309,7 @@ func main() {
if err != nil {
log.Fatal(err)
}

_, err = db.Query(context.Background(), inventoryQuery[i])
if err != nil {
log.Fatal(err)
Expand All @@ -299,17 +332,27 @@ func main() {
* `bob.Truncate(tableName)` - Truncate a table (`truncate "users"`)
* `bob.Upsert(tableName, dialect)` - UPSERT function (`insert into "users" ("name", "email") values (?, ?) on duplicate key update email = ?`)

### TODO

Meaning these are some ideas for the future development of Bob.

* `bob.ExecWith()` - Just like Squirrel's [ExecWith](https://pkg.go.dev/github.com/Masterminds/squirrel?utm_source=godoc#ExecWith)
* `bob.Count(tableName, columnName)` - Count query (`select count("active") from "users"`)

## Contributing

Contributions are always welcome! As long as you add a test for your changes.

## License

Bob is licensed under [MIT license](./LICENSE)

[squirrel-url]: https://github.com/Masterminds/squirrel
[knex-url]: https://knexjs.org/
[bob-wikipedia]: https://en.wikipedia.org/wiki/Bob_the_Builder
[pkg-go-dev-badge]: https://pkg.go.dev/badge/github.com/aldy505/bob.svg
[pkg-go-dev-link]: https://pkg.go.dev/github.com/aldy505/bob
[go-report-badge]: https://goreportcard.com/badge/github.com/aldy505/bob
[go-report-link]: https://goreportcard.com/report/github.com/aldy505/bob
[license-badge]: https://img.shields.io/github/license/aldy505/bob
[codefactor-link]: https://www.codefactor.io/repository/github/aldy505/bob
[codefactor-badge]: https://www.codefactor.io/repository/github/aldy505/bob/badge
[codecov-badge]: https://codecov.io/gh/aldy505/bob/branch/master/graph/badge.svg?token=Noeexg5xEJ
[codecov-link]: https://codecov.io/gh/aldy505/bob
[codacy-badge]: https://app.codacy.com/project/badge/Grade/9b78970127c74c1a923533e05f65848d
[codacy-link]: https://www.codacy.com/gh/aldy505/bob/dashboard?utm_source=github.com&utm_medium=referral&utm_content=aldy505/bob&utm_campaign=Badge_Grade
[actions-badge]: https://github.com/aldy505/bob/actions/workflows/coverage.yml/badge.svg
[actions-link]: https://github.com/aldy505/bob/actions/workflows/coverage.yml
23 changes: 23 additions & 0 deletions bob.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,26 @@
// Bob is an SQL builder library initially made as an extension for Squirrel
// with functionality like Knex (from the Node.js world). Squirrel itself
// doesn't provide other types of queries for creating a table, upsert,
// and some other things. Bob is meant to fill those gaps.
//
// The different between Bob and Squirrel is that Bob is solely a query builder.
// The users have to execute and manage the SQL connection themself.
// Meaning there are no ExecWith() function implemented on Bob, as you can
// find it on Squirrel.
//
// The purpose of an SQL query builder is to prevent any typo or mistypes
// on the SQL queries. Although also with that reason, Bob might not always
// have the right query for you, depending on what you are doing with the
// SQL query. It might sometimes be better for you to write the SQL query
// yourself, if your problem is specific and needs some micro-tweaks.
//
// With that being said, I hope you enjoy using Bob and consider starring or
// reporting any issues regarding the usage of Bob in your projects.
//
// MIT License
//
// Copyright (c) 2021-present Reinaldy Rafli and Bob collaborators
//
package bob

import (
Expand Down
131 changes: 131 additions & 0 deletions example_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
package bob_test

import (
"fmt"

"github.com/aldy505/bob"
)

func ExampleCreateIndex() {
sql, _, err := bob.
CreateIndex("idx_email").
On("users").
Unique().
Columns(bob.IndexColumn{Name: "email", Collate: "DEFAULT", Extras: []string{"ASC"}}).
ToSql()
if err != nil {
fmt.Printf("Handle this error: %v", err)
}

fmt.Print(sql)
// Output: CREATE UNIQUE INDEX idx_email ON users (email COLLATE DEFAULT ASC);
}

func ExampleHasTable() {
sql, args, err := bob.HasTable("users").ToSql()
if err != nil {
fmt.Printf("Handle this error: %v", err)
}

fmt.Printf("sql: %s, args: %v", sql, args)
// Output: sql: SELECT * FROM information_schema.tables WHERE table_name = ? AND table_schema = current_schema();, args: [users]
}

func ExampleHasColumn() {
sql, args, err := bob.HasColumn("email").HasTable("users").ToSql()
if err != nil {
fmt.Printf("Handle this error: %v", err)
}

fmt.Printf("sql: %s, args: %v", sql, args)
// Output: sql: SELECT * FROM information_schema.columns WHERE table_name = ? AND column_name = ? AND table_schema = current_schema();, args: [users email]
}

func ExampleDropTable() {
sql, _, err := bob.DropTable("users").Cascade().ToSql()
if err != nil {
fmt.Printf("Handle this error: %v", err)
}

fmt.Println(sql)
// Output: DROP TABLE "users" CASCADE;
}

func ExampleDropTableIfExists() {
sql, _, err := bob.DropTableIfExists("users").ToSql()
if err != nil {
fmt.Printf("Handle this error: %v", err)
}

fmt.Println(sql)
// Output: DROP TABLE IF EXISTS "users";
}

func ExampleTruncate() {
sql, _, err := bob.Truncate("users").ToSql()
if err != nil {
fmt.Printf("Handle this error: %v", err)
}

fmt.Println(sql)
// Output: TRUNCATE "users";
}

func ExampleRenameTable() {
sql, _, err := bob.RenameTable("users", "people").ToSql()
if err != nil {
fmt.Printf("Handle this error: %v", err)
}

fmt.Println(sql)
// Output: RENAME TABLE "users" TO "people";
}

func ExampleUpsert() {
// Example for MYSQL
mysql, myArgs, err := bob.
// Notice that you should give database dialect on the second params.
// Available database dialect are MySQL, PostgreSQL, SQLite, and MSSQL.
Upsert("users", bob.MySQL).
Columns("name", "email", "age").
// You could do multiple Values() call, but I'd suggest to not do it.
// Because this is an upsert function, not an insert one.
Values("Thomas Mueler", "tmueler@something.com", 25).
Replace("age", 25).
ToSql()
if err != nil {
fmt.Printf("Handle this error: %v", err)
}

// Another example for PostgreSQL
pgsql, pgArgs, err := bob.
Upsert("users", bob.PostgreSQL).
Columns("name", "email", "age").
Values("Billy Urtha", "billu@something.com", 30).
Key("email").
Replace("age", 40).
ToSql()
if err != nil {
fmt.Printf("Handle this error: %v", err)
}

// One more time, for MSSQL / SQL Server.
mssql, msArgs, err := bob.
Upsert("users", bob.MSSQL).
Columns("name", "email", "age").
Values("George Rust", "georgee@something.com", 19).
Key("email", "georgee@something.com").
Replace("age", 18).
ToSql()
if err != nil {
fmt.Printf("Handle this error: %v", err)
}

fmt.Printf("MySQL: %s, %v\n", mysql, myArgs)
fmt.Printf("PostgreSQL: %s, %v\n", pgsql, pgArgs)
fmt.Printf("MSSQL: %s, %v\n", mssql, msArgs)
// Output:
// MySQL: INSERT INTO "users" ("name", "email", "age") VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE "age" = ?;, [Thomas Mueler tmueler@something.com 25 25]
// PostgreSQL: INSERT INTO "users" ("name", "email", "age") VALUES ($1, $2, $3) ON CONFLICT ("email") DO UPDATE SET "age" = $4;, [Billy Urtha billu@something.com 30 40]
// MSSQL: IF NOT EXISTS (SELECT * FROM "users" WHERE "email" = @p1) INSERT INTO "users" ("name", "email", "age") VALUES (@p2, @p3, @p4) ELSE UPDATE "users" SET "age" = @p5 WHERE "email" = @p6;, [georgee@something.com George Rust georgee@something.com 19 18 georgee@something.com]
}

0 comments on commit 6402e24

Please sign in to comment.