diametric 0.1.1-java
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/Gemfile +28 -0
- data/Jarfile +20 -0
- data/LICENSE.txt +22 -0
- data/README.md +264 -0
- data/Rakefile +49 -0
- data/bin/datomic-rest +33 -0
- data/bin/download-datomic +13 -0
- data/datomic_version.yml +4 -0
- data/diametric-java.gemspec +39 -0
- data/ext/diametric/DiametricCollection.java +147 -0
- data/ext/diametric/DiametricConnection.java +113 -0
- data/ext/diametric/DiametricDatabase.java +107 -0
- data/ext/diametric/DiametricEntity.java +90 -0
- data/ext/diametric/DiametricListenableFuture.java +47 -0
- data/ext/diametric/DiametricObject.java +66 -0
- data/ext/diametric/DiametricPeer.java +414 -0
- data/ext/diametric/DiametricService.java +102 -0
- data/ext/diametric/DiametricUUID.java +61 -0
- data/ext/diametric/DiametricUtils.java +183 -0
- data/lib/boolean_type.rb +3 -0
- data/lib/diametric.rb +42 -0
- data/lib/diametric/config.rb +54 -0
- data/lib/diametric/config/environment.rb +42 -0
- data/lib/diametric/entity.rb +659 -0
- data/lib/diametric/errors.rb +13 -0
- data/lib/diametric/generators/active_model.rb +42 -0
- data/lib/diametric/persistence.rb +48 -0
- data/lib/diametric/persistence/common.rb +82 -0
- data/lib/diametric/persistence/peer.rb +154 -0
- data/lib/diametric/persistence/rest.rb +107 -0
- data/lib/diametric/query.rb +259 -0
- data/lib/diametric/railtie.rb +52 -0
- data/lib/diametric/rest_service.rb +74 -0
- data/lib/diametric/service_base.rb +77 -0
- data/lib/diametric/transactor.rb +86 -0
- data/lib/diametric/version.rb +3 -0
- data/lib/diametric_service.jar +0 -0
- data/lib/tasks/create_schema.rb +27 -0
- data/lib/tasks/diametric_config.rb +45 -0
- data/lib/value_enums.rb +8 -0
- data/spec/conf_helper.rb +55 -0
- data/spec/config/free-transactor-template.properties +73 -0
- data/spec/config/logback.xml +59 -0
- data/spec/data/seattle-data0.dtm +452 -0
- data/spec/data/seattle-data1.dtm +326 -0
- data/spec/developer_create_sample.rb +39 -0
- data/spec/developer_query_spec.rb +120 -0
- data/spec/diametric/config_spec.rb +60 -0
- data/spec/diametric/entity_spec.rb +476 -0
- data/spec/diametric/peer_api_spec.rb +147 -0
- data/spec/diametric/persistence/peer_many2many_spec.rb +76 -0
- data/spec/diametric/persistence/peer_spec.rb +27 -0
- data/spec/diametric/persistence/rest_spec.rb +30 -0
- data/spec/diametric/persistence_spec.rb +59 -0
- data/spec/diametric/query_spec.rb +118 -0
- data/spec/diametric/rest_service_spec.rb +56 -0
- data/spec/diametric/transactor_spec.rb +68 -0
- data/spec/integration_spec.rb +107 -0
- data/spec/parent_child_sample.rb +42 -0
- data/spec/peer_integration_spec.rb +121 -0
- data/spec/peer_seattle_spec.rb +200 -0
- data/spec/rc2013_seattle_big.rb +82 -0
- data/spec/rc2013_seattle_small.rb +60 -0
- data/spec/rc2013_simple_sample.rb +72 -0
- data/spec/seattle_integration_spec.rb +106 -0
- data/spec/simple_validation_sample.rb +31 -0
- data/spec/spec_helper.rb +63 -0
- data/spec/support/entities.rb +157 -0
- data/spec/support/gen_entity_class.rb +9 -0
- data/spec/support/persistence_examples.rb +104 -0
- data/spec/test_version_file.yml +4 -0
- metadata +290 -0
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'rails/generators/active_model'
|
2
|
+
|
3
|
+
module Diametric
|
4
|
+
module Generators
|
5
|
+
|
6
|
+
class ActiveModel < ::Rails::Generators::ActiveModel #:nodoc:
|
7
|
+
def self.all(klass)
|
8
|
+
"#{klass}.all"
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.find(klass, params=nil, connection=nil, resolve=false)
|
12
|
+
"#{klass}.get(#{params}, #{connection}, #{resolve})"
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.build(klass, params=nil)
|
16
|
+
if params
|
17
|
+
"#{klass}.new(#{params})"
|
18
|
+
else
|
19
|
+
"#{klass}.new"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def save
|
24
|
+
"#{name}.save"
|
25
|
+
end
|
26
|
+
|
27
|
+
def update_attributes(params=nil)
|
28
|
+
#"#{name}.update_attributes(#{params})"
|
29
|
+
"#{name}.update(#{params})"
|
30
|
+
end
|
31
|
+
|
32
|
+
def errors
|
33
|
+
"#{name}.errors"
|
34
|
+
end
|
35
|
+
|
36
|
+
def destroy
|
37
|
+
"#{name}.destroy"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module Diametric
|
2
|
+
# Persistence is the main entry point for adding persistence to your diametric entities.
|
3
|
+
module Persistence
|
4
|
+
class << self; attr_reader :conn_type; end
|
5
|
+
autoload :REST, 'diametric/persistence/rest'
|
6
|
+
|
7
|
+
# Establish a base connection for your application that is used unless specified otherwise. This method can
|
8
|
+
# establish connections in either REST or peer mode, depending on the supplied options.
|
9
|
+
#
|
10
|
+
# @example Connecting in peer-mode (JRuby required)
|
11
|
+
# Diametric::Persistence.establish_base_connection({:uri => "datomic:free://localhost:4334/my-db"})
|
12
|
+
#
|
13
|
+
# @example Connecting in REST-mode
|
14
|
+
# Diametric::Persistence.establish_base_connection({:uri => "http://localhost:9000/",
|
15
|
+
# :database => "my-db",
|
16
|
+
# :storage => "my-dbalias"})
|
17
|
+
def self.establish_base_connection(options)
|
18
|
+
@_persistence_class = persistence_class(options[:uri])
|
19
|
+
@_persistence_class.connect(options)
|
20
|
+
end
|
21
|
+
|
22
|
+
# Including +Diametric::Persistence+ after establishing a base connection will include
|
23
|
+
# the appropriate Persistence class ({REST} or {Peer})
|
24
|
+
def self.included(base)
|
25
|
+
base.send(:include, @_persistence_class) if @_persistence_class
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.peer?
|
29
|
+
@conn_type == :peer
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.rest?
|
33
|
+
@conn_type == :rest
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def self.persistence_class(uri)
|
39
|
+
if uri =~ /^datomic:/
|
40
|
+
@conn_type = :peer
|
41
|
+
Peer
|
42
|
+
else
|
43
|
+
@conn_type = :rest
|
44
|
+
REST
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
module Diametric
|
2
|
+
module Persistence
|
3
|
+
module Common
|
4
|
+
def self.included(base)
|
5
|
+
base.send(:extend, ClassMethods)
|
6
|
+
base.send(:include, InstanceMethods)
|
7
|
+
end
|
8
|
+
|
9
|
+
module InstanceMethods
|
10
|
+
def update_attributes(new_attributes)
|
11
|
+
assign_attributes(new_attributes)
|
12
|
+
save
|
13
|
+
end
|
14
|
+
|
15
|
+
def assign_attributes(new_attributes)
|
16
|
+
valid_keys = attribute_names + [:id]
|
17
|
+
new_attributes.each do |key, value|
|
18
|
+
if valid_keys.include? key.to_sym
|
19
|
+
self.send("#{key}=", value)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# Save the entity. If a validation error occurs an error will get raised.
|
25
|
+
#
|
26
|
+
# @example Save the entitiy.
|
27
|
+
# entity.save!
|
28
|
+
#
|
29
|
+
# @return [ true, false ] True if validation passed.
|
30
|
+
def save!
|
31
|
+
unless save
|
32
|
+
self.class.fail_validate!(self) unless errors.empty?
|
33
|
+
end
|
34
|
+
return true
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
module ClassMethods
|
39
|
+
def create_schema(connection=nil)
|
40
|
+
if self.instance_variable_get("@peer")
|
41
|
+
connection ||= Diametric::Persistence::Peer.connect
|
42
|
+
connection.transact(schema)
|
43
|
+
else
|
44
|
+
transact(schema)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def all(connection=nil, resolve=false)
|
49
|
+
if self.instance_variable_get("@peer")
|
50
|
+
connection ||= Diametric::Persistence::Peer.connect
|
51
|
+
end
|
52
|
+
Diametric::Query.new(self, connection, resolve).all
|
53
|
+
end
|
54
|
+
|
55
|
+
def first(conditions = {}, connection=nil, resolve=false)
|
56
|
+
if self.instance_variable_get("@peer")
|
57
|
+
connection ||= Diametric::Persistence::Peer.connect
|
58
|
+
end
|
59
|
+
where(conditions, connection, resolve).first
|
60
|
+
end
|
61
|
+
|
62
|
+
def where(conditions = {}, connection=nil, resolve=false)
|
63
|
+
if self.instance_variable_get("@peer")
|
64
|
+
connection ||= Diametric::Persistence::Peer.connect
|
65
|
+
end
|
66
|
+
query = Diametric::Query.new(self, connection, resolve)
|
67
|
+
query.where(conditions)
|
68
|
+
end
|
69
|
+
|
70
|
+
def filter(*filter)
|
71
|
+
if self.instance_variable_get("@peer")
|
72
|
+
connection = Diametric::Persistence::Peer.connect
|
73
|
+
else
|
74
|
+
connection = nil
|
75
|
+
end
|
76
|
+
query = Diametric::Query.new(self, connection, true)
|
77
|
+
query.filter(*filter)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,154 @@
|
|
1
|
+
require 'diametric/persistence/common'
|
2
|
+
|
3
|
+
module Diametric
|
4
|
+
module Persistence
|
5
|
+
module Peer
|
6
|
+
|
7
|
+
def save(connection=nil)
|
8
|
+
return false unless valid?
|
9
|
+
return true unless changed?
|
10
|
+
connection ||= Diametric::Persistence::Peer.connect
|
11
|
+
|
12
|
+
parsed_data = []
|
13
|
+
parse_tx_data(tx_data, parsed_data)
|
14
|
+
|
15
|
+
map = connection.transact(parsed_data).get
|
16
|
+
|
17
|
+
resolve_changes([self], map)
|
18
|
+
|
19
|
+
map
|
20
|
+
end
|
21
|
+
|
22
|
+
def resolve_tempid(map, id)
|
23
|
+
if id.to_s =~ /-\d+/
|
24
|
+
return Diametric::Persistence::Peer.resolve_tempid(map, id)
|
25
|
+
end
|
26
|
+
return id
|
27
|
+
end
|
28
|
+
|
29
|
+
def parse_tx_data(data, result)
|
30
|
+
queue = []
|
31
|
+
data.each do |c_data|
|
32
|
+
if c_data.is_a? Hash
|
33
|
+
parse_hash_data(c_data, result, queue)
|
34
|
+
elsif c_data.is_a? Array
|
35
|
+
parse_array_data(c_data, result)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
parse_tx_data(queue, result) unless queue.empty?
|
39
|
+
end
|
40
|
+
|
41
|
+
def parse_hash_data(c_hash, result, queue)
|
42
|
+
hash = {}
|
43
|
+
c_hash.each do |c_key, c_value|
|
44
|
+
if c_value.respond_to?(:tx_data)
|
45
|
+
if c_value.tx_data.empty?
|
46
|
+
hash[c_key] = c_value.dbid
|
47
|
+
else
|
48
|
+
c_value.dbid = c_value.tempid
|
49
|
+
hash[c_key] = c_value.dbid
|
50
|
+
queue << c_value.tx_data.first
|
51
|
+
end
|
52
|
+
elsif c_value.is_a? Set
|
53
|
+
set_value = Set.new
|
54
|
+
c_value.each do |s|
|
55
|
+
if s.respond_to?(:tx_data) && s.tx_data.empty?
|
56
|
+
set_value << s.dbid
|
57
|
+
elsif s.respond_to?(:tx_data)
|
58
|
+
set_value << s.tx_data[":db/id"]
|
59
|
+
parsed_tx_data(s, result)
|
60
|
+
else
|
61
|
+
set_value << s
|
62
|
+
end
|
63
|
+
end
|
64
|
+
hash[c_key] = set_value
|
65
|
+
elsif c_value.respond_to?(:eid)
|
66
|
+
hash[c_key] = c_value.eid
|
67
|
+
else
|
68
|
+
hash[c_key] = c_value
|
69
|
+
end
|
70
|
+
end
|
71
|
+
result << hash
|
72
|
+
end
|
73
|
+
|
74
|
+
def parse_array_data(c_array, result)
|
75
|
+
array = []
|
76
|
+
c_array.each do |c_value|
|
77
|
+
if c_value.respond_to?(:to_a)
|
78
|
+
a_values = []
|
79
|
+
c_value.to_a.each do |a_value|
|
80
|
+
if a_value.respond_to?(:tx_data) && a_value.tx_data.empty?
|
81
|
+
a_values << a_value.dbid
|
82
|
+
else
|
83
|
+
a_values << a_value
|
84
|
+
end
|
85
|
+
end
|
86
|
+
array << a_values
|
87
|
+
else
|
88
|
+
array << c_value
|
89
|
+
end
|
90
|
+
end
|
91
|
+
result << array
|
92
|
+
end
|
93
|
+
|
94
|
+
def resolve_changes(parents, map)
|
95
|
+
queue = []
|
96
|
+
parents.each do |child|
|
97
|
+
child.attributes.each do |a_key, a_val|
|
98
|
+
if a_val.respond_to?(:tx_data)
|
99
|
+
queue << a_val
|
100
|
+
end
|
101
|
+
end
|
102
|
+
child.instance_variable_set("@previously_changed", child.changes)
|
103
|
+
child.changed_attributes.clear
|
104
|
+
child.dbid = resolve_tempid(map, child.dbid)
|
105
|
+
child.instance_variable_set("@tx_map", map)
|
106
|
+
end
|
107
|
+
resolve_changes(queue, map) unless queue.empty?
|
108
|
+
end
|
109
|
+
|
110
|
+
def retract_entity(dbid)
|
111
|
+
Diametric::Persistence::Peer.retract_entity(dbid)
|
112
|
+
end
|
113
|
+
|
114
|
+
def method_missing(method_name, *args, &block)
|
115
|
+
result = /(.+)_from_this_(.+)/.match(method_name)
|
116
|
+
if result
|
117
|
+
query_string = ":#{result[1]}/_#{result[2]}"
|
118
|
+
entities = Diametric::Persistence::Peer.reverse_q(args[0].db, self.dbid, query_string)
|
119
|
+
entities.collect {|e| self.class.from_dbid_or_entity(e, args[0])}
|
120
|
+
else
|
121
|
+
super
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
module ClassMethods
|
126
|
+
def get(dbid, connection=nil, resolve=false)
|
127
|
+
entity = self.new
|
128
|
+
dbid = dbid.to_i if dbid.is_a?(String)
|
129
|
+
connection ||= Diametric::Persistence::Peer.connect
|
130
|
+
entity = self.from_dbid_or_entity(dbid, connection, resolve)
|
131
|
+
entity
|
132
|
+
end
|
133
|
+
|
134
|
+
def q(query, args, conn_or_db=nil)
|
135
|
+
conn_or_db ||= Diametric::Persistence::Peer.connect
|
136
|
+
if conn_or_db.is_a?(Diametric::Persistence::Connection)
|
137
|
+
db = conn_or_db.db
|
138
|
+
else
|
139
|
+
db = conn_or_db
|
140
|
+
end
|
141
|
+
|
142
|
+
results = Diametric::Persistence::Peer.q(query, db, args)
|
143
|
+
# Diametric query expects the first element of each array in
|
144
|
+
# results is dbid. Wraps dbid here by
|
145
|
+
# Diametric::Persistence::Object to make it consistent
|
146
|
+
results.each do |r|
|
147
|
+
r[0] = Diametric::Persistence::Object.new(r[0])
|
148
|
+
end
|
149
|
+
results
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
require 'diametric'
|
2
|
+
require 'diametric/persistence/common'
|
3
|
+
require 'datomic/client'
|
4
|
+
|
5
|
+
# TODO: nice errors when unable to connect
|
6
|
+
module Diametric
|
7
|
+
module Persistence
|
8
|
+
module REST
|
9
|
+
@connection = nil
|
10
|
+
@persisted_classes = Set.new
|
11
|
+
|
12
|
+
def self.included(base)
|
13
|
+
base.send(:include, Diametric::Persistence::Common)
|
14
|
+
base.send(:extend, ClassMethods)
|
15
|
+
@persisted_classes.add(base)
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.connection
|
19
|
+
@connection
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.create_schemas
|
23
|
+
@persisted_classes.each do |klass|
|
24
|
+
klass.create_schema
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
module ClassMethods
|
29
|
+
def connect(options = {})
|
30
|
+
@uri = options[:uri]
|
31
|
+
@dbalias = options[:storage]
|
32
|
+
@database = options[:database]
|
33
|
+
|
34
|
+
@connection = Datomic::Client.new(@uri, @dbalias)
|
35
|
+
@connection.create_database(@database)
|
36
|
+
end
|
37
|
+
|
38
|
+
def connection
|
39
|
+
@connection || Diametric::Persistence::REST.connection
|
40
|
+
end
|
41
|
+
|
42
|
+
def database
|
43
|
+
@database || Diametric::Persistence::REST.database
|
44
|
+
end
|
45
|
+
|
46
|
+
def transact(data)
|
47
|
+
connection.transact(database, data)
|
48
|
+
end
|
49
|
+
|
50
|
+
def get(dbid, conn=nil, resolve=false)
|
51
|
+
conn ||= connection
|
52
|
+
res = conn.entity(database, dbid.to_i)
|
53
|
+
|
54
|
+
# TODO tighten regex to only allow fields with the model name
|
55
|
+
attrs = res.data.map { |attr_symbol, value|
|
56
|
+
attr = attr_symbol.to_s.gsub(%r"^\w+/", '')
|
57
|
+
[attr, value]
|
58
|
+
}
|
59
|
+
|
60
|
+
entity = self.new(Hash[*attrs.flatten])
|
61
|
+
entity.dbid = dbid
|
62
|
+
entity
|
63
|
+
end
|
64
|
+
|
65
|
+
def q(query, args, unused=nil)
|
66
|
+
args.unshift(connection.db_alias(database))
|
67
|
+
res = connection.query(query, args)
|
68
|
+
res.data
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
extend ClassMethods
|
73
|
+
|
74
|
+
# Save the entity
|
75
|
+
#
|
76
|
+
# @example Save the entity.
|
77
|
+
# entity.save
|
78
|
+
#
|
79
|
+
# @return [ true, false ] True is success, false if not.
|
80
|
+
def save
|
81
|
+
return false unless valid?
|
82
|
+
return true unless changed?
|
83
|
+
|
84
|
+
self.dbid = self.dbid.to_i if self.dbid.class == String
|
85
|
+
|
86
|
+
res = self.class.transact(tx_data)
|
87
|
+
if dbid.nil?
|
88
|
+
self.dbid = res.data[:tempids].values.first
|
89
|
+
end
|
90
|
+
|
91
|
+
@previously_changed = changes
|
92
|
+
@changed_attributes.clear
|
93
|
+
|
94
|
+
res
|
95
|
+
end
|
96
|
+
|
97
|
+
def to_edn
|
98
|
+
self.dbid
|
99
|
+
end
|
100
|
+
|
101
|
+
def retract_entity(dbid)
|
102
|
+
query = [[:"db.fn/retractEntity", dbid.to_i]]
|
103
|
+
self.class.transact(query)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|