Last active
December 30, 2015 08:08
-
-
Save snusnu/7800261 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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