diametric 0.1.1-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (73) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +28 -0
  3. data/Jarfile +20 -0
  4. data/LICENSE.txt +22 -0
  5. data/README.md +264 -0
  6. data/Rakefile +49 -0
  7. data/bin/datomic-rest +33 -0
  8. data/bin/download-datomic +13 -0
  9. data/datomic_version.yml +4 -0
  10. data/diametric-java.gemspec +39 -0
  11. data/ext/diametric/DiametricCollection.java +147 -0
  12. data/ext/diametric/DiametricConnection.java +113 -0
  13. data/ext/diametric/DiametricDatabase.java +107 -0
  14. data/ext/diametric/DiametricEntity.java +90 -0
  15. data/ext/diametric/DiametricListenableFuture.java +47 -0
  16. data/ext/diametric/DiametricObject.java +66 -0
  17. data/ext/diametric/DiametricPeer.java +414 -0
  18. data/ext/diametric/DiametricService.java +102 -0
  19. data/ext/diametric/DiametricUUID.java +61 -0
  20. data/ext/diametric/DiametricUtils.java +183 -0
  21. data/lib/boolean_type.rb +3 -0
  22. data/lib/diametric.rb +42 -0
  23. data/lib/diametric/config.rb +54 -0
  24. data/lib/diametric/config/environment.rb +42 -0
  25. data/lib/diametric/entity.rb +659 -0
  26. data/lib/diametric/errors.rb +13 -0
  27. data/lib/diametric/generators/active_model.rb +42 -0
  28. data/lib/diametric/persistence.rb +48 -0
  29. data/lib/diametric/persistence/common.rb +82 -0
  30. data/lib/diametric/persistence/peer.rb +154 -0
  31. data/lib/diametric/persistence/rest.rb +107 -0
  32. data/lib/diametric/query.rb +259 -0
  33. data/lib/diametric/railtie.rb +52 -0
  34. data/lib/diametric/rest_service.rb +74 -0
  35. data/lib/diametric/service_base.rb +77 -0
  36. data/lib/diametric/transactor.rb +86 -0
  37. data/lib/diametric/version.rb +3 -0
  38. data/lib/diametric_service.jar +0 -0
  39. data/lib/tasks/create_schema.rb +27 -0
  40. data/lib/tasks/diametric_config.rb +45 -0
  41. data/lib/value_enums.rb +8 -0
  42. data/spec/conf_helper.rb +55 -0
  43. data/spec/config/free-transactor-template.properties +73 -0
  44. data/spec/config/logback.xml +59 -0
  45. data/spec/data/seattle-data0.dtm +452 -0
  46. data/spec/data/seattle-data1.dtm +326 -0
  47. data/spec/developer_create_sample.rb +39 -0
  48. data/spec/developer_query_spec.rb +120 -0
  49. data/spec/diametric/config_spec.rb +60 -0
  50. data/spec/diametric/entity_spec.rb +476 -0
  51. data/spec/diametric/peer_api_spec.rb +147 -0
  52. data/spec/diametric/persistence/peer_many2many_spec.rb +76 -0
  53. data/spec/diametric/persistence/peer_spec.rb +27 -0
  54. data/spec/diametric/persistence/rest_spec.rb +30 -0
  55. data/spec/diametric/persistence_spec.rb +59 -0
  56. data/spec/diametric/query_spec.rb +118 -0
  57. data/spec/diametric/rest_service_spec.rb +56 -0
  58. data/spec/diametric/transactor_spec.rb +68 -0
  59. data/spec/integration_spec.rb +107 -0
  60. data/spec/parent_child_sample.rb +42 -0
  61. data/spec/peer_integration_spec.rb +121 -0
  62. data/spec/peer_seattle_spec.rb +200 -0
  63. data/spec/rc2013_seattle_big.rb +82 -0
  64. data/spec/rc2013_seattle_small.rb +60 -0
  65. data/spec/rc2013_simple_sample.rb +72 -0
  66. data/spec/seattle_integration_spec.rb +106 -0
  67. data/spec/simple_validation_sample.rb +31 -0
  68. data/spec/spec_helper.rb +63 -0
  69. data/spec/support/entities.rb +157 -0
  70. data/spec/support/gen_entity_class.rb +9 -0
  71. data/spec/support/persistence_examples.rb +104 -0
  72. data/spec/test_version_file.yml +4 -0
  73. metadata +290 -0
@@ -0,0 +1,13 @@
1
+ require 'diametric'
2
+
3
+ module Diametric
4
+ module Errors
5
+
6
+ class ValidationError < StandardError
7
+ def initialize(entity)
8
+ super(entity.errors.full_messages.join(", "))
9
+ end
10
+ end
11
+
12
+ end
13
+ end
@@ -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