Hi Thomas,

I’ve thought about writing something like this. My postgreSQL queries go 
through database/sql and github.com/lib/pq and are concatenated strings 
with + and constants in most cases, and sometimes with Sprintf to write an 
index naming a column. This approach is hard to read. I have this issue 
about that: https://github.com/pciet/wichess/issues/49. It looks like your 
team has a lot more experience with SQL than me.

One thought is that the SQL seems to differ between relational database 
implementations. I’ve argued that database/sql should be a helper library 
instead of a gateway library because of this. Perhaps 
github.com/ulule/loukoum could be a way to hide those database differences 
from query construction? The goal would be to make servers using SQL 
relational database independent.

Anyway, here’s a code review.

I haven’t seen a library that exposes the API this way, with one file 
importing the sub-packages. While this seems clean I’ve been arguing for 
more use of flat packages in cases like this. For example, “type Map = 
types.Map” would be unnecessary if there was no types package. The 
functions here also require knowledge of the sub-packages anyway since they 
return types from those packages.

I prefer package names with a hint to what they do. The meaning of 
loukoum.Pair(…) can’t be inferred. Something like sqlb.Pair(…) would be my 
choice.

“func ToColumns(values []interface{})” isn’t clear to me. From the 
implementation it can either be a slice with one element of []stmt.Column 
or []string, or a slice of stmt.Column or string. I’ve been suggesting 
adding a type for interface{} in cases like this that documents what the 
expected types are:

// A Column can be string or stmt.Column.
type Column interface{}

I’m only saying this because these are exported functions of 
github.com/ulule/loukoum/builder, if they were private functions then the 
code may be documentation enough.

To me this shows that something might be improved to avoid this need in the 
library code:

var _ Builder = Delete{}

Along with that, I’m not sure about the Builder interface. If the interface 
is not part of a function call in the same file or package I’m worried. 
I’ve previously suggested grouping behavior as a struct type of function 
fields instead of relying on a type hierarchy, or there may be other ways 
to do it, but an interface should have an obvious use locally. Maybe having 
the flat package would make this interface more clear.

Again, the “type Select struct { query stmt.Select }” seems like a symptom 
of package overuse.

In lexer:

l := Lexer{}
l.input = buffer

could instead be

l := Lexer{input: buffer}

In stmt I’m not sure what this means:

func (Between) expression() {}

Why

// and Limit, Offset, OrderBy, Prefix, Using, Values, Where
type Value struct { Value interface{} }

instead of

type Value interface{}

Generally I could see function types and closures being useful, I’m not 
seeing those anywhere.

This kind of thing is a lot of work to get right and has the overhead of 
copying anything assigned to an interface{}:

type Map map[interface{}]interface{}

Maybe there’s a better way?

Thanks for the MIT licensing.

Matt

On Tuesday, February 27, 2018 at 11:57:42 AM UTC-6, Thomas LE ROUX wrote:
>
> Hi,
>
> I'd like to announce a new open source project from Ulule: *Loukoum *
> (https://github.com/ulule/loukoum)
>
> *.*It's a simple query builder that will help you to generate complex 
> queries without SQL injection. 
> If you're not using an ORM, you should give it a try.
>
> At the moment, we only support *PostgreSQL. *
> But feel free to contribute and give your feedback :)
>
>
> Cheers,
> Thomas.
>

-- 
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to golang-nuts+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to