A fork of https://github.com/go-jet/jet, type safe SQL builder with code generation and automatic query result data mapping
Find a file
2019-06-24 18:26:50 +02:00
.circleci Update go-jet to support CircleCi build. 2019-06-23 14:51:38 +02:00
cmd/jetgen Readme quick start example. 2019-06-24 18:22:55 +02:00
examples/quick-start Readme quick start example. 2019-06-24 18:22:55 +02:00
execution Generated test folder rename. 2019-06-24 10:01:34 +02:00
generator Generator cleanup. 2019-06-23 18:55:57 +02:00
tests Readme quick start example. 2019-06-24 18:22:55 +02:00
.gitattributes Support for quoted identifiers. 2019-06-17 12:05:52 +02:00
.gitignore Readme quick start example. 2019-06-24 18:22:55 +02:00
alias.go Package path refactor. 2019-06-21 13:56:57 +02:00
bool_expresion.go Package path refactor. 2019-06-21 13:56:57 +02:00
bool_expression_test.go Package path refactor. 2019-06-21 13:56:57 +02:00
cast.go Package path refactor. 2019-06-21 13:56:57 +02:00
clause.go Package path refactor. 2019-06-21 13:56:57 +02:00
column.go Package path refactor. 2019-06-21 13:56:57 +02:00
column_test.go Package path refactor. 2019-06-21 13:56:57 +02:00
column_types.go Package path refactor. 2019-06-21 13:56:57 +02:00
column_types_test.go Package path refactor. 2019-06-21 13:56:57 +02:00
date_expression.go Package path refactor. 2019-06-21 13:56:57 +02:00
delete_statement.go Generator cleanup. 2019-06-23 18:55:57 +02:00
delete_statement_test.go Package path refactor. 2019-06-21 13:56:57 +02:00
doc.go Package path refactor. 2019-06-21 13:56:57 +02:00
enum_value.go Package path refactor. 2019-06-21 13:56:57 +02:00
expression.go Package path refactor. 2019-06-21 13:56:57 +02:00
expression_old.go Package path refactor. 2019-06-21 13:56:57 +02:00
expression_old_test.go Package path refactor. 2019-06-21 13:56:57 +02:00
expression_table.go Package path refactor. 2019-06-21 13:56:57 +02:00
expression_test.go Package path refactor. 2019-06-21 13:56:57 +02:00
float_expression.go Package path refactor. 2019-06-21 13:56:57 +02:00
float_expression_test.go Package path refactor. 2019-06-21 13:56:57 +02:00
func_expression.go Package path refactor. 2019-06-21 13:56:57 +02:00
func_expression_test.go Package path refactor. 2019-06-21 13:56:57 +02:00
group_by_clause.go Package path refactor. 2019-06-21 13:56:57 +02:00
insert_statement.go Generator cleanup. 2019-06-23 18:55:57 +02:00
insert_statement_test.go Package path refactor. 2019-06-21 13:56:57 +02:00
integer_expression.go Package path refactor. 2019-06-21 13:56:57 +02:00
integer_expression_test.go Package path refactor. 2019-06-21 13:56:57 +02:00
keyword.go Package path refactor. 2019-06-21 13:56:57 +02:00
LICENSE Initial commit 2019-04-30 11:30:59 +02:00
literal_expression.go Package path refactor. 2019-06-21 13:56:57 +02:00
literal_expression_test.go Package path refactor. 2019-06-21 13:56:57 +02:00
lock_statement.go Generator cleanup. 2019-06-23 18:55:57 +02:00
lock_statement_test.go Package path refactor. 2019-06-21 13:56:57 +02:00
numeric_expression.go Package path refactor. 2019-06-21 13:56:57 +02:00
operators.go Package path refactor. 2019-06-21 13:56:57 +02:00
operators_test.go Package path refactor. 2019-06-21 13:56:57 +02:00
order_by_clause.go Package path refactor. 2019-06-21 13:56:57 +02:00
projection.go Package path refactor. 2019-06-21 13:56:57 +02:00
README.md Fix readme formatting. 2019-06-24 18:26:50 +02:00
row_type.go Package path refactor. 2019-06-21 13:56:57 +02:00
select_statement.go Generator cleanup. 2019-06-23 18:55:57 +02:00
select_statement_test.go Package path refactor. 2019-06-21 13:56:57 +02:00
set_statement.go Generator cleanup. 2019-06-23 18:55:57 +02:00
set_statement_test.go Package path refactor. 2019-06-21 13:56:57 +02:00
statement.go Generator cleanup. 2019-06-23 18:55:57 +02:00
string_expression.go Package path refactor. 2019-06-21 13:56:57 +02:00
string_expression_test.go Package path refactor. 2019-06-21 13:56:57 +02:00
table.go Package path refactor. 2019-06-21 13:56:57 +02:00
table_test.go Package path refactor. 2019-06-21 13:56:57 +02:00
test_utils.go Package path refactor. 2019-06-21 13:56:57 +02:00
time_expression.go Package path refactor. 2019-06-21 13:56:57 +02:00
time_expression_test.go Package path refactor. 2019-06-21 13:56:57 +02:00
timestamp_expression.go Package path refactor. 2019-06-21 13:56:57 +02:00
timestampz_expression.go Package path refactor. 2019-06-21 13:56:57 +02:00
timez_expression.go Package path refactor. 2019-06-21 13:56:57 +02:00
update_statement.go Generator cleanup. 2019-06-23 18:55:57 +02:00
update_statement_test.go Package path refactor. 2019-06-21 13:56:57 +02:00
utils.go Package path refactor. 2019-06-21 13:56:57 +02:00

Jet - Sql Builder for Postgresql

CircleCI

Jet is sql builder for Postgresql(support for MySql and OracleSql will be added later). Jet enables writing typesafe SQL queries in Go, and ability to easily convert query result to desired arbitrary structure.

Features

  • TODO

Getting Started

Prerequisites

To install Jet package, you need to install Go and set your Go workspace first.

Go version 1.8+ is required

Installation

Use the bellow command to install jet

$ go get -u github.com/go-jet/jet

Install jetgen to GOPATH bin folder. This will allow generating jet files from the command line.

go install github.com/go-jet/jet/cmd/jetgen

Make sure GOPATH bin folder is added to the PATH environment variable.

Quick Start

For this quick start example we will use sample dvd rental database. Full database dump can be found in ./tests/init/data/dvds.sql Schema diagram of interest for example can be found here.

Generate sql builder and model files

To generate sql builder and data model go files we need to call jetgen, and provide it with postgres connection parameters and destination folder for generated go files. Sample command used in tests:

jetgen -host=localhost -port=5432 -user=jet -password=jet -dbname=jetdb -schema dvds -path ./gen
Connecting to postgres database: host=localhost port=5432 user=jet password=jet dbname=jetdb sslmode=disable 
Retrieving schema information...
	FOUND 15  table(s),  1  enum(s)
Cleaning up destination directory...
Generating table sql builder files...
Generating table model files...
Generating enum sql builder files...
Generating enum model files...
Done

As jetgen command output suggest, jetgen will:
-connect to dvds database to retrieve information about the structure of database
-delete everything in destination folder ./gen,
-and finally generate sql builder and model *.go files for all database tables and enums in destination folder ./tests/gentestdata.

Now lets write some SQL queries in go

First lets import jet and generated files from previous step

import (
	. "github.com/go-jet/jet"                                           // dot import so go code would resemble as much as native SQL
	. "github.com/go-jet/jet/examples/quick-start/gen/jetdb/dvds/table" // dot import is not mandatory

	"github.com/go-jet/jet/examples/quick-start/gen/jetdb/dvds/model"
)

Lets say we want to retrieve the list of all actors that acted in films longer than 180 minutes, film language is 'English' and film category is not 'Action'.

stmt := SELECT(
		Actor.ActorID, Actor.FirstName, Actor.LastName, Actor.LastUpdate, // list of all actor columns (equivalent to Actor.AllColumns)
		Film.AllColumns,                                                  // list of all film columns (equivalent to Film.FilmID, Film.Title, ...)
		Language.AllColumns,
		Category.AllColumns,
	).FROM(
		Actor.
			INNER_JOIN(FilmActor, Actor.ActorID.EQ(FilmActor.ActorID)).  // INNER JOIN Actor with FilmActor on condition Actor.ActorID = FilmActor.ActorID
			INNER_JOIN(Film, Film.FilmID.EQ(FilmActor.FilmID)).          // then with Film, Language, FilmCategory and Category.
			INNER_JOIN(Language, Language.LanguageID.EQ(Film.LanguageID)).
			INNER_JOIN(FilmCategory, FilmCategory.FilmID.EQ(Film.FilmID)).
			INNER_JOIN(Category, Category.CategoryID.EQ(FilmCategory.CategoryID)),
	).WHERE(
		Language.Name.EQ(String("English")).                    // note every column has type.
			AND(Category.Name.NOT_EQ(String("Action"))).        // String column Language.Name and Category.Name can be compared only with string columns and expressions
			AND(Film.Length.GT(Int(180))),                      // Film.Length is integer column and can be compared only with integer columns and expressions
	).ORDER_BY(
		Actor.ActorID.ASC(),
		Film.FilmID.ASC(),
	)

To see sql formed with this statement:

query, args, err := stmt.Sql()

query - is parametrized query
args - are parameters for the query

To see debug sql that can be copy pasted to sql editor and executed.

query, err := stmt.DebugSql()

query - is parametrized query where every parameter is replaced with appropriate string argument representation

Well formed sql is just a first half the job. Now lets execute sql statement and store result in desired structure.
Let's say this is our desired structure:

var dest []struct {
    model.Actor
    Films []struct {
        model.Film
        Language model.Language
        Category []model.Category
    }
}

There is no limitation for how big or nested destination structure can be.

Now to execute a statement on open database connection db.

err := stmt.Query(db, &dest)
handleError(err)

And thats it. dest now contains the list of all actors that acted in films longer than 180 minutes, film language is 'English' and film category is not 'Action'.

Lets print dest as a json to see:

jsonText, _ := json.MarshalIndent(dest, "", "\t")
fmt.Println(string(jsonText))
[
	{
		"ActorID": 1,
		"FirstName": "Penelope",
		"LastName": "Guiness",
		"LastUpdate": "2013-05-26T14:47:57.62Z",
		"Films": [
			{
				"FilmID": 499,
				"Title": "King Evolution",
				"Description": "A Action-Packed Tale of a Boy And a Lumberjack who must Chase a Madman in A Baloon",
				"ReleaseYear": 2006,
				"LanguageID": 1,
				"RentalDuration": 3,
				"RentalRate": 4.99,
				"Length": 184,
				"ReplacementCost": 24.99,
				"Rating": "NC-17",
				"LastUpdate": "2013-05-26T14:50:58.951Z",
				"SpecialFeatures": "{Trailers,\"Deleted Scenes\",\"Behind the Scenes\"}",
				"Fulltext": "'action':5 'action-pack':4 'baloon':21 'boy':10 'chase':16 'evolut':2 'king':1 'lumberjack':13 'madman':18 'must':15 'pack':6 'tale':7",
				"Language": {
					"LanguageID": 1,
					"Name": "English             ",
					"LastUpdate": "2006-02-15T10:02:19Z"
				},
				"Category": [
					{
						"CategoryID": 8,
						"Name": "Family",
						"LastUpdate": "2006-02-15T09:46:27Z"
					}
				]
			}
		]
	},
	{
		"ActorID": 3,
		"FirstName": "Ed",
		"LastName": "Chase",
		"LastUpdate": "2013-05-26T14:47:57.62Z",
		"Films": [
			{
				"FilmID": 996,
				"Title": "Young Language",
				"Description": "A Unbelieveable Yarn of a Boat And a Database Administrator who must Meet a Boy in The First Manned Space Station",
				"ReleaseYear": 2006,
				"LanguageID": 1,
				"RentalDuration": 6,
				"RentalRate": 0.99,
				"Length": 183,
				"ReplacementCost": 9.99,
				"Rating": "G",
				"LastUpdate": "2013-05-26T14:50:58.951Z",
				"SpecialFeatures": "{Trailers,\"Behind the Scenes\"}",
				"Fulltext": "'administr':12 'boat':8 'boy':17 'databas':11 'first':20 'languag':2 'man':21 'meet':15 'must':14 'space':22 'station':23 'unbeliev':4 'yarn':5 'young':1",
				"Language": {
					"LanguageID": 1,
					"Name": "English             ",
					"LastUpdate": "2006-02-15T10:02:19Z"
				},
				"Category": [
					{
						"CategoryID": 6,
						"Name": "Documentary",
						"LastUpdate": "2006-02-15T09:46:27Z"
					}
				]
			}
		]
	},
	...(125 more items)

What if we also want to have list of films per category and actors per category, where films are longer than 180 minutes, film language is 'English' and film category is not 'Action'.
In that case we can reuse above statement stmt, and just change our destination:

var dest2 []struct {
    model.Category

    Film []model.Film
    Actor []model.Actor
}

err = stmt.Query(db, &dest2)
handleError(err)
`dest2` json:
[
	{
		"CategoryID": 8,
		"Name": "Family",
		"LastUpdate": "2006-02-15T09:46:27Z",
		"Film": [
			{
				"FilmID": 499,
				"Title": "King Evolution",
				"Description": "A Action-Packed Tale of a Boy And a Lumberjack who must Chase a Madman in A Baloon",
				"ReleaseYear": 2006,
				"LanguageID": 1,
				"RentalDuration": 3,
				"RentalRate": 4.99,
				"Length": 184,
				"ReplacementCost": 24.99,
				"Rating": "NC-17",
				"LastUpdate": "2013-05-26T14:50:58.951Z",
				"SpecialFeatures": "{Trailers,\"Deleted Scenes\",\"Behind the Scenes\"}",
				"Fulltext": "'action':5 'action-pack':4 'baloon':21 'boy':10 'chase':16 'evolut':2 'king':1 'lumberjack':13 'madman':18 'must':15 'pack':6 'tale':7"
			},
			{
				"FilmID": 50,
				"Title": "Baked Cleopatra",
				"Description": "A Stunning Drama of a Forensic Psychologist And a Husband who must Overcome a Waitress in A Monastery",
				"ReleaseYear": 2006,
				"LanguageID": 1,
				"RentalDuration": 3,
				"RentalRate": 2.99,
				"Length": 182,
				"ReplacementCost": 20.99,
				"Rating": "G",
				"LastUpdate": "2013-05-26T14:50:58.951Z",
				"SpecialFeatures": "{Commentaries,\"Behind the Scenes\"}",
				"Fulltext": "'bake':1 'cleopatra':2 'drama':5 'forens':8 'husband':12 'monasteri':20 'must':14 'overcom':15 'psychologist':9 'stun':4 'waitress':17"
			}
		],
		"Actor": [
			{
				"ActorID": 1,
				"FirstName": "Penelope",
				"LastName": "Guiness",
				"LastUpdate": "2013-05-26T14:47:57.62Z"
			},
			{
				"ActorID": 20,
				"FirstName": "Lucille",
				"LastName": "Tracy",
				"LastUpdate": "2013-05-26T14:47:57.62Z"
			},
			{
				"ActorID": 36,
				"FirstName": "Burt",
				"LastName": "Dukakis",
				"LastUpdate": "2013-05-26T14:47:57.62Z"
			},
			{
				"ActorID": 70,
				"FirstName": "Michelle",
				"LastName": "Mcconaughey",
				"LastUpdate": "2013-05-26T14:47:57.62Z"
			},
			{
				"ActorID": 118,
				"FirstName": "Cuba",
				"LastName": "Allen",
				"LastUpdate": "2013-05-26T14:47:57.62Z"
			},
			{
				"ActorID": 187,
				"FirstName": "Renee",
				"LastName": "Ball",
				"LastUpdate": "2013-05-26T14:47:57.62Z"
			},
			{
				"ActorID": 198,
				"FirstName": "Mary",
				"LastName": "Keitel",
				"LastUpdate": "2013-05-26T14:47:57.62Z"
			}
		]
	},
    ...

Complete code example can be found at ./examples/quick-start/quick-start.go

Contributing

Versioning

Licence