
Toyorm – ORM for Go - bigpigeon
https://github.com/bigpigeon/toyorm
======
tptacek
I've come to the conclusion --- maybe wrong? --- that Go doesn't want you to
do ORM this way. For awhile I thought Go didn't want you to do ORM at all
(which would be problematic for me, because I think writing SQL is a huge
waste of time). But now I think it just doesn't want you to use ORMs that look
like Django or ActiveRecord.

Instead of defining and marking up structs and setting up hooks and
configuring registries of objects and stuff, just give up on dynamic ORM and
switch to codegen.

I wrote a codegen ORM in a weekend that turned out much more pleasant to use
than anything like gorm, not least because everything was just plain-
ol'-Golang-code. All I really needed to write was the minimal Go code to dump
a schema from Postgres, and then a bunch of text/template templates for all
the functions I wanted. I got associations in just a couple functions.

I would have published, but it looks like 100 people had this thought before I
did. sqlboiler seems like the most mature (I didn't look that carefully). But
you could seriously just write your own. If I had to do it again, I'd probably
codegen something on top of Squirrel.

~~~
bigpigeon
yes, codegen have better performance than reflect

but I think text/template to generate code is not really good

it hard to read and error-prone

it is more like a powerful c-macro

I think use go/ast to implement c++ likes template is other way

~~~
tptacek
Whatever works! I just wrote the functions I wanted normally, tested them,
then converted them to templates.

------
nemothekid
As far as Go ORMs go, there isn’t a decent one that handles what I consider a
killer feature of ORMs - relationships. I think sqlx is good enough for most,
but I once inherited a project that the management wanted to rewrite off of
Scala to Go. Some of the relationships were so complex that hand writing
complex joins would have been challenging. Gorm came closest, but it’s “eager
fetching” features executes n+1 queries rather than joins.

~~~
astockwell
Yes yes and yes. Unless the usecase is truly as simple as CRUD with a single
model (in which case I reach for gorm), The easiest road often seems to be
just using sqlx and hand-writing the inserts/updates.

~~~
swah
What about 90% of cases being simple CRUD and 10% you just do the usual "raw
SQL query"?

I've chosen this path of using only sqlx on my current work project (only me)
and regret it, because so much typing..

~~~
bm1362
I also work alone on a Go service and have some complex models. I used Gorm
and then for complex selects broke out the raw sql. It works okay, I’m still
having to bolt on things like OCC and Versioning to my models. I’m glad I used
it though- it gave me a solid foundation to work off and replace the bits that
don’t quite work well.

------
andreygrehov
Off-topic: any reason why so many Go repositories have a flat structure?
Wouldn't it be nicer to organize all the *.go files?

~~~
jbboehr
Part of is is probably because subfolders are subpackages and relative imports
don't work and absolute imports have other issues - like causing issues with
forking.

~~~
littlestymaar
> because subfolders are subpackages and relative imports don't work

Really ? Is that a bug, or by design ? If the later, what's the rationnal
about it ?

~~~
jbboehr
IIRC the tooling is not smart enough to resolve them when you import a
subpackage directly.

I was working on a go project and I had to convert all of the relative imports
to absolute imports for some reason, but the exact cause escapes my memory.

------
it
It seems like it would be easier to talk to dbs if we had a way to work
directly with tables in Go, but it's not clear how to do that without
resorting to the empty interface. R is great at dealing with tables so maybe
it could be looked to as an example.

------
beagledude
It's going to be hard to unseat GORM gorm.io/docs/query.html

~~~
bigpigeon
when you want to make complex sql,toyorm maybe word better

find the name = "tom" user and it subquery blog title = "first blog" e.g

    
    
      brick := toy.Model(&User{}).Where("=",Offsetof(User{}.Name),"tom").
    			Preload(Offsetof(User{}.Blog)).Where("=", Offsetof(Blog{}.Title), "first blog").Enter()
    
      brick.Find(&user)
      // raw sql
      // select id,name,data, from user where name = "tom" limit 1
      // select id,title,content,user_id from blog where user_id = @user.id and title = "first blog"
    

toyorm select field with Offsetof, it better when you want to refactor struct
field name and you can operation main query as sub query

------
warent
Why would I use this vs. something like Gorp? How is Toyorm differentiated?

~~~
bigpigeon
preload: data association exec/query template exec: custom exec/query this is
my orm great features

------
bigpigeon
toyorm v0.3.1-alpha add join query

