argen

An ORM code-generation tool for Go, provides ActiveRecord-like functionality for your types.

  • Owner: monochromegane/argen
  • Platform:
  • License:: MIT License
  • Category::
  • Topic:
  • Like:
    0
      Compare:

Github stars Tracking Chart

argen

argen is an ORM code-generation tool for Go, provides ActiveRecord-like functionality for your types.

Installation

$ go get -u github.com/monochromegane/argen/...

Quick start

  1. Define a table mapping struct in main.go.
  2. Mark it up with a +AR annotation in an adjacent comment like so:
//+AR
type User struct{
	Id int `db:"pk"`
	Name string
	Age int
}

And at the command line, simply type:

$ argen main.go

You should see new files, named *_gen.go.

And you can use ActiveRecord-like functions.

db, _ := sql.Open("sqlite3", "foo.db")
Use(db)

u := User{Name: "test", Age: 20}
u.Save()
//// INSERT INTO users (name, age) VALUES (?, ?); [test 20]

User{}.Where("name", "test").And("age", ">", 20).Query()
//// SELECT users.id, users.name, users.age FROM users WHERE name = ? AND age > ?; [test 20]

ActiveRecord-like functions

Setup

db, _ := sql.Open("sqlite3", "foo.db")

// Set db
Use(db)

Create record

u := User{Name: "test", Age: 20}
u.Save()

or

// XxxParams has same fields to original type.
User{}.Create(UserParams{Name: "test", Age: 20})

Query

// Get the first record
User{}.First()
//// SELECT users.id, users.name, users.age FROM users ORDER BY id ASC LIMIT ?; [1]

// Get the last record
User{}.Last()
//// SELECT users.id, users.name, users.age FROM users ORDER BY id DESC LIMIT ?; [1]

// Get the record by Id
User{}.Find(1)
//// SELECT users.id, users.name, users.age FROM users WHERE id = ? LIMIT ?; [1 1]

// Get all record
User{}.All().Query()
//// SELECT users.id, users.name, users.age FROM users;

Query with conditions

// Get the first matched record
User{}.FindBy("name", "test")
//// SELECT users.id, users.name, users.age FROM users WHERE name = ? LIMIT ?; [test 1]

// Get the first matched record
User{}.Where("name", "test").QueryRow()
//// SELECT users.id, users.name, users.age FROM users WHERE name = ?; [test]

// Get the all matched records
User{}.Where("name", "test").Query()
//// SELECT users.id, users.name, users.age FROM users WHERE name = ?; [test]

// And
User{}.Where("name", "test").And("age", ">", 20).Query()
//// SELECT users.id, users.name, users.age FROM users WHERE name = ? AND age > ?; [test 20]
// Count
User{}.Count()
//// SELECT COUNT(*) FROM users;

// Exists
User{}.Exists()
//// SELECT 1 FROM users LIMIT ?; [1]

// Select
User{}.Select("id", "name").Query()
//// SELECT users.id, users.name FROM users;

// Order
User{}.Order("name", "ASC").Query()
//// SELECT users.id, users.name, users.age FROM users ORDER BY name ASC;

// Limit and offset
User{}.Limit(1).Offset(2).Query()
//// SELECT users.id, users.name, users.age FROM users LIMIT ? OFFSET ?; [1 2]

// GroupBy and having
User{}.Group("name").Having("count(name)", 2).Query()
//// SELECT users.id, users.name, users.age FROM users GROUP BY name HAVING count(name) = ?; [2]

Update

user, _ := User{}.Find(1)

// Update an existing struct
user.Name = "a"
user.Save()
//// UPDATE users SET id = ?, name = ?, age = ? WHERE id = ?; [1 a 20 1]

// Update attributes with validation
user.Update(UserParams{Name: "b"})
//// UPDATE users SET id = ?, name = ?, age = ? WHERE id = ?; [1 b 20 1]

// Update attributes without validation
user.UpdateColumns(UserParams{Name: "c"})
//// UPDATE users SET id = ?, name = ?, age = ? WHERE id = ?; [1 b 20 1]

Delete

user, _ := User{}.Find(1)

// Delete an existing struct
user.Destroy()
//// DELETE FROM users WHERE id = ?; [1]

Associations

Has One

Add association function to your type:

func (m User) hasOnePost() *ar.Association {
        return nil
}

And type argen or go generate on your command line.

user, _ := User{}.Create(UserParams{Name: "user1"})
user.BuildPost(PostParams{Name: "post1"}).Save()

// Get the related record
user.Post()
//// SELECT posts.id, posts.user_id, posts.name FROM posts WHERE user_id = ?; [1]

// Join
user.JoinsPost().Query()
//// SELECT users.id, users.name, users.age FROM users INNER JOIN posts ON posts.user_id = users.id;

Has Many

Add association function to your type:

func (m User) hasManyPosts() *ar.Association {
        return nil
}

And type argen or go generate on your command line.

user, _ := User{}.Create(UserParams{Name: "user1"})
user.BuildPost(PostParams{Name: "post1"}).Save()

// Get the related records
user.Posts()
//// SELECT posts.id, posts.user_id, posts.name FROM posts WHERE user_id = ?; [1]

// Join
user.JoinsPosts()
//// SELECT users.id, users.name, users.age FROM users INNER JOIN posts ON posts.user_id = users.id;

Belongs To

Add association function to your type:

func (p Post) belongsToUser() *ar.Association {
        return nil
}

And type argen or go generate on your command line.

u, _ := User{}.Create(UserParams{Name: "user1"})
post, _ := u.BuildPost(PostParams{Name: "post1"})
post.Save()

// Get the related record
post.User()
//// SELECT users.id, users.name, users.age FROM users WHERE id = ?; [1]

// Join
post.JoinsUser().Query()
//// SELECT posts.id, posts.user_id, posts.name FROM posts INNER JOIN users ON users.id = posts.user_id;

Validation

Add validation function to your type:

func (u User) validatesName() ar.Rule {
	// Define rule for "name" column
	return ar.MakeRule().Format().With("[a-z]")
}

You specify target column by naming validatesXxx.

Rules

// presence
Presence()

// format
Formart().With("regex")

// numericality
Numericality().OnlyInteger().GreaterThan(10)

Trigger

// OnCreate
OnCreate()

// OnUpdate
OnUpdate()

Method chain

Validation rules has a chainable API. you could use it like this.

ar.MakeRule().
	Presence().
	Format().With("[a-z]").
	OnCreate()

Custom validation

Add custom validation function to your type:

func (p Post) validateCustom() ar.Rule {
        return ar.CustomRule(func(errors *ar.Errors) {
                if p.Name != "name" {
                        errors.Add("name", "must be name")
                }
        }).OnUpdate()
}

And type argen or go generate on your command line.

Error

u := User{Name: "invalid name"}
_, errs := u.IsValid()
if errs != nil {
	fmt.Errorf("%v\n", errs.Messages["name"])
}

Log

LogMode(true)

go generate

If you want to generate it by using go generate, you mark it up an annotation at top of file.

//go:generate argen

and type:

$ go generate

Code status

Build Status

TODO

  • Transaction
  • Callbacks (before/after save)
  • Conditions for callbacks and validations.
  • AS clause
  • Log options

Author

monochromegane

License

argen is licensed under the MIT

Main metrics

Overview
Name With Ownermonochromegane/argen
Primary LanguageGo
Program languageGo (Language Count: 1)
Platform
License:MIT License
所有者活动
Created At2015-02-26 12:31:20
Pushed At2016-06-14 15:21:45
Last Commit At2015-07-11 23:01:48
Release Count0
用户参与
Stargazers Count197
Watchers Count9
Fork Count14
Commits Count147
Has Issues Enabled
Issues Count2
Issue Open Count1
Pull Requests Count5
Pull Requests Open Count0
Pull Requests Close Count1
项目设置
Has Wiki Enabled
Is Archived
Is Fork
Is Locked
Is Mirror
Is Private