Skip to content

Instantly share code, notes, and snippets.

@snusnu
Last active December 30, 2015 08:08
Show Gist options
  • Save snusnu/7800261 to your computer and use it in GitHub Desktop.
Save snusnu/7800261 to your computer and use it in GitHub Desktop.
require 'axiom-schema'
# A schema (definition) is pure RA, no RDMBS
# concepts are in the mix. Those are only
# added with Axiom::Database objects shown
# further below. Even renaming of attributes
# is not done at this level. It's database
# business. Internally, this is implemented
# by performing a #rename op on an axiom
# relation tho.
#
# The following returns an Axiom::Schema::Definition
# instance which exposes a registry of objects that
# basically wrap a relation AST node and may or may
# not provide additional API useful to the DSL. For
# example it might expose attribute names by relying
# on #method_missing (this might be useful for FK
# references shown in the DSL for Database objects
# further below)
#
schema_definition = Axiom::Schema.define do
base_relation :people do
attribute :id, Integer
attribute :name, String
attribute :email, String
key :id
end
base_relation :orders do
attribute :id, Integer
key :id
foreign_key :person_fk, person_id: people.id
end
base_relation :items do
attribute :id, Integer
key :id, primary: true
end
base_relation :line_items do
foreign_key :order_fk, order_id: orders.id
foreign_key :item_fk, item_id: items.id
key :order_id, :item_id
end
base_relation :prices do
attribute :id, Integer
key :id
foreign_key :item_fk, item_id: items.id
end
relation :people_orders do
people.join(orders.rename(person_id: :id, id: :order_id))
end
end
# Handy shortcuts for the schema slice operations further below
CUSTOMER_RELATIONS = [
:people,
:orders,
:line_items
].freeze
ITEM_RELATIONS = [
:items,
:prices
].freeze
# Obviously those are not yet finished ...
#
# require 'axiom-postgres-adapter'
# require 'axiom-mongo-adapter'
# These return a new schema definition containing only the given relations
customer_relations = schema_definition.slice(CUSTOMER_RELATIONS)
item_relations = schema_definition.slice(ITEM_RELATIONS)
PG_URI = 'postgres://localhost/customer_data'
MG_URI = 'mongo://localhost/item_data'
# -------------------------------------------------------------------
# DSL alternative (1) (optimized for schemas setup in multiple files)
# -------------------------------------------------------------------
# Axiom::Database will provide (at least) the following methods
#
# .build
# .new
# #each (iterate over all gateway relations)
# #install (execute DDL generated by #to_s)
# #upgrade (execute DDL generated by some diff strategy)
# #to_s (return DDL statements needed to persist this database schema)
#
customer_data = Axiom::Database.build(:customer_data, PG_URI, customer_relations) do
# The context yielded to this block will be provided by the adapter
# instantiated for the given URI. It can therefore provide methods
# that are meaningful to the backend that is being connected to.
#
# However, some base functionality will be provided by axiom-schema
# for adapter authors to build on top of. For example, the #name method
# can probably be supported by every possible adapter, since it basically
# only allows to have a name in the schema, that is different from the
# one used in the backend relation. The same goes for the #rename method,
# since it basically only allows to have an attribute name in a schema
# relation, that is different from the one used in the backend relation.
#
# The #primary_key, #unique and #foreign_key methods will probably be
# provided by every DO adapter, but may or may not make sense for other
# adapters.
# Completely customize a relation via the block DSL
relation :people do
name :customers
rename name: :fullName
primary_key :id # *args
unique :email # *args
foreign_key :person_fk, update: :cascade, delete: :cascade # default :restrict
end
# Customize a relation using options
# Useful when only one or a few customizations are necessary
relation :people, name: :customers, unique: :email, primary_key: :id
# Set all relations to have :id as primary key
# Can be overwritten on a per relation basis
# Accepts *args
primary_key :id
# Set propagation rules for all FK constraints
# Can be overwritten on a per FK basis
# Defaults to :restrict for both :update and :delete
on update: :cascade, delete: :cascade
# Specify propagation rules for a specific FK constraint
foreign_key people.person_fk, update: :cascade, delete: :cascade
end
# No further customizations done here (mainly for brevity,
# but also to show that this is intended to work)
item_data = Axiom::Database.new(:item_data, MG_URI, item_relations)
schema = Axiom::Schema.coerce(customer_data, item_data)
# Optional
#
# Raise unless all base relations have been set up.
# Trying to call #[] on an unvalidated schema can be
# configured to raise too
schema.validate(schema_definition)
# Usage
schema[:people] # => a postgres backed axiom base relation called :customers
schema[:items] # => a mongo backed axiom base relation called :items
# ------------------------------------------------------
# spec_helper.rb
# ------------------------------------------------------
# All relations use the memory adapter, therefore
# no specific relation customizations are needed
schema = Axiom::Schema.build(schema_definition)
# Usage
schema[:people] # => a memory backed axiom base relation called :people
schema[:items] # => a memory backed axiom base relation called :items
# ------------------------------------------------------------
# DSL alternative (2) (optimized for single file schema setup)
# very likely to only be implemented after (1) or not at all
# ------------------------------------------------------------
schema = Axiom::Schema.build(schema_definition) do
database(:customer_data, PG_URI, CUSTOMER_RELATIONS) do
# all the methods shown in Alternative 1
end
database(:item_data, MG_URI, ITEM_RELATIONS) do
# all the methods shown in Alternative 1
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment