Marlow is a code generation tool written in golang designed to create useful constructs that provide an ergonomic API for interacting with a project's data persistence layer while maintaining strong compile time type safety assurance.
Marlow was created to improve developer velocity on projects written in golang that interact with a data persistence layer, like mysql or postgres. In other web application backend environments, these interfaces are usually provided by an application framework's ORM, like the ActiveRecord library used by Rails.
For web applications leveraging the benefits of using golang, it can be difficult to construct the equivalent
abstraction of their database that provides crud operations - especially one that is type-safe and dry. There are
several open source projects in the golang ecosystem who's goal is exactly that; gorm
, beego
, and gorp
to
name a few. Marlow differs from these other projects in its philosophy; rather than attempt to provide an
eloquent orm for your project at runtime, it generates a tailored solution at compile time.
At its core, marlow simply reads a package's field tags and generates valid golang code. The marlowc
executable
can be installed & used directly via:
go get -u github.com/dadleyy/marlow/marlowc
marlowc -input=./examples/library/models -stdout=true
For a full list of options supported by the compiler refer to marlowc -help
. The command line tool can also be used
as the executable target for golang's go generate
command using //go:generate
comment syntax:
package models
//go:generate marlow -input=book.go
type Book struct {
ID string `marlow="column=id"`
AuthorID string `marlow="column=author_id"`
}
The generated files will live in the same directory as their source counterparts, with an optional suffix to
distinguish them (useful if a project is using make
to manage the build pipeline). In general it is encouraged that
the generated files are not committed to your project's revision control; the source should always be generated
immediately before the rest of the package's source code is compiled.
The compiler parses the marlow
field tag value using the net/url
package's parseQuery
function. This means that
each configuration option supported by marlow would end up in delimited by the ampersand (&
) character where the key
and value are separated by an equal sign (=
). For example, a user record may look like:
package Model
type User struct {
table string `marlow:"tableName=users"`
ID uint `marlow:"column=id"`
Name string `marlow:"column=name"`
Email string `marlow:"column=name"`
}
In this example, marlow would create golang code that would look (not exactly) like this:
func (s *UserStore) FindUsers(query *UserQuery) ([]*User, error) {
out := make([]*User, 0)
// ...
_rows, e := s.DB.Query(_generatedSQL) // e.g "SELECT id, name FROM users ..."
// ...
for _rows.Next() {
var _u User
if e := _rows.Scan(&u.Id, &u.Name); e != nil {
return e
}
out = append(out, &_u)
}
// ...
}
Special table
field
If present, marlow will recognize the table
field's marlow
tag value as a container for developer specified
overrides for default marlow assumptions about the table.
Option | Description |
---|---|
tableName |
The name of the table (marlow will assume a lowercased & pluralized version of the struct name). |
defaultLimit |
When using the queryable feature, this will be the default maximum number of records to load. |
storeName |
The name of the store type that will be generated, defaults to %sStore , where %s is the name of the struct. |
blueprintRangeFieldSuffix |
A string that is added to numerical blueprint fields for range selections. |
blueprintLikeFieldSuffix |
A string that is added to string/text blueprint fields for like selections. |
All other fields
Option | Description |
---|---|
column |
This is the column that any raw sql generated will target when scanning/selecting/querying this field. |
generated coverage badge provided by gendry