go-dbx

module
v1.20.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 31, 2024 License: BSD-3-Clause

README

DBX – DataBase eXtensions

DBX is a convenience layer built on database/sql and sqlx which aims to strike a very particular balance between automating SQL drudgery and telling you how to model or query your data.

DBX is not an ORM (but it does some ORM stuff)

Among other things, DBX:

  • Marshals fields from your structs into and out of a database,
  • Provides mechanisms for storing and fetching graphs of entities,
  • Makes very specific aspects of writing SQL easier.

Some of the things DBX does not do include:

  • Requiring you to interact with a Functional().Meta().Query().Language(),
  • Dictating any particular manner of modeling your data,
  • Generating source code or SQL (mostly).

Oh yeah and it's only really tested with Postgres, cause that's the only relational database I care about. Sorry.

It's Exampletown

Ok, so you've decided to completely rewrite your application to use DBX. Excellent decision. But where do you start? Let's talk about it.

Act One, in which we meet the entity

Let's say we have a simple entity in our Go program that we want to persist as a row in Postgres. It's modeled as the following struct.

type User struct {
  Id        string    `db:"id,pk"
  Username  string    `db:"username"
  Password  string    `db:"password"
  Notes     string    `db:"notes,omitempty"
  Created   time.Time `db:"created_at,omitempty"
}

We need to get this struct into this database table, which we have to write ourself, on purpose:

CREATE TABLE users (
  id          varchar(32)   primary key,
  username    varchar(32)   not null,
  password    varchar(64)   not null, -- bcrypt, because we're not dumb
  notes       text,
  created_at  timestamp with time zone not null default now()
);

Well, good news for us. Because this is exactly the sort of thing DBX was created for! That was extremely lucky.

Act Two, in which we persist the entity

What we need for this job is a persister. This is the high-level concept that deals with converting a struct to and from its database representation. Let's make one.

pst := persist.New(
  db, // make a *sqlx.DB somehow, I'm not your mom
  entity.DefaultFieldMapper(),
  registry.DefaultRegistry(),
  ident.AlphaNumeric(16),
)

We'll discuss some of those parameters later, but for the moment, note the last one. A persister sometimes needs to generate primary keys in order to insert new entities. ident.AlphaNumeric(16) returns a function that generates random alpha-numeric strings 16 characters long.

There are a few common generators in the ident package that will create UUIDs, ULIDs, and random strings. If those don't meet your needs you can easily write your own.

Ok, we have our persister now. Let's store an instance of our User type.

user := &User{
  Username: "cooldude",
  Password: "some long hash",
}

err := pst.Store("users", user, nil)
if err != nil {
  panic(err)
}

Now we have a database row like this:

| id | username | password | notes | created_at |
+----+----------+----------+-------+------------+
|jnjIYRgmCIC0oCUE | cooldude | some long hash | NULL | 2020-02-20 15:24:38.743665+00 |

As a special treat for us, before it persisted our entity, DBX used the identifier generator function we passed into our persister to create a new primary key for this record because it didn't have one. (If it did already have one, DBX would have performed an UPDATE using that key instead of an INSERT.)

So once the Store call succeeds we can reference user.Id, which will be populated with the persisted record's primary key.

Act Three, in which we restore the entity

Alright, let's fetch it back now and see what we're working with.

dup := &User{}
err = pst.Fetch("users, &dup, user.Id)
if err != nil {
  panic(err)
}

assertEqual(user, dup) // Sì – er, correcto

That which was lost is now found.

Directories

Path Synopsis
v1
filter
DEPRECATED: everything in this package is deprecated and will be removed in a future release.
DEPRECATED: everything in this package is deprecated and will be removed in a future release.
query
The `query` package replaces the `filter` package and improves support for both read- and write-oriented configuration options.
The `query` package replaces the `filter` package and improves support for both read- and write-oriented configuration options.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL