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,47 @@
1
+ package diametric;
2
+
3
+ import org.jruby.Ruby;
4
+ import org.jruby.RubyClass;
5
+ import org.jruby.RubyObject;
6
+ import org.jruby.anno.JRubyClass;
7
+ import org.jruby.anno.JRubyMethod;
8
+ import org.jruby.javasupport.JavaUtil;
9
+ import org.jruby.runtime.ThreadContext;
10
+ import org.jruby.runtime.builtin.IRubyObject;
11
+
12
+ import datomic.ListenableFuture;
13
+
14
+ @JRubyClass(name = "Diametric::Persistence::ListenableFuture")
15
+ public class DiametricListenableFuture extends RubyObject {
16
+ private static final long serialVersionUID = 2083281771243513904L;
17
+ // future is supposed to datomic.ListenableFuture type;
18
+ private Object future = null;
19
+
20
+ public DiametricListenableFuture(Ruby runtime, RubyClass klazz) {
21
+ super(runtime, klazz);
22
+ }
23
+
24
+ void init(Object future) {
25
+ this.future = future;
26
+ }
27
+
28
+ @JRubyMethod
29
+ public IRubyObject to_java(ThreadContext context) {
30
+ return JavaUtil.convertJavaToUsableRubyObject(context.getRuntime(), future);
31
+ }
32
+
33
+ @JRubyMethod
34
+ public IRubyObject get(ThreadContext context) {
35
+ Ruby runtime = context.getRuntime();
36
+ if (future == null) return runtime.getNil();
37
+ try {
38
+ Object result = ((ListenableFuture)future).get();
39
+ RubyClass clazz = (RubyClass)runtime.getClassFromPath("Diametric::Persistence::Object");
40
+ DiametricObject diametric_object = (DiametricObject)clazz.allocate();
41
+ diametric_object.update(result);
42
+ return diametric_object;
43
+ } catch (Throwable t) {
44
+ throw runtime.newRuntimeError(t.getMessage());
45
+ }
46
+ }
47
+ }
@@ -0,0 +1,66 @@
1
+ package diametric;
2
+
3
+ import org.jruby.Ruby;
4
+ import org.jruby.RubyClass;
5
+ import org.jruby.RubyObject;
6
+ import org.jruby.anno.JRubyClass;
7
+ import org.jruby.anno.JRubyMethod;
8
+ import org.jruby.javasupport.JavaUtil;
9
+ import org.jruby.runtime.ThreadContext;
10
+ import org.jruby.runtime.builtin.IRubyObject;
11
+
12
+ @JRubyClass(name = "Diametric::Persistence::Object")
13
+ public class DiametricObject extends RubyObject {
14
+ private static final long serialVersionUID = -4198258841171995687L;
15
+ private Object java_object = null;
16
+
17
+ public DiametricObject(Ruby runtime, RubyClass klazz) {
18
+ super(runtime, klazz);
19
+ }
20
+
21
+ void update(Object java_object) {
22
+ this.java_object = java_object;
23
+ }
24
+
25
+ @Override
26
+ public Object clone() throws CloneNotSupportedException {
27
+ return super.clone();
28
+ }
29
+
30
+ Object toJava() {
31
+ return java_object;
32
+ }
33
+
34
+ @JRubyMethod(name="new", meta=true)
35
+ public static IRubyObject rbNew(ThreadContext context, IRubyObject klazz, IRubyObject arg) {
36
+ RubyClass clazz = (RubyClass)context.getRuntime().getClassFromPath("Diametric::Persistence::Object");
37
+ DiametricObject diametric_object = (DiametricObject)clazz.allocate();
38
+ diametric_object.update(DiametricUtils.convertRubyToJava(context, arg));
39
+ return diametric_object;
40
+ }
41
+
42
+ @JRubyMethod
43
+ public IRubyObject to_java(ThreadContext context) {
44
+ return JavaUtil.convertJavaToUsableRubyObject(context.getRuntime(), java_object);
45
+ }
46
+
47
+ @JRubyMethod(name="==", required=1)
48
+ public IRubyObject op_equal(ThreadContext context, IRubyObject arg) {
49
+ Ruby runtime = context.getRuntime();
50
+ if (arg instanceof DiametricObject) {
51
+ DiametricObject other = (DiametricObject)arg;
52
+ if (java_object.toString().equals(other.toJava().toString())) {
53
+ return runtime.getTrue();
54
+ } else {
55
+ return runtime.getFalse();
56
+ }
57
+ } else {
58
+ return runtime.getFalse();
59
+ }
60
+ }
61
+
62
+ @JRubyMethod
63
+ public IRubyObject to_s(ThreadContext context) {
64
+ return context.getRuntime().newString(java_object.toString());
65
+ }
66
+ }
@@ -0,0 +1,414 @@
1
+ package diametric;
2
+
3
+ import java.util.ArrayList;
4
+ import java.util.Collection;
5
+ import java.util.Iterator;
6
+ import java.util.List;
7
+ import java.util.Map;
8
+ import java.util.UUID;
9
+
10
+ import org.jruby.Ruby;
11
+ import org.jruby.RubyArray;
12
+ import org.jruby.RubyBoolean;
13
+ import org.jruby.RubyClass;
14
+ import org.jruby.RubyFixnum;
15
+ import org.jruby.RubyHash;
16
+ import org.jruby.RubyModule;
17
+ import org.jruby.RubyString;
18
+ import org.jruby.RubySymbol;
19
+ import org.jruby.anno.JRubyMethod;
20
+ import org.jruby.anno.JRubyModule;
21
+ import org.jruby.runtime.Block;
22
+ import org.jruby.runtime.ThreadContext;
23
+ import org.jruby.runtime.builtin.IRubyObject;
24
+
25
+ import clojure.lang.PersistentHashSet;
26
+ import datomic.Connection;
27
+ import datomic.Peer;
28
+
29
+ @JRubyModule(name="Diametric::Persistence::Peer")
30
+ public class DiametricPeer extends RubyModule {
31
+ private static final long serialVersionUID = 8659857729004427581L;
32
+
33
+ protected DiametricPeer(Ruby runtime) {
34
+ super(runtime);
35
+ }
36
+
37
+ private static DiametricConnection saved_connection = null;
38
+
39
+ @JRubyMethod(meta=true)
40
+ public static IRubyObject connect(ThreadContext context, IRubyObject klazz, IRubyObject arg) {
41
+ String uriOrMap = null;
42
+ if (arg instanceof RubyString) {
43
+ uriOrMap = DiametricUtils.rubyStringToJava(arg);
44
+ } else if (arg instanceof RubyHash) {
45
+ RubySymbol key = RubySymbol.newSymbol(context.getRuntime(), "uri");
46
+ RubyString value = (RubyString)((RubyHash)arg).op_aref(context, key);
47
+ uriOrMap = DiametricUtils.rubyStringToJava(value);
48
+ } else {
49
+ throw context.getRuntime().newArgumentError("Argument should be a String or Hash");
50
+ }
51
+ if (uriOrMap == null )
52
+ throw context.getRuntime().newArgumentError("Argument should be a String or Hash with :uri key");
53
+
54
+ RubyClass clazz = (RubyClass) context.getRuntime().getClassFromPath("Diametric::Persistence::Connection");
55
+ DiametricConnection rubyConnection = (DiametricConnection)clazz.allocate();
56
+ try {
57
+ // what value will be returned when connect fails? API doc doesn't tell anything.
58
+ Connection connection = (Connection) clojure.lang.RT.var("datomic.api", "connect").invoke(uriOrMap);
59
+ rubyConnection.init(connection);
60
+ saved_connection = rubyConnection;
61
+ return rubyConnection;
62
+ } catch (Exception e) {
63
+ // Diametric doesn't require creating database before connect.
64
+ if (e.getMessage().contains(":peer/db-not-found") && (Boolean)clojure.lang.RT.var("datomic.api", "create-database").invoke(uriOrMap)) {
65
+ Connection connection = (Connection) clojure.lang.RT.var("datomic.api", "connect").invoke(uriOrMap);
66
+ rubyConnection.init(connection);
67
+ saved_connection = rubyConnection;
68
+ return rubyConnection;
69
+ }
70
+ }
71
+ throw context.getRuntime().newRuntimeError("Failed to create connection");
72
+ }
73
+
74
+ @JRubyMethod(meta=true)
75
+ public static IRubyObject create_database(ThreadContext context, IRubyObject klazz, IRubyObject arg) {
76
+ String uriOrMap = DiametricUtils.rubyStringToJava(arg);
77
+ if (uriOrMap == null)
78
+ throw context.getRuntime().newArgumentError("Argument should be a String");
79
+ try {
80
+ boolean status = (Boolean)clojure.lang.RT.var("datomic.api", "create-database").invoke(uriOrMap);
81
+ return RubyBoolean.newBoolean(context.getRuntime(), status);
82
+ } catch (Exception e) {
83
+ throw context.getRuntime().newRuntimeError("Datomic Error: " + e.getMessage());
84
+ }
85
+ }
86
+
87
+ @JRubyMethod(meta=true, required=2, rest=true)
88
+ public static IRubyObject rename_database(ThreadContext context, IRubyObject klazz, IRubyObject[] args) {
89
+ if (args.length != 2) return context.getRuntime().getNil();
90
+ String uriOrMap = DiametricUtils.rubyStringToJava(args[0]);
91
+ if (uriOrMap == null) return context.getRuntime().getNil();
92
+ String newName = DiametricUtils.rubyStringToJava(args[1]);
93
+ if (newName == null) return context.getRuntime().getNil();
94
+ try {
95
+ boolean status = (Boolean)clojure.lang.RT.var("datomic.api", "rename-database").invoke(uriOrMap, newName);
96
+ return RubyBoolean.newBoolean(context.getRuntime(), status);
97
+ } catch (Exception e) {
98
+ throw context.getRuntime().newRuntimeError("Datomic Error: " + e.getMessage());
99
+ }
100
+ }
101
+
102
+ @JRubyMethod(meta=true)
103
+ public static IRubyObject delete_database(ThreadContext context, IRubyObject klazz, IRubyObject arg) {
104
+ String uriOrMap = DiametricUtils.rubyStringToJava(arg);
105
+ if (uriOrMap == null) return context.getRuntime().getNil();
106
+ try {
107
+ boolean status = (Boolean)clojure.lang.RT.var("datomic.api", "delete-database").invoke(uriOrMap);
108
+ return RubyBoolean.newBoolean(context.getRuntime(), status);
109
+ } catch (Exception e) {
110
+ throw context.getRuntime().newRuntimeError("Datomic Error: " + e.getMessage());
111
+ }
112
+ }
113
+
114
+ @JRubyMethod(meta=true)
115
+ public static IRubyObject shutdown(ThreadContext context, IRubyObject klazz, IRubyObject arg) {
116
+ if (!(arg instanceof RubyBoolean)) {
117
+ throw context.getRuntime().newArgumentError("Wrong argument type.");
118
+ }
119
+ Boolean shutdownClojure = (Boolean) arg.toJava(Boolean.class);
120
+ try {
121
+ clojure.lang.RT.var("datomic.api", "shutdown").invoke(shutdownClojure);
122
+ } catch (Exception e) {
123
+ throw context.getRuntime().newRuntimeError("Datomic Error: " + e.getMessage());
124
+ }
125
+ return context.getRuntime().getNil();
126
+ }
127
+
128
+ /**
129
+ * Constructs a semi-sequential UUID useful for creating UUIDs that don't fragment indexes
130
+ *
131
+ * @param context
132
+ * @param klazz
133
+ * @return java.util.UUID. a UUID whose most significant 32 bits are currentTimeMillis rounded to seconds
134
+ */
135
+ @JRubyMethod(meta=true)
136
+ public static IRubyObject squuid(ThreadContext context, IRubyObject klazz) {
137
+ RubyClass clazz = (RubyClass) context.getRuntime().getClassFromPath("Diametric::Persistence::UUID");
138
+ diametric.DiametricUUID ruby_uuid = (diametric.DiametricUUID)clazz.allocate();
139
+ try {
140
+ java.util.UUID java_uuid = (UUID) clojure.lang.RT.var("datomic.api", "squuid").invoke();
141
+ ruby_uuid.init(java_uuid);
142
+ return ruby_uuid;
143
+ } catch (Throwable t) {
144
+ throw context.getRuntime().newRuntimeError("Datomic Exception: " + t.getMessage());
145
+ }
146
+ }
147
+
148
+ /**
149
+ * Gets the time part of a squuid
150
+ *
151
+ * @param context
152
+ * @param klazz
153
+ * @param arg diametric.UUID. squuid - a UUID created by squuid()
154
+ * @return the time in the format of System.currentTimeMillis
155
+ */
156
+ @JRubyMethod(meta=true)
157
+ public static IRubyObject squuid_time_millis(ThreadContext context, IRubyObject klazz, IRubyObject arg) {
158
+ if (!(arg instanceof diametric.DiametricUUID)) {
159
+ throw context.getRuntime().newArgumentError("Wrong argument type.");
160
+ }
161
+ java.util.UUID squuid = ((diametric.DiametricUUID)arg).getUUID();
162
+ if (squuid == null) return context.getRuntime().getNil();
163
+ long value;
164
+ try {
165
+ value = (Long) clojure.lang.RT.var("datomic.api", "squuid-time-millis").invoke(squuid);
166
+ return RubyFixnum.newFixnum(context.getRuntime(), value);
167
+ } catch (Throwable t) {
168
+ throw context.getRuntime().newRuntimeError("Datomic Exception: " + t.getMessage());
169
+ }
170
+ }
171
+
172
+ /**
173
+ * Generates a temp id in the designated partition
174
+ * In case the second argument is given,
175
+ * it should be an idNumber from -1 (inclusive) to -1000000 (exclusive).
176
+ *
177
+ * @param context
178
+ * @param klazz
179
+ * @param args the first argument: String. a partition, which is a keyword identifying the partition.
180
+ * @return
181
+ */
182
+ @JRubyMethod(meta=true, required=1, optional=1)
183
+ public static IRubyObject tempid(ThreadContext context, IRubyObject klazz, IRubyObject[] args) {
184
+ if (args.length < 1 || args.length > 2) {
185
+ throw context.getRuntime().newArgumentError("Wrong number of arguments");
186
+ }
187
+ String partition = DiametricUtils.rubyStringToJava(args[0]);
188
+ RubyClass clazz = (RubyClass)context.getRuntime().getClassFromPath("Diametric::Persistence::Object");
189
+ DiametricObject diametric_object = (DiametricObject)clazz.allocate();
190
+ try {
191
+ clojure.lang.Var clj_var = clojure.lang.RT.var("datomic.api", "tempid");
192
+ if (args.length > 1 && (args[1] instanceof RubyFixnum)) {
193
+ long idNumber = (Long) args[1].toJava(Long.class);
194
+ diametric_object.update(clj_var.invoke(partition, idNumber));
195
+ } else {
196
+ diametric_object.update(clj_var.invoke(partition));
197
+ }
198
+ return diametric_object;
199
+ } catch (Throwable t) {
200
+ throw context.getRuntime().newRuntimeError(t.getMessage());
201
+ }
202
+ }
203
+
204
+ /**
205
+ *
206
+ * @param context
207
+ * @param klazz
208
+ * @param args Both 2 arguments should be DiametricObject.
209
+ * The first argument should hold clojure.lang.PersistentArrayMap.
210
+ * The second one should hold datomic.db.DbId.
211
+ * @return
212
+ */
213
+ @JRubyMethod(meta=true, required=2, rest=true)
214
+ public static IRubyObject resolve_tempid(ThreadContext context, IRubyObject klazz, IRubyObject[] args) {
215
+ if (args.length != 2) {
216
+ throw context.getRuntime().newArgumentError("Wrong number of arguments");
217
+ }
218
+ Map map;
219
+ DiametricObject ruby_object;
220
+ if ((args[0] instanceof DiametricObject) && (args[1] instanceof DiametricObject)) {
221
+ map = (Map) ((DiametricObject)args[0]).toJava();
222
+ ruby_object = ((DiametricObject)args[1]);
223
+ } else {
224
+ throw context.getRuntime().newArgumentError("Wrong argument type.");
225
+ }
226
+ try {
227
+ Object dbid = clojure.lang.RT.var("datomic.api", "resolve-tempid")
228
+ .invoke(map.get(Connection.DB_AFTER), map.get(Connection.TEMPIDS), ruby_object.toJava());
229
+ ruby_object.update(dbid);
230
+ return ruby_object;
231
+ } catch (Throwable t) {
232
+ throw context.getRuntime().newRuntimeError("Datomic Exception: " + t.getMessage());
233
+ }
234
+ }
235
+
236
+ @JRubyMethod(meta=true, required=2, rest=true)
237
+ public static IRubyObject q(ThreadContext context, IRubyObject klazz, IRubyObject[] args) {
238
+ Ruby runtime = context.getRuntime();
239
+ if (args.length < 2) {
240
+ throw runtime.newArgumentError("Wrong number of arguments");
241
+ }
242
+ if (!(args[0] instanceof RubyString)) {
243
+ throw runtime.newArgumentError("The first arg should be a query string");
244
+ }
245
+ if (!(args[1] instanceof DiametricDatabase)) {
246
+ throw runtime.newArgumentError("The second arg should be a database.");
247
+ }
248
+ String query = (String)args[0].toJava(String.class);
249
+ Object database = ((DiametricDatabase)args[1]).toJava();
250
+
251
+ Collection<List<Object>> results = null;
252
+ try {
253
+ if (args.length == 2) {
254
+ results = (Collection<List<Object>>) clojure.lang.RT.var("datomic.api", "q").invoke(query, database);
255
+ } else if ((args.length == 3) && (args[2] instanceof RubyArray)) {
256
+ RubyArray ruby_inputs = (RubyArray)args[2];
257
+ if (ruby_inputs.getLength() == 0) {
258
+ results = Peer.q(query, database);
259
+ } else {
260
+ Object[] inputs = new Object[ruby_inputs.getLength()];
261
+ for (int i=0; i<inputs.length; i++) {
262
+ inputs[i] = DiametricUtils.convertRubyToJava(context, ruby_inputs.shift(context));
263
+ }
264
+ //System.out.println("OH INPUTS ARE: ");
265
+ //for (int i=0; i<inputs.length; i++) {
266
+ // System.out.println("OH: " + inputs[i]);
267
+ //}
268
+ results = (Collection<List<Object>>) clojure.lang.RT.var("datomic.api", "q").invoke(query, database, inputs);
269
+ }
270
+ } else {
271
+ Object[] inputs = new Object[args.length-2];
272
+ for (int i=0; i<inputs.length; i++) {
273
+ inputs[i] = DiametricUtils.convertRubyToJava(context, args[i+2]);
274
+ }
275
+ results = (Collection<List<Object>>) clojure.lang.RT.var("datomic.api", "q").invoke(query, database, inputs);
276
+ }
277
+ } catch (Throwable t) {
278
+ throw runtime.newRuntimeError("Datomic Exception: " + t.getMessage());
279
+ }
280
+
281
+ if (results == null) return context.getRuntime().getNil();
282
+ RubyArray ruby_results = RubyArray.newArray(context.getRuntime());
283
+ for (List list : results) {
284
+ RubyArray ruby_elements = RubyArray.newArray(context.getRuntime());
285
+ for (Object element : list) {
286
+ //System.out.println("OH ELEMENT IS: " + element + " [" + element.getClass().getCanonicalName() +"]");
287
+ ruby_elements.append(DiametricUtils.convertJavaToRuby(context, element));
288
+ }
289
+ ruby_results.append(ruby_elements);
290
+ }
291
+ return ruby_results;
292
+ }
293
+
294
+ private static List<RubyModule> bases = new ArrayList<RubyModule>();
295
+
296
+ @JRubyMethod(meta=true)
297
+ public static IRubyObject included(ThreadContext context, IRubyObject klazz, IRubyObject arg) {
298
+ Ruby runtime = context.getRuntime();
299
+ if (arg instanceof RubyModule) {
300
+ RubyModule base = (RubyModule)arg;
301
+ bases.add(base);
302
+ base.instance_variable_set(RubyString.newString(context.getRuntime(), "@peer"), runtime.getTrue());
303
+ IRubyObject common = runtime.getClassFromPath("Diametric::Persistence::Common");
304
+ base.send(context, RubySymbol.newSymbol(runtime, "include"), common, Block.NULL_BLOCK);
305
+ IRubyObject classmethods = runtime.getClassFromPath("Diametric::Persistence::Peer::ClassMethods");
306
+ base.send(context, RubySymbol.newSymbol(runtime, "extend"), classmethods, Block.NULL_BLOCK);
307
+ }
308
+ return runtime.getNil();
309
+ }
310
+
311
+ @JRubyMethod(meta=true)
312
+ public static IRubyObject connect(ThreadContext context, IRubyObject klazz) {
313
+ if (saved_connection == null) return context.getRuntime().getNil();
314
+ return saved_connection;
315
+ }
316
+
317
+ @JRubyMethod(meta=true)
318
+ public static IRubyObject create_schemas(ThreadContext context, IRubyObject klazz, IRubyObject arg) {
319
+ if (!(arg instanceof DiametricConnection))
320
+ throw context.getRuntime().newArgumentError("Argument should be Connection.");
321
+ IRubyObject result = context.getRuntime().getNil();
322
+ for (RubyModule base : bases) {
323
+ if (base.respondsTo("schema")) {
324
+ IRubyObject schema = base.send(context, RubySymbol.newSymbol(context.getRuntime(), "schema"), Block.NULL_BLOCK);
325
+ result = ((DiametricConnection)arg).transact(context, schema);
326
+ }
327
+ }
328
+ return result;
329
+ }
330
+
331
+ @JRubyMethod(meta=true)
332
+ public static IRubyObject transact(ThreadContext context, IRubyObject klazz, IRubyObject arg) {
333
+ return saved_connection.transact(context, arg);
334
+ }
335
+
336
+ @JRubyMethod(meta=true)
337
+ public static IRubyObject get(ThreadContext context, IRubyObject klazz, IRubyObject arg) {
338
+ Ruby runtime = context.getRuntime();
339
+ Object dbid = null;
340
+ if ((arg instanceof DiametricObject) && (((DiametricObject)arg).to_java(context) instanceof RubyFixnum)) {
341
+ dbid = ((DiametricObject)arg).toJava();
342
+ } else if (arg instanceof RubyFixnum) {
343
+ dbid = ((RubyFixnum)arg).toJava(Long.class);
344
+ } else {
345
+ throw runtime.newArgumentError("Argument should be dbid");
346
+ }
347
+ if (saved_connection == null) throw runtime.newRuntimeError("Connection is not established");
348
+ try {
349
+ Object database = clojure.lang.RT.var("datomic.api", "db").invoke(saved_connection.toJava());
350
+ Object entity = clojure.lang.RT.var("datomic.api", "entity").invoke(database, dbid);
351
+ RubyClass clazz = (RubyClass) context.getRuntime().getClassFromPath("Diametric::Persistence::Entity");
352
+ DiametricEntity ruby_entity = (DiametricEntity)clazz.allocate();
353
+ ruby_entity.init(entity);
354
+ return ruby_entity;
355
+ } catch (Throwable t) {
356
+ throw context.getRuntime().newRuntimeError(t.getMessage());
357
+ }
358
+ }
359
+
360
+ @JRubyMethod(meta=true)
361
+ public static IRubyObject retract_entity(ThreadContext context, IRubyObject klazz, IRubyObject arg) {
362
+ Object dbid = DiametricUtils.convertRubyToJava(context, arg);
363
+ List query = datomic.Util.list((datomic.Util.list(":db.fn/retractEntity", dbid)));
364
+ try {
365
+ clojure.lang.RT.var("datomic.api", "transact-async").invoke(saved_connection.toJava(), query);
366
+ } catch (Throwable t) {
367
+ throw context.getRuntime().newRuntimeError("Datomic error: " + t.getMessage());
368
+ }
369
+ return context.getRuntime().getNil();
370
+ }
371
+
372
+ /**
373
+ *
374
+ * @param context
375
+ * @param klazz
376
+ * @param args database, dbid, query
377
+ * @return
378
+ */
379
+ @JRubyMethod(meta=true, required=3, rest=true)
380
+ public static IRubyObject reverse_q(ThreadContext context, IRubyObject klazz, IRubyObject[] args) {
381
+ Ruby runtime = context.getRuntime();
382
+ if (args[0] instanceof DiametricDatabase &&
383
+ (args[1] instanceof DiametricObject || args[1] instanceof RubyFixnum) &&
384
+ args[2] instanceof RubyString) {
385
+ Object database = ((DiametricDatabase)args[0]).toJava();
386
+ Long dbid = (Long)DiametricUtils.convertRubyToJava(context, args[1]);
387
+ String query_string = (String)args[2].toJava(String.class);
388
+ try {
389
+ Object entity = clojure.lang.RT.var("datomic.api", "entity").invoke(database, dbid);
390
+ clojure.lang.PersistentHashSet set =
391
+ (PersistentHashSet) clojure.lang.RT.var("clojure.core", "get").invoke(entity, query_string);
392
+
393
+ if (set == null) {
394
+ return RubyArray.newEmptyArray(runtime);
395
+ }
396
+
397
+ RubyArray array = RubyArray.newArray(runtime, set.size());
398
+ Iterator iter = set.iterator();
399
+ while (iter.hasNext()) {
400
+ Object e = iter.next();
401
+ RubyClass clazz = (RubyClass) context.getRuntime().getClassFromPath("Diametric::Persistence::Entity");
402
+ DiametricEntity ruby_entity = (DiametricEntity)clazz.allocate();
403
+ ruby_entity.init(e);
404
+ array.append(ruby_entity);
405
+ }
406
+ return array;
407
+ } catch (Throwable t) {
408
+ throw runtime.newRuntimeError("Datomic Error: " + t.getMessage());
409
+ }
410
+ } else {
411
+ throw runtime.newArgumentError("Arguments should be 'database, dbid, query_string'");
412
+ }
413
+ }
414
+ }