Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up

Yet Another ORM for Golang

License

NotificationsYou must be signed in to change notification settings

geoffreybauduin/yaorm

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

59 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Build StatusGo Report CardCoverage Status

Important notice

YAORM is not maintained anymore.

This is another ORM. Another one.

Concept

  • Declare a bit more of code to handle all your models the same way
  • Use filters to select data
  • With good coding practices, it becomes easy to use and easy to read

Must-do

  • Models should composeyaorm.DatabaseModel in order to correctly implement theyaorm.Model interface
  • Filters should composeyaorm.ModelFilter in order to correctly implement theyaorm.Filter interface

Models by examples

Declaration

package mainimport ("time""github.com/geoffreybauduin/yaorm")funcinit() {yaorm.NewTable("test","category",&Category{})}typeCategorystruct {// Always compose this struct    yaorm.DatabaseModelIDint64`db:"id"`Namestring`db:"name"`CreatedAt time.Time`db:"created_at"`UpdatedAt time.Time`db:"updated_at"`}

Loading a model

Using a generic function

package mainimport ("time""github.com/geoffreybauduin/yaorm""github.com/geoffreybauduin/yaorm/yaormfilter")funcinit() {yaorm.NewTable("test","category",&Category{}).WithFilter(&CategoryFilter{})}typeCategorystruct {// Always compose this struct    yaorm.DatabaseModelIDint64`db:"id"`Namestring`db:"name"`CreatedAt time.Time`db:"created_at"`UpdatedAt time.Time`db:"updated_at"`}typeCategoryFilterstruct {// Always compose this struct    yaormfilter.ModelFilterFilterID   yaormfilter.ValueFilter`filter:"id"`}funcGetCategory(dbp yaorm.DBProvider,idint64) (*Category,error) {category,err:=yaorm.GenericSelectOne(dbp,&filter.CategoryFilter{FilterID:yaormfilter.Equals(id)})returncategory.(*Category),err}// GetCategoryLight only loads "id" and "name" columns (other fields// won't be initialized in returned *Category).funcGetCategoryLight(dbp yaorm.DBProvider,idint64) (*Category,error) {f:= filter.CategoryFilter{FilterID:yaormfilter.Equals(id)}f.LoadColumns("id","name")category,err:=yaorm.GenericSelectOne(dbp,&f)returncategory.(*Category),err}// GetCategoryNoDates does not load "created_at" and "updated_at"// columns (these fields won't be initialized in returned *Category).funcGetCategoryNoDates(dbp yaorm.DBProvider,idint64) (*Category,error) {f:= filter.CategoryFilter{FilterID:yaormfilter.Equals(id)}f.DontLoadColumns("created_at","updated_at")category,err:=yaorm.GenericSelectOne(dbp,&f)returncategory.(*Category),err}

Using the model's load function

package mainimport ("time""github.com/geoffreybauduin/yaorm""github.com/geoffreybauduin/yaorm/yaormfilter")funcinit() {yaorm.NewTable("test","category",&Category{}).WithFilter(&CategoryFilter{})}typeCategorystruct {// Always compose this struct    yaorm.DatabaseModelIDint64`db:"id"`Namestring`db:"name"`CreatedAt time.Time`db:"created_at"`UpdatedAt time.Time`db:"updated_at"`}typeCategoryFilterstruct {// Always compose this struct    yaormfilter.ModelFilterFilterID   yaormfilter.ValueFilter`filter:"id"`}// Load loads into the model filtering by the already defined values// it is necessary to override this function if you want to be able to automatically Load modelsfunc (c*Category)Load(dbp yaorm.DBProvider)error {returnyaorm.GenericSelectOneFromModel(dbp,c)}funcGetCategory(dbp yaorm.DBProvider,idint64) (*Category,error) {category:=&Category{ID:id}returncategory,category.Load(dbp)}

Saving a model

NB: saving includes both inserting and updating

Using a generic function

package mainimport ("time""github.com/geoffreybauduin/yaorm""github.com/geoffreybauduin/yaorm/yaormfilter")funcinit() {yaorm.NewTable("test","category",&Category{}).WithFilter(&CategoryFilter{})}typeCategorystruct {// Always compose this struct    yaorm.DatabaseModelIDint64`db:"id"`Namestring`db:"name"`CreatedAt time.Time`db:"created_at"`UpdatedAt time.Time`db:"updated_at"`}typeCategoryFilterstruct {// Always compose this struct    yaormfilter.ModelFilterFilterID   yaormfilter.ValueFilter`filter:"id"`}funcCreateCategory(dbp yaorm.DBProvider,namestring) (*Category,error) {category:=&testdata.Category{Name:name}returncategory,yaorm.GenericSave(category)}

Using the model's save function

package mainimport ("time""github.com/geoffreybauduin/yaorm""github.com/geoffreybauduin/yaorm/yaormfilter")funcinit() {yaorm.NewTable("test","category",&Category{}).WithFilter(&CategoryFilter{})}typeCategorystruct {// Always compose this struct    yaorm.DatabaseModelIDint64`db:"id"`Namestring`db:"name"`CreatedAt time.Time`db:"created_at"`UpdatedAt time.Time`db:"updated_at"`}typeCategoryFilterstruct {// Always compose this struct    yaormfilter.ModelFilterFilterID   yaormfilter.ValueFilter`filter:"id"`}// Save saves the current category inside the database// it is necessary to declare this method if you want to really save the modelfunc (c*Category)Save()error {returnyaorm.GenericSave(c)}funcCreateCategory(dbp yaorm.DBProvider,namestring) (*Category,error) {category:=&testdata.Category{Name:name}category.Save(dbp)returncategory,category.Save()}

Joining

package mainimport ("time""github.com/geoffreybauduin/yaorm""github.com/geoffreybauduin/yaorm/yaormfilter")funcinit() {yaorm.NewTable("test","category",&Category{}).WithFilter(&CategoryFilter{})yaorm.NewTable("test","post",&Post{}).WithFilter(&PostFilter{})}typeCategorystruct {// Always compose this struct    yaorm.DatabaseModelIDint64`db:"id"`Namestring`db:"name"`CreatedAt time.Time`db:"created_at"`UpdatedAt time.Time`db:"updated_at"`}typeCategoryFilterstruct {// Always compose this struct    yaormfilter.ModelFilterFilterID   yaormfilter.ValueFilter`filter:"id"`}typePoststruct {    yaorm.DatabaseModelIDint64`db:"id"`Subjectstring`db:"subject"`CategoryIDint64`db:"category_id"`Category*Category`db:"-" filterload:"category,category_id"`}typePostFilterstruct {    yaormfilter.ModelFilterFilterCategory yaormfilter.Filter`filter:"category,join,id,category_id" filterload:"category"`}funcGetPostsFromCategory(dbp yaorm.DBProvider,category*Category) {posts,err:=yaorm.GenericSelectAll(dbp,&PostFilter{FilterCategory:&CategoryFilter{ID:yaormfilter.Equals(category.ID)}})}

And more...

Intestdata folder

The theory

Here's a list of what you can do with this library

Filtering on any model

You can filter on any model you declare by also coding aFilter object

  • Define the tagfilter on your filter struct, should be the same value than the db field you want to filter on
  • Declare your filter when you declare your sql table using theWithFilter helper.

No need to write SQL queries anymore.

package mainimport ("time""github.com/geoffreybauduin/yaorm""github.com/geoffreybauduin/yaorm/yaormfilter")funcinit() {yaorm.NewTable("test","category",&Category{}).WithFilter(&CategoryFilter{})}typeCategorystruct {// Always compose this struct    yaorm.DatabaseModelIDint64`db:"id"`Namestring`db:"name"`CreatedAt time.Time`db:"created_at"`UpdatedAt time.Time`db:"updated_at"`}typeCategoryFilterstruct {// Always compose this struct    yaormfilter.ModelFilterFilterID   yaormfilter.ValueFilter`filter:"id"`}

Automatic loading

You can automatically load your nested objects with a bit of code.

  • Define the tagfilterload on your model inside the linked struct
  • Define the tagfilterload on your filter inside the linked struct (should be the same tag value), and specify the corresponding key to match with (here it'sPost.category_id)
  • Define the subquery loading function withWithSubqueryloading helper while you declare the sql table
package mainimport ("time""github.com/geoffreybauduin/yaorm""github.com/geoffreybauduin/yaorm/yaormfilter")funcinit() {yaorm.NewTable("test","category",&Category{}).WithFilter(&CategoryFilter{}).WithSubqueryloading(func(dbp yaorm.DBProvider,ids []interface{}) (interface{},error) {returnyaorm.GenericSelectAll(dbp,NewCategoryFilter().ID(yaormfilter.In(ids...)))        },"id",    )yaorm.NewTable("test","post",&Post{}).WithFilter(&PostFilter{})}typeCategorystruct {// Always compose this struct    yaorm.DatabaseModelIDint64`db:"id"`Namestring`db:"name"`CreatedAt time.Time`db:"created_at"`UpdatedAt time.Time`db:"updated_at"`}typeCategoryFilterstruct {// Always compose this struct    yaormfilter.ModelFilterFilterID     yaormfilter.ValueFilter`filter:"id"`FilterName   yaormfilter.ValueFilter`filter:"name"`}funcNewCategoryFilter()*CategoryFilter {return&CategoryFilter{}}func (cf*CategoryFilter)ID (v yaormfilter.ValueFilter)*CategoryFilter {cf.FilterID=vreturncf}func (cf*CategoryFilter)Name (v yaormfilter.ValueFilter)*CategoryFilter {cf.FilterName=vreturncf}func (cf*CategoryFilter)Subqueryload() yaormfilter.Filter {cf.AllowSubqueryload()returncf}typePoststruct {    yaorm.DatabaseModelIDint64`db:"id"`Subjectstring`db:"subject"`CategoryIDint64`db:"category_id"`Category*Category`db:"-" filterload:"category,category_id"`}typePostFilterstruct {    yaormfilter.ModelFilterFilterCategory yaormfilter.Filter`filter:"category,join,id,category_id" filterload:"category"`}funcNewPostFilter()*PostFilter {return&PostFilter{}}func (pf*PostFilter)Category (category yaormfilter.Filter)*PostFilter {pf.FilterCategory=categoryreturnpf}funcGetPostsFromCategory(dbp yaorm.DBProvider,category*Category) {posts,err:=yaorm.GenericSelectAll(dbp,NewPostFilter().Category(NewCategoryFilter().Name(category.Name).Subqueryload(),    )// and then posts[0].Category won't be nil}

Hooks

SQL Executor

It is possible to define custom hooks while executing SQL requests. Possible hooks are currently:

  • Before/AfterSelectOne
  • Before/AfterSelect (multiple)

Your executor should implementyaorm.ExecutorHook interface, and can composeyaorm.DefaultExecutorHook to avoid any issues with updates (like a missing method to implement).The executor hook can be declared while registering the database

package mainimport ("log""github.com/geoffreybauduin/yaorm")typeLoggingExecutorstruct {*yaorm.DefaultExecutorHook}func (hLoggingExecutor)AfterSelectOne(querystring,args...interface{})  {log.Printf("SQL Query: %s %+v\n",query,args)}funcmain() {deferfunc() {os.Remove("/tmp/test_test.sqlite")yaorm.UnregisterDB("test")    }()yaorm.RegisterDB(&yaorm.DatabaseConfiguration{Name:"test",DSN:"/tmp/test_test.sqlite",System:yaorm.DatabaseSqlite3,AutoCreateTables:true,ExecutorHook:&LoggingExecutor{},    })// now it will use the executor}

Good practices

Filters

  • Define filters to be able to chain functions, it is a lot more readable !
typeCategoryFilterstruct {// Always compose this struct    yaormfilter.ModelFilterFilterID     yaormfilter.ValueFilter`filter:"id"`FilterName   yaormfilter.ValueFilter`filter:"name"`}funcNewCategoryFilter()*CategoryFilter {return&CategoryFilter{}}func (cf*CategoryFilter)ID (v yaormfilter.ValueFilter)*CategoryFilter {cf.FilterID=vreturncf}func (cf*CategoryFilter)Name (v yaormfilter.ValueFilter)*CategoryFilter {cf.FilterName=vreturncf}funcmain() {f:=NewCategoryFilter().ID(yaormfilter.Equals(1))}

Contributing

Contributions are welcomed. Don't hesitate to open a PR.

License

MIT License

Copyright (c) 2017 Geoffrey Bauduin

Permission is hereby granted, free of charge, to any person obtaining a copyof this software and associated documentation files (the "Software"), to dealin the Software without restriction, including without limitation the rightsto use, copy, modify, merge, publish, distribute, sublicense, and/or sellcopies of the Software, and to permit persons to whom the Software isfurnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in allcopies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ORIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THEAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHERLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THESOFTWARE.


[8]ページ先頭

©2009-2025 Movatter.jp