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.
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