Skip to content

Commit

Permalink
Turns out transaction function for REST doesn't work
Browse files Browse the repository at this point in the history
  • Loading branch information
yokolet committed Apr 24, 2014
1 parent 5d87ef2 commit f44a482
Show file tree
Hide file tree
Showing 8 changed files with 141 additions and 81 deletions.
2 changes: 2 additions & 0 deletions lib/diametric.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
require "diametric/query"
require "diametric/persistence"
require "diametric/persistence/function"
require "diametric/persistence/rest_function"
require "diametric/persistence/peer_function"
require "diametric/errors"

require 'diametric/config'
Expand Down
9 changes: 9 additions & 0 deletions lib/diametric/persistence/common.rb
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,15 @@ def save!
end
return true
end

def transaction_functions
functions = self.instance_variable_get("@transaction_functions")
unless functions
functions = ::Set.new
self.instance_variable_set("@transaction_functions", functions)
end
functions
end
end
end
end
Expand Down
71 changes: 15 additions & 56 deletions lib/diametric/persistence/function.rb
Original file line number Diff line number Diff line change
@@ -1,71 +1,30 @@
module Diametric
module Persistence
class Function
# Defines a database function from given hash.
# The hash should have keys of :lang, :paramsm and :code.
# The hash can have optional keys of :requires and :imports.
#
# @example Defines a database function.
# Function.define_function({
# lang: :clojure,
# params: [:name],
# code: %{(str "Hello, " name)}})
#
# @return Diametric::Persistence::Function Function placeholder.
def self.define(function_map)
return Diametric::Persistence::Peer.function(function_map)
end

# Defines and saves a database function from given hash.
# The hash should have keys of :name, :lang, :paramsm and :code.
# Defines and saves a transaction or database function from given hash.
# The hash should have keys of :name, :lang, :params and :code.
# The hash can have optional keys of :doc, :requires and :imports.
# The second argument is a connection to datomic. (optional)
#
# @example Defines and saves a database function in datomic.
# Function.create({
# name: :hello,
# name: :inc_fn
# lang: :clojure,
# params: [:name],
# code: %{(str "Hello, " name)}}, connection)
# params: [:db, :id, :attr, :amount],
# code: %{(let [e (datomic.api/entity db id) orig (attr e 0)]
# [[:db/add id attr (+ orig amount) ]])},
# connection)
#
# @return result of the transaction
# @return result of the updated entity.
def self.create(function_map, conn=nil)
conn ||= Diametric::Persistence::Peer.connection
map = function_map.dup
name = map.delete(:name)
doc = map.delete(:doc)
function = Diametric::Persistence::Peer.function(map)
schema = {:"db/id" => Diametric::Persistence::Peer.tempid(:"db.part/user"),
:"db/ident" => name.to_sym,
:"db/fn" => function}
if doc
schema.merge!({:"db/doc" => doc})
if Diametric::Persistence::REST.connection
self.extend(Diametric::Persistence::RestFunction)
elsif Diametric::Persistence::Peer.connect
self.extend(Diametric::Persistence::PeerFunction)
else
raise RuntimeError 'Connection is not established'
end
conn.transact([schema]).get
function.name = name
function
end

def name=(name)
self.instance_variable_set("@name", name)
end

def name
self.instance_variable_get("@name")
end

# Save the function.
#
# @example Save the function.
# function.save
#
# @return Diametric::Persistence::Listenable
def save(name, doc=nil, conn=nil)
conn ||= Diametric::Persistence::Peer.connect
schema = [{:"db/id" => tempid(:"db.part/user"),
:"db/ident" => name.to_sym,
:"db/fn" => hello}]
self.save(conn)
self.create_function(function_map, conn)
end
end
end
Expand Down
9 changes: 0 additions & 9 deletions lib/diametric/persistence/peer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -117,15 +117,6 @@ def retract_entity(dbid)
Diametric::Persistence::Peer.retract_entity(dbid)
end

def transaction_functions
functions = self.instance_variable_get("@transaction_functions")
unless functions
functions = ::Set.new
self.instance_variable_set("@transaction_functions", functions)
end
functions
end

def method_missing(method_name, *args, &block)
functions = self.instance_variable_get("@transaction_functions")
if functions && functions.include?(method_name)
Expand Down
20 changes: 20 additions & 0 deletions lib/diametric/persistence/peer_function.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
module Diametric
module Persistence
module PeerFunction
def create_function(function_map, conn=nil)
conn ||= Diametric::Persistence::Peer.connection
map = function_map.dup
name = map.delete(:name)
doc = map.delete(:doc)
function = Diametric::Persistence::Peer.function(map)
schema = {:"db/id" => Diametric::Persistence::Peer.tempid(:"db.part/user"),
:"db/ident" => name.to_sym,
:"db/fn" => function}
if doc
schema.merge!({:"db/doc" => doc})
end
conn.transact([schema]).get
end
end
end
end
23 changes: 23 additions & 0 deletions lib/diametric/persistence/rest.rb
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,29 @@ def retract_entity(dbid)
query = [[:"db.fn/retractEntity", dbid.to_i]]
self.class.transact(query)
end

def method_missing(method_name, *args, &block)
functions = self.instance_variable_get("@transaction_functions")
if functions && functions.include?(method_name)
return invoke_function(method_name, args)
end
end

def invoke_function(method_name, args)
params = args.dup
conn = params.shift
conn ||= Diametric::Persistence::REST.connection
attribute_names = self.class.attribute_names
params = params.map do |e|
if attribute_names.include?(e)
e = (self.class.prefix + "/" + e.to_s).to_sym
else
e
end
end
conn.transact(Diametric::Persistence::REST.database, [[method_name, self.dbid, *params]])
self.class.reify(self.dbid, conn)
end
end
end
end
19 changes: 19 additions & 0 deletions lib/diametric/persistence/rest_function.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
module Diametric
module Persistence
module RestFunction
def create_function(function_map, unused)
conn = Diametric::Persistence::REST.connection
map = function_map.dup
name = map.delete(:name)
doc = map.delete(:doc)
schema = {:"db/id" => Diametric::Persistence::REST.tempid(:"db.part/user"),
:"db/ident" => name.to_sym}
schema.merge!({:"db/fn" => EDN.tagged_element('db/fn', map)})
if doc
schema.merge!({:"db/doc" => doc})
end
result = conn.transact(Diametric::Persistence::REST.database, [schema]) # fails
end
end
end
end
69 changes: 53 additions & 16 deletions spec/diametric/function_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@
end

it "saves in database" do
function = Diametric::Persistence::Function.create(hello_with_info, @conn)
function.name.should == :hello
result = Diametric::Persistence::Function.create(hello_with_info, @conn)
result.should_not be_nil
end
end

Expand Down Expand Up @@ -87,23 +87,60 @@
}
}

before do
datomic_uri = "datomic:mem://function-#{SecureRandom.uuid}"
@conn = Diametric::Persistence::Peer.connect(datomic_uri)
function = Diametric::Persistence::Function.create(inc_fn, @conn)
Rat.create_schema(@conn)
end
describe "Peer" do
before do
datomic_uri = "datomic:mem://function-#{SecureRandom.uuid}"
@conn = Diametric::Persistence::Peer.connect(datomic_uri)
Diametric::Persistence::Function.create(inc_fn, @conn)
Rat.create_schema(@conn)
end

after do
@conn.release
after do
@conn.release
end

it "can be added to an entity and run" do
jay = Rat.new({name: "Jay", age: 10})
jay.save
jay.transaction_functions << :inc_fn
jay = jay.inc_fn(@conn, :age, 3)
jay.age.should == 13
end
end

it "can be added to an entity and run" do
jay = Rat.new({name: "Jay", age: 10})
jay.save
jay.transaction_functions << :inc_fn
jay = jay.inc_fn(@conn, :age, 3)
jay.age.should == 13
describe "REST" do
before do
@db_uri = ENV['DATOMIC_URI'] || 'http://localhost:46291'
@storage = ENV['DATOMIC_STORAGE'] || 'free'
@dbname = ENV['DATOMIC_NAME'] || "function-#{SecureRandom.uuid}"
@connection_options = {
:uri => @db_uri,
:storage => @storage,
:database => @dbname
}
Diametric::Persistence::REST.connect(@connection_options)
Diametric::Persistence::REST.create_schemas
end

it "can create and save transaction funcrion" do
result = Diametric::Persistence::Function.create(inc_fn)
result.should_not be_nil
end

context "with saved transaction function" do
before do
Diametric::Persistence::Function.create(inc_fn)
end

it "can be added to an entity and run" do
juliet = Mouse.new({name: "Juliet", age: 13})
juliet.save
juliet.transaction_functions << :inc_fn
juliet = juliet.inc_fn(nil, :age, 4)
pending("REST fails to transact function")
juliet.age.should == 17
end
end
end
end
end

0 comments on commit f44a482

Please sign in to comment.