dyndao

module
v0.0.0-...-22ac7ce Latest Latest
Warning

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

Go to latest
Published: Jan 21, 2018 License: MIT

README

dyndao

DYNamic Data Access Object (in Go)

JSON <-> object.Object <-> RDBMS

dyndao is a dynamic Golang ORM, drawing influence from the Active Record pattern, Martin Fowler's Data Mapper pattern, and the author's experience with Perl's database packages (DBI, Class::DBI, DBIx::Class, etc.)

Currently, basic support for the following databases is included:

  • SQLite
  • MySQL
  • Microsoft SQL Server
  • Oracle
  • Postgres
  • CockroachDB

If you encounter problems using dyndao with any of the currently supported databases, please feel free to file a detailed issue.

dyndao started out due to the fact that Go lacks a 'very dynamic' ORM, and the author had some requirements for dynamic schemas and a vision for multiple database support. The goal is not to support every feature of every database, but provide a common set of data types and abstractions which allow a developer to deliver an application that supports a myriad of underlying storage mechanisms.

DATA TYPES, RELATIONAL JSON, ETC.

If you have legacy requirements and specific data type requirements, dyndao may or may not be the right solution for you. If you have more control over your selection of data types, then it's more likely that dyndao could be a good fit.

The basic data types currently supported are: strings, integers, clobs / blobs, floats, and timestamps.

The reasoning here is that dyndao is geared towards systems which utilize a 'relational JSON' approach - the trend of only defining certain columns to exist on a table, typically primary keys and timestamps, and then adding a JSON document to support an arbitrary number of additional data attributes.

Additionally, systems utilizing JSON for RPC can trivially support additional nested complex structures, which may be mapped using arbritrarily and dynamically configured data mapping rules. Dyndao's object package can help serve as a Data Transfer Object, implicitly supporting serialization and enabling data transfer across services.

Thus, not all additions or removal of data attributes will require schema changes, because the JSON document column can be leveraged to store them. This provides some of the benefits of NoSQL in conjunction with the relational and ACID benefits of SQL.

Since many relational databases are adding support for indexing JSON documents and directly querying them within a WHERE clause, this idea is believed to be sound.

Additionally, many relational databases support data types which offer inconsistent functionality despite having similar names. The possible length of one column data type for a given database may be completely different from another (TODO: provide examples). One of dyndao's design goals is to help steer developers towards multiple-database compatibility where possible. As such, few of the abstractions dyndao offers will match what is commonly expected for Go data types and access patterns.

DYNAMIC SCHEMAS

See github.com/rbastic/dyndao/schema for how dyndao supports dynamic schemas.

There are several options for the dyndao user. Declare a schema using Go code. Edit one directly in JSON and have some code that unmarshals it. Or, if the underlying database being used is well-supported, then dyndao's schema/parser sub-packages can be utilized to dynamically load a schema at run-time.

MISC

An additional feature that dyndao supports is a type named object.SQLValue, which lets you explicitly store values that will be rendered as SQL function calls (and other unquoted values), without making the mistake of constructing them as binding parameters.

NULL values mapped from the database will also be internally mapped using the object.NewNULLValue() method. This is in contrast to how Go's sql.NullString data types, etc., work. Those types are still utilized underneath the hood where necessary for mapping purposes, but to provide a common abstraction, the type object.SQLValue is used, with the internal SQLValue string being set with a value of "NULL".

This is to help with supporting scanning of NULL values across the myriad of databases supported -- a feature that seems otherwise contentious to implement within dyndao's design, due to some database drivers offering their own NULL types.

I specifically mention this as an example because I have not yet seen an ORM support this particular feature in Go, and dyndao's design lends itself to using the object.SQLValue for other things, which are not yet covered here. Here is an example of the initial use case:

UPDATE fooTable SET ..., UPDATE_TIMESTAMP=NOW() WHERE fooTable_ID = 1;

NOW() is the current timestamp function call (at least in MySQL).

Presently, the way dyndao is written, you could do something like:

myORM = getORM() // see tests for example
obj, err := myORM.Retrieve(ctx, tableString, pkValues)
if err != nil {
	return errors.Wrap(err, "Retrieve")
}

// Lack of result is not considered an error in dyndao - "nil, nil" would be
// returned
if obj == nil {
	return errors.New("no object available to update")
} else {
	// obj is a dyndao/object, see github.com/rbastic/dyndao/object
	obj.Set("UPDATE_TIMESTAMP", object.NewSQLValue("NOW()"))
	// nil below means 'transactionless save', otherwise you can pass your own
	// *sql.Tx
	r, err := myORM.Save(ctx, nil, obj)
	if err != nil {
		return err
	}
	// ...
}

So, instead of representing rows as structs like other ORMs, you represent them as pointers to object.Object (see github.com/rbastic/dyndao/object for details).

Note, one should not have to hard-code the NOW() function, because if the underlying database changes to say, Oracle, it will not work. Some work is underway to explore how better cross-platform support for date- and timestamp- handling can be implemented.

CODE LAYOUT

object - object.Object and object.Array

schema - schema definitions and supporting types

orm    - Bridge pattern-influenced package combining schema, sqlgen, and
	 object.

adapters - SQL statement generators for various database implementations

sqlgen - Specifies SQL Generator vtables

mapper - Custom JSON mapping layers (WIP)

CONTEXT CHECKING

dyndao no longer requires you to check your own contexts.

DISCLAIMER

This package is a work in progress. While much of the code is regularly tested on production workloads, please use it at your own risk. Suggestions and patches are welcome. Currently, I reserve the right to refactor the API at any time.

If you find yourself using this package to do cool things, please let me know. :-)

THANKS

The author would like to express his sincere thanks to Rob Hansen (github.com/rhansen2), without whom this library surely would have suffered.

LICENSE

dyndao is released under the MIT license. See LICENSE file.

Directories

Path Synopsis
adapters
common
Package common encapsulates common functionality that can be leveraged by all (or almost all) necessary database adapters.
Package common encapsulates common functionality that can be leveraged by all (or almost all) necessary database adapters.
core
Package core encapsulates an implementation for a given schema attached to a generator.
Package core encapsulates an implementation for a given schema attached to a generator.
db2
mysql
Package mysql encapsulates an implementation for a given schema attached to a generator.
Package mysql encapsulates an implementation for a given schema attached to a generator.
oracle
Package oracle encapsulates an implementation for a given schema attached to a generator.
Package oracle encapsulates an implementation for a given schema attached to a generator.
sqlite
Package sqlite encapsulates an implementation for a given schema attached to a generator.
Package sqlite encapsulates an implementation for a given schema attached to a generator.
examples
migrator
This is a sample Oracle->MySQL schema migrator.
This is a sample Oracle->MySQL schema migrator.
Package jsonmapper is a DAO mapper for mapping between JSON, an generic object, and a configurable database schema
Package jsonmapper is a DAO mapper for mapping between JSON, an generic object, and a configurable database schema
experiments
Package mapper is a DAO mapper for mapping between JSON, an generic object, and a configurable database schema
Package mapper is a DAO mapper for mapping between JSON, an generic object, and a configurable database schema
Package object is an abstract data record which tracks state changes.
Package object is an abstract data record which tracks state changes.
Package dao is the data access object swiss army knife / "black box".
Package dao is the data access object swiss army knife / "black box".

Jump to

Keyboard shortcuts

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