go-beget

command module
v0.0.0-...-d5f281d Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 25, 2016 License: MIT Imports: 16 Imported by: 0

README

go-beget

GoDoc build status

Generate serializable and (somewhat) typesafe search requests to pass around.

The intent is not to create an ORM, but rather provide a forkable baseline to help generate all your boilerplate just the way you like it.

Getting started / Overview

Install beget by running go get -u github.com/brianstarke/go-beget

Add the go:generate go-beget comment, tag all fields with db and json tags if you want something other than ToLower'd DB column names and JSON field names.

struct is the struct you want the go-beget generator to look at, table is the name of the database table to be used in SQL statement generation/execution.

  • (currently, sql statement generation/execution only works on PostgreSQL)

Create functions will automatically omit ID and CreatedAt fields from the INSERT statement. If you wish to omit additional fields, pass them in to the omitFromInsert flag (separated by commas).

package model

//go:generate go-beget -struct=Thing -table=things -omitFromInsert=Length,Height

// Thing is a normal thing
type Thing struct {
	ID          int64     `json:"id" db:"id"`
	Color       string    `json:"color" db:"color"`
	Description string    `json:"description" db:"description"`
	Length      int       `json:"length" db:"length"`
	Height      int       `json:"height" db:"height"`
	CreatedAt   time.Time `json:"createdAt" db:"created_at_utc"`
}

go-beget currently generates it's code into the same package and directory as the one your struct is in.

Run go generate ./...

[go-beget/generator] Generating methods for Thing
[go-beget/generator] create generated		[thingCreate.generated.go]
[go-beget/generator] fields generated		[thingFields.generated.go]
[go-beget/generator] enums generated		[search.generated.go]
[go-beget/generator] update generated		[thingUpdate.generated.go]
[go-beget/generator] search generated		[thingSearch.generated.go]

Search Requests

Using a generated SearchRequest like so...

package main

import (
	"encoding/json"
	"log"

	"github.com/brianstarke/go-beget/example"
)

func main() {
	var sr example.ThingSearchRequest

	sr.
		AddFields(example.ThingColor, example.ThingHeight).
		AddFilter(example.ThingColor, "red", func(f *example.ThingFilter) {
			f.Condition = example.Or
		}).
		AddFilter(example.ThingColor, "blue", func(f *example.ThingFilter) {
			f.Condition = example.Or
		}).
		SetOrderBy(example.ThingHeight, false).
		SetLimit(10)

	jsonb, _ := json.MarshalIndent(sr, "", "  ")

	log.Println(string(jsonb))

	sql, _, _ := sr.GenerateSelectSQL()

	log.Println(sql)
}

Would output:

{
  "fields": [
    "color",
    "height"
  ],
  "filters": [
    {
      "field": "color",
      "value": "red",
      "operator": "eq",
      "condition": "or"
    },
    {
      "field": "color",
      "value": "blue",
      "operator": "eq",
      "condition": "or"
    }
  ],
  "orderBy": {
    "field": "height",
    "isDescending": false
  },
  "limit": 10,
  "offset": 0
}
SELECT color, height FROM things WHERE (color = $1 OR color = $2) ORDER BY height LIMIT 10

By default, AddFilter will use Eq (Equals) as an operator and And as a condition, if you want to override those - you can pass in functions to modify the options (H/T to [Dave Cheney](http://dave.cheney.net/2014/10/17/functional-options-for-friendly-apis http://dave.cheney.net/2014/10/17/functional-options-for-friendly-apis))

e.g:

var sr example.MahSearchRequest

sr.AddFilter(example.MahSticks, 4) // And 'sticks' = 4

sr.AddFilter(example.MahStones, 80, func(f *example.MahFilter) {
	f.Operator = example.GreaterThan
}) // And 'stones' > 80

sr.AddFilter(example.MahMarbles, 22, func(f *example.MahFilter) {
	f.Condition = example.Or
	f.Operator = example.LesserThanOrEq
}) // Or 'marbles' <= 22

sr.AddFilter(example.MahMarbles, 12, func(f *example.MahFilter) {
	f.Condition = example.Or
	f.Operator = example.GreaterThanOrEq
}) // Or 'marbles' >= 12

Would result in

SELECT * FROM mah_things WHERE (marbles <= $1 OR marbles >= $2) AND (sticks = $3 AND stones > $4)
Using HTTP handlers (totally optional)

go-beget also generates HTTP handlers, you can wire them up in your routes like so:

func main() {
  http.HandleFunc("/create", search.NewThingCreateHandlerFunc(db))
  http.HandleFunc("/search", search.NewThingSearchHandlerFunc(db))
  http.HandleFunc("/update", search.NewThingUpdateHandlerFunc(db))
  http.ListenAndServe(":8080", nil)
}

On success they return 200 and the result as JSON.

Sample JSON SearchRequest for generated handler

{
    "filters":[{
      "field": "color",
      "value": "RED",
      "operator": "eq",
      "condition": "and"
    },
		{
			"field": "size",
			"value": 13,
			"operator": "gt",
			"condition": "and"
		}],
    "fields": ["height", "type"],
    "orderBy": {
        "field": "createdAt",
        "isDescending": true
    },
    "limit":20,
    "offset": 2
}

TODO document create usage

TODO document update usage

Generator templates

go-beget uses the excellent go-bindata tool to compile it's templates in to the executable for easier command line use.

Therefore, if you make any changes to the templates, you must install go-bindata (go get -u github.com/jteeuwen/go-bindata/...).

Then ./rebuild_templates.sh from the root of this project.

TODO
  • add getByID function
  • add upsert function?
  • make ID field configurable
  • break search dependency on sqlx
  • add fake/mock implementations for testing?

Documentation

The Go Gopher

There is no documentation for this package.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL