Rubernate 0.1.5 → 0.1.6
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.
- data/README +1 -1
- data/lib/rubernate/callbacks.rb +17 -20
- data/lib/rubernate/impl/dbi_generic.rb +77 -50
- data/lib/rubernate/impl/dbi_mysql.rb +2 -2
- data/lib/rubernate/impl/dbi_oracle.rb +29 -3
- data/lib/rubernate/impl/dbi_pg.rb +2 -2
- data/lib/rubernate/impl/memory.rb +14 -12
- data/lib/rubernate/init/init_mysql.rb +2 -2
- data/lib/rubernate/init/init_oracle.rb +2 -2
- data/lib/rubernate/lazyload.rb +63 -0
- data/lib/rubernate/mixins.rb +6 -4
- data/lib/rubernate/persistent.rb +21 -21
- data/lib/rubernate/queries.rb +33 -11
- data/lib/rubernate/runtime.rb +49 -27
- data/lib/rubernate.rb +51 -33
- data/tests/config.rb +8 -5
- data/tests/rubernate/impl/dbi_generic_stub.rb +102 -35
- data/tests/rubernate/impl/dbi_oracle_test.rb +20 -0
- data/tests/rubernate/impl/memory_test.rb +16 -17
- data/tests/rubernate/rubernate_test.rb +352 -302
- metadata +3 -2
data/lib/rubernate/queries.rb
CHANGED
@@ -48,7 +48,13 @@ module Queries
|
|
48
48
|
end
|
49
49
|
end
|
50
50
|
|
51
|
-
# Factory method, creates queries
|
51
|
+
# Factory method, creates queries using stardart factory.
|
52
|
+
#
|
53
|
+
# :call-seq:
|
54
|
+
#
|
55
|
+
# q = Rubernate::Queries.query "Select :o; Where o.prop.str == :value"
|
56
|
+
# puts q.to_sql
|
57
|
+
#
|
52
58
|
def self.query q_text=nil, &q_block
|
53
59
|
if block_given?
|
54
60
|
@@generic_factory.query(&q_block)
|
@@ -68,7 +74,7 @@ module Queries
|
|
68
74
|
#
|
69
75
|
# New implementations of elements MUST accept factory as it's first parameter.
|
70
76
|
class Factory
|
71
|
-
attr_reader :cache # Queries cache. TODO: limit size!
|
77
|
+
attr_reader :cache # Queries cache. TODO: limit cache size!
|
72
78
|
# Initalizes default implementations
|
73
79
|
def initialize
|
74
80
|
@expr = Expr
|
@@ -102,7 +108,6 @@ module Queries
|
|
102
108
|
end
|
103
109
|
end
|
104
110
|
|
105
|
-
# Contains classes for standart ANSY SQL.
|
106
111
|
# Represent abstract expression
|
107
112
|
class Expr
|
108
113
|
include Operations
|
@@ -145,7 +150,7 @@ module Queries
|
|
145
150
|
end
|
146
151
|
end
|
147
152
|
|
148
|
-
# Represents constraint for one
|
153
|
+
# Represents constraint for one column.
|
149
154
|
class UnOpConstr < Expr
|
150
155
|
def initialize factory, expr, op, braces = false
|
151
156
|
@factory, @op, @braces = factory, op, braces
|
@@ -169,7 +174,7 @@ module Queries
|
|
169
174
|
end
|
170
175
|
end
|
171
176
|
|
172
|
-
# Represent constraint
|
177
|
+
# Represent constraint applied on two columns.
|
173
178
|
class BinOpConstr < Expr
|
174
179
|
def initialize factory, expr1, expr2, sign, braces = false
|
175
180
|
@factory, @sign, @braces = factory, sign, braces
|
@@ -196,7 +201,8 @@ module Queries
|
|
196
201
|
end
|
197
202
|
end
|
198
203
|
|
199
|
-
# Represent expression with
|
204
|
+
# Represent expression with tabls field such as
|
205
|
+
# <tt>r_params.name</tt> or <tt>r_objects.object_class</tt>
|
200
206
|
class FieldExpr < Expr
|
201
207
|
def initialize factory, table, field
|
202
208
|
@factory, @table, @field, @markers = factory, table, field, []
|
@@ -216,7 +222,7 @@ module Queries
|
|
216
222
|
end
|
217
223
|
end
|
218
224
|
|
219
|
-
#
|
225
|
+
# Represents r_params for hashes and arrays constrained by key
|
220
226
|
class KeyRefExpr < BinOpConstr
|
221
227
|
def initialize factory, r_param, key_field, key_value
|
222
228
|
@factory, @r_param, @key_field, @key_value = factory, r_param, key_field, key_value
|
@@ -227,7 +233,7 @@ module Queries
|
|
227
233
|
end
|
228
234
|
end
|
229
235
|
|
230
|
-
# Reresents
|
236
|
+
# Reresents collection of expressions
|
231
237
|
class ExprsList < Expr
|
232
238
|
def initialize factory, list
|
233
239
|
@factory, @exprs = factory, list.collect{|expr| Expr === expr ? expr : factory.expr(expr)}
|
@@ -243,7 +249,7 @@ module Queries
|
|
243
249
|
end
|
244
250
|
end
|
245
251
|
|
246
|
-
# Represents r_params table
|
252
|
+
# Represents <tt>r_params</tt> table
|
247
253
|
class RParam < Expr
|
248
254
|
include Rubernate::DBI
|
249
255
|
|
@@ -260,15 +266,31 @@ module Queries
|
|
260
266
|
@r_object.to_sql + @p_name
|
261
267
|
end
|
262
268
|
|
263
|
-
#
|
269
|
+
# Creates accessor to +r_params.primary_key+.
|
264
270
|
def pk () f_expr 'object_pk'; end
|
271
|
+
|
272
|
+
# Creates accessor to +r_params.int_value+.
|
265
273
|
def int () f_expr 'int_value'; end
|
274
|
+
|
275
|
+
# Creates accessor to +r_parms.flt_value+.
|
266
276
|
def float() f_expr 'flt_value'; end
|
277
|
+
|
278
|
+
# Creates accessor to +r_parms.str_value+.
|
267
279
|
def str () f_expr 'str_value'; end
|
280
|
+
|
281
|
+
# Creates accessor to +r_parms.dat_value+ with appropriate converison to time if needed.
|
268
282
|
def time () f_expr 'dat_value'; end
|
283
|
+
|
284
|
+
# Creates accessor to +r_parms.dat_value+ with appropriate converison if needed.
|
269
285
|
def date () f_expr 'dat_value'; end
|
286
|
+
|
287
|
+
# Creates accessor to +r_parms.ref_value+.
|
270
288
|
def ref () f_expr 'ref_value'; end
|
289
|
+
|
290
|
+
# Creates accessor to +r_parms.flags+.
|
271
291
|
def flags() f_expr 'flags'; end
|
292
|
+
|
293
|
+
# Creates accessor to +r_parms.name+.
|
272
294
|
def name () f_expr 'name'; end
|
273
295
|
|
274
296
|
# The following methods checks r_param.flags value. (r_param.flags)
|
@@ -304,7 +326,7 @@ module Queries
|
|
304
326
|
end
|
305
327
|
end
|
306
328
|
|
307
|
-
# Represent r_objects table
|
329
|
+
# Represent <tt>r_objects</tt> table
|
308
330
|
class RObject < Expr
|
309
331
|
# Init Table accepts query and name of table
|
310
332
|
def initialize factory, name
|
data/lib/rubernate/runtime.rb
CHANGED
@@ -1,4 +1,6 @@
|
|
1
|
-
|
1
|
+
require 'rubernate/lazyload'
|
2
|
+
|
3
|
+
module Rubernate
|
2
4
|
# Base class for all Runtime implementations.
|
3
5
|
class Runtime
|
4
6
|
include Callbacks::Runtime
|
@@ -6,13 +8,18 @@ module Rubernate
|
|
6
8
|
# Log for Runtime events
|
7
9
|
Log = Rubernate::Log
|
8
10
|
|
11
|
+
# Runtime scope settings
|
12
|
+
attr_reader :settings
|
13
|
+
|
9
14
|
def initialize
|
10
15
|
@pool = {} # Contains objects loaded during the session
|
11
|
-
|
12
|
-
|
16
|
+
@@factory = Queries::Factory.new unless @@factory
|
17
|
+
@factory = @@factory
|
18
|
+
@settings = Hash.new {|hash, key| hash[key] = Rubernate.settings[key]}
|
19
|
+
end
|
20
|
+
@@factory = nil
|
13
21
|
|
14
|
-
# Finds object by primary key
|
15
|
-
# raises ObjectNotFoundException if object is not found
|
22
|
+
# Finds object by primary key. Raises ObjectNotFoundException if object is not found
|
16
23
|
def find_by_pk pk, load = false
|
17
24
|
result = @pool[pk]
|
18
25
|
unless result
|
@@ -28,13 +35,14 @@ module Rubernate
|
|
28
35
|
result
|
29
36
|
end
|
30
37
|
|
31
|
-
# Finds objects by query. Returns ordered list of objects.
|
32
|
-
#
|
33
|
-
#
|
38
|
+
# Finds objects by query. Returns ordered list of objects or empty one if no objects was found.
|
39
|
+
# The query can be one of two types.
|
40
|
+
# * native sql - in this case +params+ should be of type Array.
|
41
|
+
# * query language - +params+ shoud be of type Hash.
|
34
42
|
def find_by_query query, params={} #TODO: improve working with paramters
|
35
43
|
flush_modified
|
36
44
|
params = case params
|
37
|
-
when Hash: params
|
45
|
+
when Hash : params
|
38
46
|
when Array: params
|
39
47
|
else [params]
|
40
48
|
end
|
@@ -54,7 +62,7 @@ module Rubernate
|
|
54
62
|
# primary key already loaded in session.
|
55
63
|
def attach object
|
56
64
|
raise "Can't attach object: #{object.primary_key}" if @pool.has_key? object.primary_key
|
57
|
-
object.
|
65
|
+
object.__peer = Peer.new unless object.__peer
|
58
66
|
create object
|
59
67
|
@pool[object.primary_key] = object
|
60
68
|
Log.debug {"Attach #{object.class.name}: #{object.primary_key} to session"}
|
@@ -75,13 +83,13 @@ module Rubernate
|
|
75
83
|
raise
|
76
84
|
end
|
77
85
|
|
78
|
-
# Begins session
|
86
|
+
# Begins session and transaction.
|
79
87
|
def begin
|
80
88
|
Log.debug {"Begin session #{self}"}
|
81
89
|
on_begin
|
82
90
|
end
|
83
91
|
|
84
|
-
# Persist all changes and
|
92
|
+
# Persist all changes and commit transction.
|
85
93
|
def commit
|
86
94
|
before_commit # callback
|
87
95
|
flush_modified
|
@@ -93,7 +101,7 @@ module Rubernate
|
|
93
101
|
raise
|
94
102
|
end
|
95
103
|
|
96
|
-
# Discard all changes and
|
104
|
+
# Discard all changes and rollback transaction.
|
97
105
|
def rollback ex='not specified'
|
98
106
|
on_rollback # callback
|
99
107
|
Log.warn {"Rollback session #{self} due to error: #{ex}"}
|
@@ -103,7 +111,10 @@ module Rubernate
|
|
103
111
|
raise
|
104
112
|
end
|
105
113
|
|
106
|
-
#
|
114
|
+
# Stores modified objects to database. This method is invoked before
|
115
|
+
# transaction commit and before each invokation of Runtime.find_by_query.
|
116
|
+
# You can invoke this method manually if you want to store all changes of your
|
117
|
+
# objects to database immediately.
|
107
118
|
def flush_modified
|
108
119
|
objects = modified
|
109
120
|
before_flush modified # callback
|
@@ -116,8 +127,9 @@ module Rubernate
|
|
116
127
|
|
117
128
|
private
|
118
129
|
# Creates new object instance or returns insance from pool
|
119
|
-
#
|
120
|
-
|
130
|
+
# * klass - can be Class or String (class name)
|
131
|
+
# * peer - can be Peer, LazyLoader or nill
|
132
|
+
def instantiate pk, klass, peer = nil
|
121
133
|
object = @pool[pk]
|
122
134
|
unless object
|
123
135
|
clazz = klass.is_a?(Class) ? klass : get_class(klass)
|
@@ -125,10 +137,10 @@ module Rubernate
|
|
125
137
|
object.primary_key = pk
|
126
138
|
@pool[pk] = object
|
127
139
|
end
|
128
|
-
object.
|
140
|
+
object.__peer = peer if peer
|
129
141
|
object
|
130
|
-
end
|
131
|
-
|
142
|
+
end
|
143
|
+
|
132
144
|
#Classes cache.
|
133
145
|
@@classes = {}
|
134
146
|
|
@@ -141,17 +153,27 @@ module Rubernate
|
|
141
153
|
@@classes[name] = klass
|
142
154
|
end
|
143
155
|
|
156
|
+
# Returns LazyLoaderFactory instance.
|
157
|
+
def lazy_factory
|
158
|
+
case settings[:lazy_load]
|
159
|
+
when :holder: HolderLazyLoaderFactory.new
|
160
|
+
when :collection: ParamLazyLoaderFactory.new
|
161
|
+
when :separately, nil: LazyLoaderFactory.new
|
162
|
+
else "wrong value for setting :lazy_load - #{settings[:lazy_load]}"
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
144
166
|
# Returns modified objects.
|
145
167
|
def modified
|
146
|
-
@pool.values.find_all {|object| object.
|
168
|
+
@pool.values.find_all {|object| object.__peer and object.dirty?}
|
147
169
|
end
|
148
170
|
|
149
|
-
# Callback functions invoked when session successfully closed
|
171
|
+
# Callback functions it's invoked when session successfully closed
|
150
172
|
# Should be overriden by subclasses to perform implement closing logic
|
151
173
|
def close
|
152
174
|
end
|
153
175
|
|
154
|
-
# Callback functions invoked when session fails
|
176
|
+
# Callback functions it's invoked when session fails.
|
155
177
|
# Should be overriden by subclasses to cleanup resources
|
156
178
|
def failed
|
157
179
|
end
|
@@ -203,10 +225,10 @@ module Rubernate
|
|
203
225
|
end
|
204
226
|
|
205
227
|
def post_load object
|
206
|
-
for value in object.
|
228
|
+
for value in object.__peer.values
|
207
229
|
value.compact! if value.is_a? Array
|
208
230
|
end
|
209
|
-
object.
|
231
|
+
object.__peer.dirty = false
|
210
232
|
object.on_load
|
211
233
|
end
|
212
234
|
|
@@ -221,10 +243,10 @@ module Rubernate
|
|
221
243
|
when Class: p.name
|
222
244
|
else p
|
223
245
|
end
|
224
|
-
end
|
246
|
+
end
|
225
247
|
end
|
226
|
-
|
227
|
-
# Represetns
|
248
|
+
|
249
|
+
# Represetns object whose class wasn't found during loading.
|
228
250
|
class DummyPersistent
|
229
251
|
persistent
|
230
252
|
def initialize class_name
|
data/lib/rubernate.rb
CHANGED
@@ -41,8 +41,8 @@ module Rubernate
|
|
41
41
|
# Rubernate core singelton methods.
|
42
42
|
class << self
|
43
43
|
# Allows you setup Rubernate by yours implementaion of Configuration.
|
44
|
-
# See also method config
|
45
|
-
def configuration= config
|
44
|
+
# See also method config
|
45
|
+
def configuration= config # :nodoc:
|
46
46
|
Log.info "Rubernate configured by #{config}"
|
47
47
|
@factory = config
|
48
48
|
end
|
@@ -63,37 +63,14 @@ module Rubernate
|
|
63
63
|
self.configuration = DBI::Configuration.new impl, init, url, user, password
|
64
64
|
end
|
65
65
|
|
66
|
-
# Loads MySQL module
|
67
|
-
def require_mysql
|
68
|
-
require 'rubernate/impl/dbi_mysql'
|
69
|
-
require 'rubernate/init/init_mysql'
|
70
|
-
[DBI::MySqlRuntime, DBI::MySqlInit.new]
|
71
|
-
end
|
72
|
-
|
73
|
-
# Loads Oracle module
|
74
|
-
def require_oracle
|
75
|
-
require 'rubernate/impl/dbi_oracle'
|
76
|
-
require 'rubernate/init/init_oracle'
|
77
|
-
[DBI::OracleRuntime, DBI::OracleInit.new]
|
78
|
-
end
|
79
|
-
|
80
|
-
# Loads Postgres module
|
81
|
-
def require_pg
|
82
|
-
require 'rubernate/impl/dbi_pg'
|
83
|
-
require 'rubernate/init/init_pg'
|
84
|
-
[DBI::PgRuntime, DBI::PgInit.new]
|
85
|
-
end
|
86
|
-
|
87
|
-
# Loads Memory module used only for testing
|
88
|
-
def require_memory
|
89
|
-
require 'rubernate/impl/memory'
|
90
|
-
Memory::Runtime
|
91
|
-
end
|
92
66
|
|
93
67
|
# Intializes database - creates necessary tables, sequences and indices.
|
94
68
|
def init_db
|
95
69
|
@factory.init_db
|
96
70
|
end
|
71
|
+
|
72
|
+
# Global scope settings
|
73
|
+
attr_reader :settings
|
97
74
|
|
98
75
|
# Returns Runtime object associated with current session
|
99
76
|
# or nil if session does not excists
|
@@ -108,8 +85,9 @@ module Rubernate
|
|
108
85
|
Thread.current[:Rubernate] != nil
|
109
86
|
end
|
110
87
|
|
111
|
-
# Begins new
|
88
|
+
# Begins new session and transaction in database. Returns Runtime object or supply it to block if one is given.
|
112
89
|
def session
|
90
|
+
raise 'No config found. Call Rubernate.config first.' unless @factory
|
113
91
|
runtime = @factory.create
|
114
92
|
Thread.current[:Rubernate] = runtime
|
115
93
|
runtime.begin
|
@@ -125,19 +103,59 @@ module Rubernate
|
|
125
103
|
end
|
126
104
|
result
|
127
105
|
end
|
128
|
-
|
106
|
+
private
|
107
|
+
# Loads MySQL module
|
108
|
+
def require_mysql # :nodoc:
|
109
|
+
require 'rubernate/impl/dbi_mysql'
|
110
|
+
require 'rubernate/init/init_mysql'
|
111
|
+
[DBI::MySqlRuntime, DBI::MySqlInit.new]
|
112
|
+
end
|
129
113
|
|
130
|
-
|
114
|
+
# Loads Oracle module
|
115
|
+
def require_oracle # :nodoc:
|
116
|
+
require 'rubernate/impl/dbi_oracle'
|
117
|
+
require 'rubernate/init/init_oracle'
|
118
|
+
[DBI::OracleRuntime, DBI::OracleInit.new]
|
119
|
+
end
|
120
|
+
|
121
|
+
# Loads Postgres module
|
122
|
+
def require_pg # :nodoc:
|
123
|
+
require 'rubernate/impl/dbi_pg'
|
124
|
+
require 'rubernate/init/init_pg'
|
125
|
+
[DBI::PgRuntime, DBI::PgInit.new]
|
126
|
+
end
|
127
|
+
|
128
|
+
# Loads Memory module used only for testing :nodoc:
|
129
|
+
def require_memory # :nodoc:
|
130
|
+
require 'rubernate/impl/memory'
|
131
|
+
Memory::Runtime
|
132
|
+
end
|
133
|
+
end
|
134
|
+
@settings = {}
|
135
|
+
|
136
|
+
# Finds object by primary key. This method is actually shortcut to Runtime.find_by_pk
|
131
137
|
def find_by_pk pk
|
132
138
|
Rubernate.runtime.find_by_pk pk
|
133
139
|
end
|
134
140
|
|
135
|
-
#
|
141
|
+
# Finds object by query. This method is actually shortcut to Runtime.find_by_query
|
142
|
+
# Retruns array of objects, accepts native sql or query language expressions.
|
143
|
+
# If query is sql then +params+ should be array as in DBI. Else it should be Hash of <tt>{:maker=>value}</tt>.
|
144
|
+
#
|
145
|
+
# :call-seq: find_by_query(query, params={})
|
146
|
+
#
|
147
|
+
# Rubernate.find_by_query 'Select :p; Where p.name.str == :name', :name => 'Andy'
|
148
|
+
#
|
149
|
+
# #Or the same using native sql.
|
150
|
+
# Rubernate.find_by_query "select p_.* from r_objects p_ left outer join r_params p_name
|
151
|
+
# on (p_.object_pk = p_name.object_pk)
|
152
|
+
# where p_name.name = 'name' and p_name.str_value = ?", ['Andy']
|
153
|
+
#
|
136
154
|
def find_by_query query, params={}
|
137
155
|
Rubernate.runtime.find_by_query query, params
|
138
156
|
end
|
139
157
|
|
140
|
-
#
|
158
|
+
# Returns current runtime object.
|
141
159
|
def runtime
|
142
160
|
Rubernate.runtime
|
143
161
|
end
|
data/tests/config.rb
CHANGED
@@ -1,15 +1,17 @@
|
|
1
1
|
# Set to true to run tests on Oracle
|
2
2
|
$run_oracle_tests = false
|
3
3
|
|
4
|
-
|
5
|
-
|
4
|
+
module Rubernate
|
5
|
+
|
6
|
+
ORA_RUNTIME_CLASS = require_oracle[0]
|
7
|
+
ORA_DB_URL = 'dbi:OCI8:nc65db'
|
6
8
|
ORA_DB_USER = 'netcracker65'
|
7
9
|
ORA_DB_PWD = 'netcracker65'
|
8
10
|
|
9
11
|
# Set to true to run tests on MySQL
|
10
12
|
$run_mysql_tests = false
|
11
13
|
|
12
|
-
MYSQL_RUNTIME_CLASS =
|
14
|
+
MYSQL_RUNTIME_CLASS = require_mysql[0]
|
13
15
|
MYSQL_DB_URL = 'dbi:Mysql:rubernate_db:localhost'
|
14
16
|
MYSQL_DB_USER = nil
|
15
17
|
MYSQL_DB_PWD = nil
|
@@ -17,12 +19,13 @@ MYSQL_DB_PWD = nil
|
|
17
19
|
# Set to true to run tests on PostgreSQL
|
18
20
|
$run_pg_tests = false
|
19
21
|
|
20
|
-
PG_RUNTIME_CLASS =
|
22
|
+
PG_RUNTIME_CLASS = require_pg[0]
|
21
23
|
PG_DB_URL = 'dbi:Pg:rubernate_db'
|
22
24
|
PG_DB_USER = 'rn_test'
|
23
25
|
PG_DB_PWD = 'rn_password'
|
24
26
|
|
25
|
-
|
27
|
+
require_memory
|
28
|
+
end
|
26
29
|
|
27
30
|
# Log4r configuration
|
28
31
|
Rubernate::Log.level = Log4r::DEBUG
|