og 0.9.5 → 0.10.0
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/ChangeLog +260 -0
- data/LICENSE +1 -0
- data/README.og +6 -5
- data/RELEASES.og +23 -0
- data/Rakefile +102 -92
- data/examples/og/mock_example.rb +0 -2
- data/examples/og/mysql_to_psql.rb +0 -2
- data/examples/og/run.rb +23 -22
- data/install.rb +44 -0
- data/lib/glue/array.rb +6 -10
- data/lib/glue/attribute.rb +0 -3
- data/lib/glue/cache.rb +1 -1
- data/lib/glue/inflector.rb +5 -5
- data/lib/glue/mixins.rb +3 -12
- data/lib/glue/number.rb +1 -1
- data/lib/glue/object.rb +7 -1
- data/lib/glue/property.rb +32 -22
- data/lib/glue/string.rb +13 -75
- data/lib/glue/time.rb +2 -2
- data/lib/glue/validation.rb +7 -11
- data/lib/og.rb +27 -261
- data/lib/og/adapter.rb +352 -0
- data/lib/og/adapters/mysql.rb +304 -0
- data/lib/og/adapters/psql.rb +286 -0
- data/lib/og/adapters/sqlite.rb +262 -0
- data/lib/og/backend.rb +1 -1
- data/lib/og/connection.rb +123 -87
- data/lib/og/database.rb +268 -0
- data/lib/og/meta.rb +23 -22
- data/lib/og/mock.rb +2 -3
- data/test/og/tc_lifecycle.rb +22 -25
- data/test/og/tc_sqlite.rb +87 -0
- data/test/tc_og.rb +61 -42
- metadata +35 -11
- data/lib/glue/macro.rb +0 -56
- data/lib/og/backends/mysql.rb +0 -370
- data/lib/og/backends/psql.rb +0 -386
- data/lib/og/backends/sqlite.rb +0 -383
- data/lib/og/version.rb +0 -9
@@ -0,0 +1,87 @@
|
|
1
|
+
$:.unshift File.join(File.dirname(__FILE__), '..', '..', 'lib')
|
2
|
+
|
3
|
+
=begin
|
4
|
+
|
5
|
+
require 'test/unit'
|
6
|
+
require 'ostruct'
|
7
|
+
|
8
|
+
require 'og'
|
9
|
+
require 'og/adapters/sqlite'
|
10
|
+
|
11
|
+
class TC_OgSqlite3 < Test::Unit::TestCase # :nodoc: all
|
12
|
+
include N
|
13
|
+
|
14
|
+
# Forward declaration.
|
15
|
+
|
16
|
+
class Comment; end
|
17
|
+
|
18
|
+
class Article
|
19
|
+
prop_accessor :name, String
|
20
|
+
prop_accessor :age, Fixnum
|
21
|
+
has_many :comments, Comment
|
22
|
+
|
23
|
+
def initialize (name = nil, age = nil)
|
24
|
+
@name, @age = name, age
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class Comment
|
29
|
+
prop_accessor :text, String
|
30
|
+
belongs_to :article, Article
|
31
|
+
|
32
|
+
def initialize(text = nil)
|
33
|
+
@text = text
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def setup
|
38
|
+
config = {
|
39
|
+
:adapter => 'sqlite',
|
40
|
+
:database => 'test',
|
41
|
+
:connection_count => 2
|
42
|
+
}
|
43
|
+
|
44
|
+
$DBG = true
|
45
|
+
|
46
|
+
Og::Database.drop_db!(config)
|
47
|
+
@og = Og::Database.new(config)
|
48
|
+
end
|
49
|
+
|
50
|
+
def teardown
|
51
|
+
@og.shutdown
|
52
|
+
end
|
53
|
+
|
54
|
+
def test_all
|
55
|
+
a = Article.new('gmosx', 30)
|
56
|
+
a.save!
|
57
|
+
|
58
|
+
a1 = Article[1]
|
59
|
+
|
60
|
+
assert_equal 'gmosx', a1.name
|
61
|
+
assert_equal 30, a1.age
|
62
|
+
assert_equal 1, a1.oid
|
63
|
+
|
64
|
+
Article.create('drak', 12)
|
65
|
+
Article.create('ekarak', 34)
|
66
|
+
Article.create('mario', 53)
|
67
|
+
Article.create('elathan', 34)
|
68
|
+
|
69
|
+
articles = Article.all
|
70
|
+
|
71
|
+
assert_equal 5, articles.size
|
72
|
+
|
73
|
+
a3 = Article[3]
|
74
|
+
|
75
|
+
assert_equal 'ekarak', a3.name
|
76
|
+
|
77
|
+
c1 = Comment.new('a comment')
|
78
|
+
c1.save!
|
79
|
+
a3.add_comment(c1)
|
80
|
+
|
81
|
+
a5 = Article[3]
|
82
|
+
assert_equal 1, a5.comments.size
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
86
|
+
|
87
|
+
=end
|
data/test/tc_og.rb
CHANGED
@@ -85,52 +85,59 @@ class OrderItem
|
|
85
85
|
end
|
86
86
|
|
87
87
|
class TC_N_OG < Test::Unit::TestCase
|
88
|
+
def test_psql
|
89
|
+
config = {
|
90
|
+
:adapter => 'psql',
|
91
|
+
# :address => 'localhost',
|
92
|
+
:database => 'test',
|
93
|
+
:user => 'postgres',
|
94
|
+
:password => 'navelrulez',
|
95
|
+
:connection_count => 2
|
96
|
+
}
|
97
|
+
|
98
|
+
run_all_tests(config)
|
99
|
+
end
|
88
100
|
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
else
|
102
|
-
config = {
|
103
|
-
:backend => "mysql",
|
104
|
-
:address => "localhost",
|
105
|
-
:database => "test",
|
106
|
-
:user => "root",
|
107
|
-
:password => "navelrulez",
|
108
|
-
:connection_count => 1
|
109
|
-
}
|
110
|
-
end
|
111
|
-
|
112
|
-
Og::Database.drop_db!(config)
|
113
|
-
$og = Og::Database.new(config)
|
101
|
+
=begin
|
102
|
+
def test_mysql
|
103
|
+
config = {
|
104
|
+
:adapter => 'mysql',
|
105
|
+
# :address => 'localhost',
|
106
|
+
:database => 'test',
|
107
|
+
:user => 'root',
|
108
|
+
:password => 'navelrulez',
|
109
|
+
:connection_count => 2
|
110
|
+
}
|
111
|
+
|
112
|
+
run_all_tests(config)
|
114
113
|
end
|
115
114
|
|
116
|
-
def
|
117
|
-
|
115
|
+
def test_sqlite
|
116
|
+
config = {
|
117
|
+
:adapter => 'sqlite',
|
118
|
+
:database => 'test',
|
119
|
+
:connection_count => 2
|
120
|
+
}
|
121
|
+
|
122
|
+
run_all_tests(config)
|
118
123
|
end
|
124
|
+
=end
|
119
125
|
|
120
126
|
# gmosx: hmm, implemented in one method to enforce order.
|
121
|
-
|
122
|
-
def
|
123
|
-
|
127
|
+
|
128
|
+
def run_all_tests(config)
|
129
|
+
Og::Database.drop_db!(config)
|
130
|
+
og = Og::Database.new(config)
|
124
131
|
|
125
|
-
|
132
|
+
og.get_connection
|
126
133
|
|
127
134
|
article = Article.new("Title", "Here comes the body")
|
128
|
-
|
135
|
+
og << article
|
129
136
|
|
130
137
|
article.title = "Changed"
|
131
138
|
article.save!
|
132
139
|
|
133
|
-
|
140
|
+
og.pupdate("body='Hello'", article)
|
134
141
|
|
135
142
|
article.update_properties "body='Hello'"
|
136
143
|
|
@@ -143,9 +150,9 @@ class TC_N_OG < Test::Unit::TestCase
|
|
143
150
|
another.options = nil
|
144
151
|
another.save!
|
145
152
|
|
146
|
-
assert_equal(nil,
|
153
|
+
assert_equal(nil, og.load(30000, Article))
|
147
154
|
|
148
|
-
articles =
|
155
|
+
articles = og.load_all(Article)
|
149
156
|
|
150
157
|
# p articles
|
151
158
|
# p Article[23]
|
@@ -157,9 +164,9 @@ class TC_N_OG < Test::Unit::TestCase
|
|
157
164
|
|
158
165
|
assert_equal("gmosx", user.name)
|
159
166
|
|
160
|
-
users1 =
|
167
|
+
users1 = og.select("name='gmosx' ORDER BY oid", User)
|
161
168
|
|
162
|
-
users =
|
169
|
+
users = og.select("SELECT * FROM #{User::DBTABLE} WHERE name='gmosx' ORDER BY oid", User)
|
163
170
|
|
164
171
|
users2 = User.select "name='gmosx' ORDER BY oid"
|
165
172
|
|
@@ -173,7 +180,6 @@ class TC_N_OG < Test::Unit::TestCase
|
|
173
180
|
comment.author = User["gmosx"]
|
174
181
|
comment.save!
|
175
182
|
|
176
|
-
|
177
183
|
# test automatically generated add_commnet
|
178
184
|
comment = Comment.new("This is another comment")
|
179
185
|
comment.author = User["gmosx"]
|
@@ -195,8 +201,10 @@ class TC_N_OG < Test::Unit::TestCase
|
|
195
201
|
article.add_comment(Comment.new("hello"))
|
196
202
|
article.add_comment(Comment.new("world"))
|
197
203
|
|
204
|
+
assert_equal 2, Comment.count
|
205
|
+
|
198
206
|
Article.delete(article)
|
199
|
-
|
207
|
+
|
200
208
|
assert Comment.all.empty?
|
201
209
|
|
202
210
|
comment.delete!
|
@@ -210,14 +218,14 @@ class TC_N_OG < Test::Unit::TestCase
|
|
210
218
|
end
|
211
219
|
end
|
212
220
|
|
213
|
-
assert(
|
221
|
+
assert(og.managed_classes.include?(Test::Article))
|
214
222
|
|
215
223
|
# bug: indirectly managed (includes managed Module)
|
216
|
-
assert(
|
224
|
+
assert(og.managed_classes.include?(Test::MyClass))
|
217
225
|
|
218
226
|
# test create
|
219
227
|
article = Article.create("title", "body")
|
220
|
-
assert_equal(3, article.oid)
|
228
|
+
# assert_equal(3, article.oid)
|
221
229
|
|
222
230
|
# test refers_to
|
223
231
|
|
@@ -235,7 +243,18 @@ class TC_N_OG < Test::Unit::TestCase
|
|
235
243
|
|
236
244
|
user = User['gmosx']
|
237
245
|
assert_equal true, user.banned
|
246
|
+
|
247
|
+
og.put_connection
|
248
|
+
og.shutdown
|
249
|
+
|
250
|
+
# Test database allready exists
|
251
|
+
|
252
|
+
og = Og::Database.new(config)
|
253
|
+
|
254
|
+
user = User.new("gmosx")
|
255
|
+
user.save!
|
238
256
|
|
257
|
+
og.shutdown
|
239
258
|
end
|
240
259
|
|
241
260
|
end
|
metadata
CHANGED
@@ -3,13 +3,13 @@ rubygems_version: 0.8.4
|
|
3
3
|
specification_version: 1
|
4
4
|
name: og
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.
|
7
|
-
date: 2005-02-
|
6
|
+
version: 0.10.0
|
7
|
+
date: 2005-02-15
|
8
8
|
summary: Og (ObjectGraph)
|
9
9
|
require_paths:
|
10
10
|
- lib
|
11
11
|
email: gm@navel.gr
|
12
|
-
homepage: http://www.
|
12
|
+
homepage: http://www.rubyforge.com/projects/nitro
|
13
13
|
rubyforge_project: nitro
|
14
14
|
description: An efficient and transparent Object-Relational mapping library
|
15
15
|
autorequire: og
|
@@ -21,7 +21,7 @@ required_ruby_version: !ruby/object:Gem::Version::Requirement
|
|
21
21
|
-
|
22
22
|
- ">="
|
23
23
|
- !ruby/object:Gem::Version
|
24
|
-
version: 1.8.
|
24
|
+
version: 1.8.0
|
25
25
|
version:
|
26
26
|
platform: ruby
|
27
27
|
authors:
|
@@ -34,6 +34,7 @@ files:
|
|
34
34
|
- Rakefile
|
35
35
|
- ChangeLog.1
|
36
36
|
- ChangeLog
|
37
|
+
- install.rb
|
37
38
|
- examples/og/mysql_to_psql.rb
|
38
39
|
- examples/og/run.rb
|
39
40
|
- examples/og/mock_example.rb
|
@@ -48,7 +49,6 @@ files:
|
|
48
49
|
- lib/glue/time.rb
|
49
50
|
- lib/glue/property.rb
|
50
51
|
- lib/glue/misc.rb
|
51
|
-
- lib/glue/macro.rb
|
52
52
|
- lib/glue/flexob.rb
|
53
53
|
- lib/glue/cache.rb
|
54
54
|
- lib/glue/string.rb
|
@@ -56,18 +56,20 @@ files:
|
|
56
56
|
- lib/glue/array.rb
|
57
57
|
- lib/glue/validation.rb
|
58
58
|
- lib/glue/attribute.rb
|
59
|
-
- lib/og/
|
60
|
-
- lib/og/
|
59
|
+
- lib/og/adapter.rb
|
60
|
+
- lib/og/adapters
|
61
61
|
- lib/og/enchant.rb
|
62
62
|
- lib/og/connection.rb
|
63
|
+
- lib/og/database.rb
|
63
64
|
- lib/og/mock.rb
|
64
65
|
- lib/og/meta.rb
|
65
66
|
- lib/og/backend.rb
|
66
|
-
- lib/og/
|
67
|
-
- lib/og/
|
68
|
-
- lib/og/
|
67
|
+
- lib/og/adapters/mysql.rb
|
68
|
+
- lib/og/adapters/sqlite.rb
|
69
|
+
- lib/og/adapters/psql.rb
|
69
70
|
- lib/og.rb
|
70
71
|
- test/tc_og.rb
|
72
|
+
- test/og/tc_sqlite.rb
|
71
73
|
- test/og/tc_lifecycle.rb
|
72
74
|
- vendor/extensions/enumerable.rb
|
73
75
|
- vendor/extensions/all.rb
|
@@ -92,6 +94,8 @@ rdoc_options:
|
|
92
94
|
- README.og
|
93
95
|
- "--title"
|
94
96
|
- Og Documentation
|
97
|
+
- "--all"
|
98
|
+
- "--inline-source"
|
95
99
|
extra_rdoc_files:
|
96
100
|
- README.og
|
97
101
|
- RELEASES.og
|
@@ -100,4 +104,24 @@ extra_rdoc_files:
|
|
100
104
|
executables: []
|
101
105
|
extensions: []
|
102
106
|
requirements: []
|
103
|
-
dependencies:
|
107
|
+
dependencies:
|
108
|
+
- !ruby/object:Gem::Dependency
|
109
|
+
name: extensions
|
110
|
+
version_requirement:
|
111
|
+
version_requirements: !ruby/object:Gem::Version::Requirement
|
112
|
+
requirements:
|
113
|
+
-
|
114
|
+
- ">="
|
115
|
+
- !ruby/object:Gem::Version
|
116
|
+
version: "0.5"
|
117
|
+
version:
|
118
|
+
- !ruby/object:Gem::Dependency
|
119
|
+
name: flexmock
|
120
|
+
version_requirement:
|
121
|
+
version_requirements: !ruby/object:Gem::Version::Requirement
|
122
|
+
requirements:
|
123
|
+
-
|
124
|
+
- ">="
|
125
|
+
- !ruby/object:Gem::Version
|
126
|
+
version: 0.0.3
|
127
|
+
version:
|
data/lib/glue/macro.rb
DELETED
@@ -1,56 +0,0 @@
|
|
1
|
-
# = Macros
|
2
|
-
#
|
3
|
-
# A powerfull macro implementation for Ruby. Allows definition
|
4
|
-
# of new macro.
|
5
|
-
#
|
6
|
-
# EXPERIMENTAL, not fully working yet
|
7
|
-
#
|
8
|
-
# code:
|
9
|
-
# George Moschovitis <gm@navel.gr>
|
10
|
-
#
|
11
|
-
# (c) 2004 Navel, all rights reserved.
|
12
|
-
# $Id: macro.rb 165 2004-11-18 12:04:04Z gmosx $
|
13
|
-
|
14
|
-
$__macros__ = {}
|
15
|
-
$__required__ = {}
|
16
|
-
|
17
|
-
module Kernel
|
18
|
-
|
19
|
-
alias_method :old_require, :require
|
20
|
-
def require(path)
|
21
|
-
return if $__required__[path]
|
22
|
-
|
23
|
-
source = File.read(path)
|
24
|
-
|
25
|
-
# parse macro
|
26
|
-
source.gsub!(/defmacro\s*\/(.*?)\/\s(.*?)endmacro/m) {
|
27
|
-
$__macros__[Regexp.new($1)] = $2 ; ""
|
28
|
-
}
|
29
|
-
|
30
|
-
# expand macros
|
31
|
-
$__macros__.each { |match, replace|
|
32
|
-
source.gsub!(match, replace)
|
33
|
-
}
|
34
|
-
|
35
|
-
$__required__[path] = true
|
36
|
-
|
37
|
-
eval(source)
|
38
|
-
end
|
39
|
-
|
40
|
-
end
|
41
|
-
|
42
|
-
require "nitro/test1.rb"
|
43
|
-
require "nitro/test2.rb"
|
44
|
-
|
45
|
-
__END__
|
46
|
-
|
47
|
-
Examples:
|
48
|
-
|
49
|
-
defmacro /my_macro\((.*)\)/
|
50
|
-
begin
|
51
|
-
my_function(\1)
|
52
|
-
rescue => ex
|
53
|
-
puts ex
|
54
|
-
end
|
55
|
-
endmacro
|
56
|
-
|
data/lib/og/backends/mysql.rb
DELETED
@@ -1,370 +0,0 @@
|
|
1
|
-
# * George Moschovitis <gm@navel.gr>
|
2
|
-
# * Elias Athanasopoulos <elathan@navel.gr>
|
3
|
-
# (c) 2004-2005 Navel, all rights reserved.
|
4
|
-
# $Id: mysql.rb 248 2005-01-31 13:38:34Z gmosx $
|
5
|
-
|
6
|
-
require 'mysql'
|
7
|
-
|
8
|
-
require 'og/backend'
|
9
|
-
|
10
|
-
class Og
|
11
|
-
|
12
|
-
# Implements a MySQL powered backend.
|
13
|
-
|
14
|
-
class MysqlBackend < Og::Backend
|
15
|
-
|
16
|
-
# A mapping between Ruby and SQL types.
|
17
|
-
|
18
|
-
TYPEMAP = {
|
19
|
-
Integer => 'integer',
|
20
|
-
Fixnum => 'integer',
|
21
|
-
Float => 'float',
|
22
|
-
String => 'text',
|
23
|
-
Time => 'timestamp',
|
24
|
-
Date => 'date',
|
25
|
-
TrueClass => 'tinyint',
|
26
|
-
Object => 'text',
|
27
|
-
Array => 'text',
|
28
|
-
Hash => 'text'
|
29
|
-
}
|
30
|
-
|
31
|
-
# Intitialize the connection to the RDBMS.
|
32
|
-
|
33
|
-
def initialize(config)
|
34
|
-
begin
|
35
|
-
@conn = Mysql.connect(config[:address], config[:user],
|
36
|
-
config[:password], config[:database])
|
37
|
-
rescue => ex
|
38
|
-
if ex.errno == 1049 # database does not exist.
|
39
|
-
Logger.info "Database '#{config[:database]}' not found!"
|
40
|
-
MysqlBackend.create_db(config[:database], config[:user], config[:password])
|
41
|
-
retry
|
42
|
-
end
|
43
|
-
raise
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
48
|
-
# Utilities
|
49
|
-
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
50
|
-
|
51
|
-
# Escape an SQL string
|
52
|
-
|
53
|
-
def self.escape(str)
|
54
|
-
return nil unless str
|
55
|
-
return Mysql.quote(str)
|
56
|
-
end
|
57
|
-
|
58
|
-
# Convert a ruby time to an sql timestamp.
|
59
|
-
# TODO: Optimize this
|
60
|
-
|
61
|
-
def self.timestamp(time = Time.now)
|
62
|
-
return nil unless time
|
63
|
-
return time.strftime("%Y%m%d%H%M%S")
|
64
|
-
end
|
65
|
-
|
66
|
-
# Output YYY-mm-dd
|
67
|
-
# TODO: Optimize this
|
68
|
-
|
69
|
-
def self.date(date)
|
70
|
-
return nil unless date
|
71
|
-
return "#{date.year}-#{date.month}-#{date.mday}"
|
72
|
-
end
|
73
|
-
|
74
|
-
# Parse sql datetime
|
75
|
-
# TODO: Optimize this
|
76
|
-
|
77
|
-
def self.parse_timestamp(str)
|
78
|
-
return Time.parse(str)
|
79
|
-
end
|
80
|
-
|
81
|
-
# Input YYYY-mm-dd
|
82
|
-
# TODO: Optimize this
|
83
|
-
|
84
|
-
def self.parse_date(str)
|
85
|
-
return nil unless str
|
86
|
-
return Date.strptime(str)
|
87
|
-
end
|
88
|
-
|
89
|
-
# Return an sql string evaluator for the property.
|
90
|
-
# No need to optimize this, used only to precalculate code.
|
91
|
-
# YAML is used to store general Ruby objects to be more
|
92
|
-
# portable.
|
93
|
-
#
|
94
|
-
# FIXME: add extra handling for float.
|
95
|
-
|
96
|
-
def self.write_prop(p)
|
97
|
-
if p.klass.ancestors.include?(Integer)
|
98
|
-
return "#\{@#{p.symbol} || 'NULL'\}"
|
99
|
-
elsif p.klass.ancestors.include?(Float)
|
100
|
-
return "#\{@#{p.symbol} || 'NULL'\}"
|
101
|
-
elsif p.klass.ancestors.include?(String)
|
102
|
-
return "'#\{Og::MysqlBackend.escape(@#{p.symbol})\}'"
|
103
|
-
elsif p.klass.ancestors.include?(Time)
|
104
|
-
return %|#\{@#{p.symbol} ? "'#\{Og::MysqlBackend.timestamp(@#{p.symbol})\}'" : 'NULL'\}|
|
105
|
-
elsif p.klass.ancestors.include?(Date)
|
106
|
-
return %|#\{@#{p.symbol} ? "'#\{Og::MysqlBackend.date(@#{p.symbol})\}'" : 'NULL'\}|
|
107
|
-
elsif p.klass.ancestors.include?(TrueClass)
|
108
|
-
return "#\{@#{p.symbol} ? 1 : 0 \}"
|
109
|
-
else
|
110
|
-
return %|#\{@#{p.symbol} ? "'#\{Og::MysqlBackend.escape(@#{p.symbol}.to_yaml)\}'" : "''"\}|
|
111
|
-
end
|
112
|
-
end
|
113
|
-
|
114
|
-
# Return an evaluator for reading the property.
|
115
|
-
# No need to optimize this, used only to precalculate code.
|
116
|
-
|
117
|
-
def self.read_prop(p, idx)
|
118
|
-
if p.klass.ancestors.include?(Integer)
|
119
|
-
return "res[#{idx}].to_i()"
|
120
|
-
elsif p.klass.ancestors.include?(Float)
|
121
|
-
return "res[#{idx}].to_f()"
|
122
|
-
elsif p.klass.ancestors.include?(String)
|
123
|
-
return "res[#{idx}]"
|
124
|
-
elsif p.klass.ancestors.include?(Time)
|
125
|
-
return "Og::MysqlBackend.parse_timestamp(res[#{idx}])"
|
126
|
-
elsif p.klass.ancestors.include?(Date)
|
127
|
-
return "Og::MysqlBackend.parse_date(res[#{idx}])"
|
128
|
-
elsif p.klass.ancestors.include?(TrueClass)
|
129
|
-
return "('0' != res[#{idx}])"
|
130
|
-
else
|
131
|
-
return "YAML::load(res[#{idx}])"
|
132
|
-
end
|
133
|
-
end
|
134
|
-
|
135
|
-
# Returns the props that will be included in the insert query.
|
136
|
-
# The oid property is rejected because it is mapped to an
|
137
|
-
# AUTO_INCREMENT column.
|
138
|
-
|
139
|
-
def self.props_for_insert(klass)
|
140
|
-
klass.__props.reject { |p| :oid == p.symbol }
|
141
|
-
end
|
142
|
-
|
143
|
-
# Returns the code that actually inserts the object into the
|
144
|
-
# database. Returns the code as String.
|
145
|
-
|
146
|
-
def self.insert_code(klass, sql, pre_cb, post_cb)
|
147
|
-
%{
|
148
|
-
#{pre_cb}
|
149
|
-
conn.exec "#{sql}"
|
150
|
-
@oid = conn.db.conn.insert_id()
|
151
|
-
#{post_cb}
|
152
|
-
}
|
153
|
-
end
|
154
|
-
|
155
|
-
# generate the mapping of the database fields to the
|
156
|
-
# object properties.
|
157
|
-
|
158
|
-
def self.calc_field_index(klass, og)
|
159
|
-
res = og.query "SELECT * FROM #{klass::DBTABLE} LIMIT 1"
|
160
|
-
meta = og.managed_classes[klass]
|
161
|
-
|
162
|
-
for idx in (0...res.num_fields)
|
163
|
-
meta.field_index[res.fetch_field.name] = idx
|
164
|
-
end
|
165
|
-
end
|
166
|
-
|
167
|
-
# Generate the property for oid.
|
168
|
-
|
169
|
-
def self.eval_og_oid(klass)
|
170
|
-
klass.class_eval %{
|
171
|
-
prop_accessor :oid, Fixnum, :sql => "integer AUTO_INCREMENT PRIMARY KEY"
|
172
|
-
}
|
173
|
-
end
|
174
|
-
|
175
|
-
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
176
|
-
# Connection methods.
|
177
|
-
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
178
|
-
|
179
|
-
# Create the database.
|
180
|
-
|
181
|
-
def self.create_db(database, user = nil, password = nil)
|
182
|
-
Logger.info "Creating database '#{database}'."
|
183
|
-
`mysqladmin -f --user=#{user} --password=#{password} create #{database}`
|
184
|
-
end
|
185
|
-
|
186
|
-
# Drop the database.
|
187
|
-
|
188
|
-
def self.drop_db(database, user = nil, password = nil)
|
189
|
-
Logger.info "Dropping database '#{database}'."
|
190
|
-
`mysqladmin -f --user=#{user} --password=#{password} drop #{database}`
|
191
|
-
end
|
192
|
-
|
193
|
-
# Execute an SQL query and return the result
|
194
|
-
|
195
|
-
def query(sql)
|
196
|
-
Logger.debug sql if $DBG
|
197
|
-
return @conn.query(sql)
|
198
|
-
end
|
199
|
-
|
200
|
-
# Execute an SQL query, no result returned.
|
201
|
-
|
202
|
-
def exec(sql)
|
203
|
-
Logger.debug sql if $DBG
|
204
|
-
@conn.query(sql)
|
205
|
-
end
|
206
|
-
|
207
|
-
# Execute an SQL query and return the result. Wrapped in a rescue
|
208
|
-
# block.
|
209
|
-
|
210
|
-
def safe_query(sql)
|
211
|
-
Logger.debug sql if $DBG
|
212
|
-
begin
|
213
|
-
return @conn.query(sql)
|
214
|
-
rescue => ex
|
215
|
-
Logger.error "DB error #{ex}, [#{sql}]"
|
216
|
-
Logger.error ex.backtrace
|
217
|
-
return nil
|
218
|
-
end
|
219
|
-
end
|
220
|
-
|
221
|
-
# Execute an SQL query, no result returned. Wrapped in a rescue
|
222
|
-
# block.
|
223
|
-
|
224
|
-
def safe_exec(sql)
|
225
|
-
Logger.debug sql if $DBG
|
226
|
-
begin
|
227
|
-
@conn.query(sql)
|
228
|
-
rescue => ex
|
229
|
-
Logger.error "DB error #{ex}, [#{sql}]"
|
230
|
-
Logger.error ex.backtrace
|
231
|
-
end
|
232
|
-
end
|
233
|
-
|
234
|
-
# Check if it is a valid resultset.
|
235
|
-
|
236
|
-
def valid?(res)
|
237
|
-
return !(res.nil? or 0 == res.num_rows)
|
238
|
-
end
|
239
|
-
|
240
|
-
# Start a new transaction.
|
241
|
-
|
242
|
-
def start
|
243
|
-
# no transaction support
|
244
|
-
end
|
245
|
-
|
246
|
-
# Commit a transaction.
|
247
|
-
|
248
|
-
def commit
|
249
|
-
# no transaction support
|
250
|
-
end
|
251
|
-
|
252
|
-
# Rollback transaction.
|
253
|
-
|
254
|
-
def rollback
|
255
|
-
# no transaction support
|
256
|
-
end
|
257
|
-
|
258
|
-
# Create the managed object table. The properties of the
|
259
|
-
# object are mapped to the table columns. Additional sql relations
|
260
|
-
# and constrains are created (indicices, sequences, etc).
|
261
|
-
|
262
|
-
def create_table(klass)
|
263
|
-
fields = create_fields(klass, TYPEMAP)
|
264
|
-
|
265
|
-
sql = "CREATE TABLE #{klass::DBTABLE} (#{fields.join(', ')}"
|
266
|
-
|
267
|
-
# Create table constrains
|
268
|
-
|
269
|
-
if klass.__meta and constrains = klass.__meta[:sql_constrain]
|
270
|
-
sql << ", #{constrains.join(', ')}"
|
271
|
-
end
|
272
|
-
|
273
|
-
sql << ');'
|
274
|
-
|
275
|
-
begin
|
276
|
-
exec(sql)
|
277
|
-
Logger.info "Created table '#{klass::DBTABLE}'."
|
278
|
-
rescue => ex
|
279
|
-
if ex.errno == 1050 # table already exists.
|
280
|
-
Logger.debug "Table already exists" if $DBG
|
281
|
-
else
|
282
|
-
raise
|
283
|
-
end
|
284
|
-
end
|
285
|
-
|
286
|
-
# Create indices
|
287
|
-
|
288
|
-
if klass.__meta and indices = klass.__meta[:sql_index]
|
289
|
-
for data in indices
|
290
|
-
idx, options = *data
|
291
|
-
idx = idx.to_s
|
292
|
-
pre_sql, post_sql = options[:pre], options[:post]
|
293
|
-
idxname = idx.gsub(/ /, "").gsub(/,/, "_").gsub(/\(.*\)/, "")
|
294
|
-
exec "CREATE #{pre_sql} INDEX #{klass::DBTABLE}_#{idxname}_idx #{post_sql} ON #{klass::DBTABLE} (#{idx})"
|
295
|
-
end
|
296
|
-
end
|
297
|
-
|
298
|
-
# Create join tables if needed. Join tables are used in
|
299
|
-
# 'many_to_many' relations.
|
300
|
-
|
301
|
-
if klass.__meta and joins = klass.__meta[:sql_join]
|
302
|
-
for data in joins
|
303
|
-
# the class to join to and some options.
|
304
|
-
join_class, options = *data
|
305
|
-
|
306
|
-
# gmosx: dont use DBTABLE here, perhaps the join class
|
307
|
-
# is not managed yet.
|
308
|
-
join_table = "#{self.class.join_table(klass, join_class)}"
|
309
|
-
join_src = "#{self.class.encode(klass)}_oid"
|
310
|
-
join_dst = "#{self.class.encode(join_class)}_oid"
|
311
|
-
begin
|
312
|
-
exec "CREATE TABLE #{join_table} ( key1 integer NOT NULL, key2 integer NOT NULL )"
|
313
|
-
exec "CREATE INDEX #{join_table}_key1_idx ON #{join_table} (key1)"
|
314
|
-
exec "CREATE INDEX #{join_table}_key2_idx ON #{join_table} (key2)"
|
315
|
-
rescue => ex
|
316
|
-
if ex.errno == 1050 # table already exists.
|
317
|
-
Logger.debug "Join table already exists" if $DBG
|
318
|
-
else
|
319
|
-
raise
|
320
|
-
end
|
321
|
-
end
|
322
|
-
end
|
323
|
-
end
|
324
|
-
end
|
325
|
-
|
326
|
-
# Deserialize one row of the resultset.
|
327
|
-
|
328
|
-
def deserialize_one(res, klass)
|
329
|
-
return nil unless valid?(res)
|
330
|
-
|
331
|
-
# gmosx: Managed objects should have no params constructor.
|
332
|
-
row = res.fetch_row()
|
333
|
-
entity = klass.new()
|
334
|
-
entity.og_deserialize(row)
|
335
|
-
|
336
|
-
# get_join_fields(res, 0, entity, join_fields) if join_fields
|
337
|
-
|
338
|
-
return entity
|
339
|
-
end
|
340
|
-
|
341
|
-
# Deserialize all rows of the resultset.
|
342
|
-
|
343
|
-
def deserialize_all(res, klass)
|
344
|
-
return [] unless valid?(res)
|
345
|
-
|
346
|
-
entities = []
|
347
|
-
|
348
|
-
for tuple in (0...res.num_rows)
|
349
|
-
row = res.fetch_row()
|
350
|
-
|
351
|
-
entity = klass.new()
|
352
|
-
entity.og_deserialize(row)
|
353
|
-
|
354
|
-
# get_join_fields(res, tuple, entity, join_fields) if join_fields
|
355
|
-
|
356
|
-
entities << entity
|
357
|
-
end
|
358
|
-
|
359
|
-
return entities
|
360
|
-
end
|
361
|
-
|
362
|
-
# Return a single integer value from the resultset.
|
363
|
-
|
364
|
-
def get_int(res, idx = 0)
|
365
|
-
return res.fetch_row[idx].to_i
|
366
|
-
end
|
367
|
-
|
368
|
-
end
|
369
|
-
|
370
|
-
end
|