Skip to content
This repository has been archived by the owner on Aug 18, 2020. It is now read-only.
/ marlow Public archive

golang generator for type-safe sql api constructs

License

Notifications You must be signed in to change notification settings

dadleyy/marlow

Repository files navigation


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.


travis.img codecov.img report.img godoc.img tag.img commits.img awesome.img generated-coverage.img


Objective & Inspiration

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.

Useage

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.

Field Tag Configuration

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.

logo

generated coverage badge provided by gendry