og 0.20.0 → 0.21.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 +796 -664
- data/INSTALL +24 -24
- data/README +39 -32
- data/Rakefile +41 -42
- data/benchmark/bench.rb +36 -36
- data/doc/AUTHORS +15 -12
- data/doc/LICENSE +3 -3
- data/doc/RELEASES +311 -243
- data/doc/config.txt +1 -1
- data/examples/mysql_to_psql.rb +15 -15
- data/examples/run.rb +92 -92
- data/install.rb +7 -17
- data/lib/og.rb +76 -75
- data/lib/og/collection.rb +203 -160
- data/lib/og/entity.rb +168 -169
- data/lib/og/errors.rb +5 -5
- data/lib/og/manager.rb +179 -178
- data/lib/og/mixin/hierarchical.rb +107 -107
- data/lib/og/mixin/optimistic_locking.rb +36 -36
- data/lib/og/mixin/orderable.rb +148 -148
- data/lib/og/mixin/timestamped.rb +8 -8
- data/lib/og/mixin/tree.rb +124 -124
- data/lib/og/relation.rb +237 -213
- data/lib/og/relation/belongs_to.rb +5 -5
- data/lib/og/relation/has_many.rb +60 -58
- data/lib/og/relation/joins_many.rb +93 -47
- data/lib/og/relation/refers_to.rb +25 -21
- data/lib/og/store.rb +210 -207
- data/lib/og/store/filesys.rb +79 -79
- data/lib/og/store/kirby.rb +263 -258
- data/lib/og/store/memory.rb +261 -261
- data/lib/og/store/mysql.rb +288 -284
- data/lib/og/store/psql.rb +261 -244
- data/lib/og/store/sql.rb +873 -720
- data/lib/og/store/sqlite.rb +177 -175
- data/lib/og/store/sqlserver.rb +204 -214
- data/lib/og/types.rb +1 -1
- data/lib/og/validation.rb +57 -57
- data/lib/vendor/mysql.rb +376 -376
- data/lib/vendor/mysql411.rb +10 -10
- data/test/og/mixin/tc_hierarchical.rb +59 -59
- data/test/og/mixin/tc_optimistic_locking.rb +40 -40
- data/test/og/mixin/tc_orderable.rb +67 -67
- data/test/og/mixin/tc_timestamped.rb +19 -19
- data/test/og/store/tc_filesys.rb +46 -46
- data/test/og/tc_inheritance.rb +81 -81
- data/test/og/tc_join.rb +67 -0
- data/test/og/tc_polymorphic.rb +49 -49
- data/test/og/tc_relation.rb +57 -30
- data/test/og/tc_select.rb +49 -0
- data/test/og/tc_store.rb +345 -337
- data/test/og/tc_types.rb +11 -11
- metadata +11 -18
data/lib/og/store/sqlite.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
begin
|
2
|
-
|
2
|
+
require 'sqlite3'
|
3
3
|
rescue Object => ex
|
4
|
-
|
5
|
-
|
4
|
+
Logger.error 'Ruby-Sqlite3 bindings are not installed!'
|
5
|
+
Logger.error ex
|
6
6
|
end
|
7
7
|
|
8
8
|
require 'fileutils'
|
@@ -13,19 +13,21 @@ require 'og/store/sql'
|
|
13
13
|
# more compatible with Og.
|
14
14
|
|
15
15
|
class SQLite3::ResultSet
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
16
|
+
alias_method :blank?, :eof?
|
17
|
+
|
18
|
+
def each_row
|
19
|
+
each do |row|
|
20
|
+
yield(row, 0)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def first_value
|
25
|
+
val = self.next[0]
|
26
|
+
close
|
27
|
+
return val
|
28
|
+
end
|
29
|
+
|
30
|
+
alias_method :fields, :columns
|
29
31
|
end
|
30
32
|
|
31
33
|
module Og
|
@@ -36,171 +38,171 @@ module Og
|
|
36
38
|
|
37
39
|
class SqliteStore < SqlStore
|
38
40
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
41
|
+
# Override if needed.
|
42
|
+
|
43
|
+
def self.db_filename(options)
|
44
|
+
"#{options[:name]}.db"
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.destroy(options)
|
48
|
+
begin
|
49
|
+
FileUtils.rm(db_filename(options))
|
50
|
+
super
|
51
|
+
rescue Object
|
52
|
+
Logger.info "Cannot drop '#{options[:name]}'!"
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def initialize(options)
|
57
|
+
super
|
58
|
+
@conn = SQLite3::Database.new(self.class.db_filename(options))
|
59
|
+
end
|
60
|
+
|
61
|
+
def close
|
62
|
+
@conn.close
|
63
|
+
super
|
64
|
+
end
|
65
|
+
|
66
|
+
def enchant(klass, manager)
|
67
|
+
klass.property :oid, Fixnum, :sql => 'integer PRIMARY KEY'
|
68
|
+
super
|
69
|
+
end
|
70
|
+
|
71
|
+
def query(sql)
|
72
|
+
Logger.debug sql if $DBG
|
73
|
+
return @conn.query(sql)
|
74
|
+
rescue => ex
|
75
|
+
handle_sql_exception(ex, sql)
|
76
|
+
end
|
77
|
+
|
78
|
+
def exec(sql)
|
79
|
+
Logger.debug sql if $DBG
|
80
|
+
@conn.query(sql).close
|
81
|
+
rescue => ex
|
82
|
+
handle_sql_exception(ex, sql)
|
83
|
+
end
|
84
|
+
|
85
|
+
def start
|
86
|
+
@conn.transaction if @transaction_nesting < 1
|
87
|
+
@transaction_nesting += 1
|
88
|
+
end
|
89
|
+
|
90
|
+
def commit
|
91
|
+
@transaction_nesting -= 1
|
92
|
+
@conn.commit if @transaction_nesting < 1
|
93
|
+
end
|
94
|
+
|
95
|
+
def rollback
|
96
|
+
@transaction_nesting -= 1
|
97
|
+
@conn.rollback if @transaction_nesting < 1
|
98
|
+
end
|
97
99
|
|
98
100
|
def last_insert_rowid
|
99
|
-
|
100
|
-
|
101
|
+
conn.query("SELECT last_insert_rowid()").first_value.to_i
|
102
|
+
end
|
101
103
|
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
104
|
+
def sql_update(sql)
|
105
|
+
exec(sql)
|
106
|
+
@conn.changes
|
107
|
+
end
|
106
108
|
|
107
109
|
private
|
108
110
|
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
111
|
+
def create_table(klass)
|
112
|
+
fields = fields_for_class(klass)
|
113
|
+
|
114
|
+
sql = "CREATE TABLE #{klass::OGTABLE} (#{fields.join(', ')}"
|
115
|
+
|
116
|
+
# Create table constrains.
|
117
|
+
|
118
|
+
if klass.__meta and constrains = klass.__meta[:sql_constrain]
|
119
|
+
sql << ", #{constrains.join(', ')}"
|
120
|
+
end
|
121
|
+
|
122
|
+
sql << ");"
|
123
|
+
|
124
|
+
# Create indices.
|
125
|
+
|
126
|
+
if klass.__meta and indices = klass.__meta[:index]
|
127
|
+
for data in indices
|
128
|
+
idx, options = *data
|
129
|
+
idx = idx.to_s
|
130
|
+
pre_sql, post_sql = options[:pre], options[:post]
|
131
|
+
idxname = idx.gsub(/ /, "").gsub(/,/, "_").gsub(/\(.*\)/, "")
|
132
|
+
sql << " CREATE #{pre_sql} INDEX #{klass::OGTABLE}_#{idxname}_idx #{post_sql} ON #{klass::OGTABLE} (#{idx});"
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
begin
|
137
|
+
@conn.query(sql).close
|
138
|
+
Logger.info "Created table '#{klass::OGTABLE}'."
|
139
|
+
rescue Object => ex
|
140
|
+
# gmosx: any idea how to better test this?
|
141
|
+
if ex.to_s =~ /table .* already exists/i
|
142
|
+
Logger.debug 'Table already exists' if $DBG
|
143
|
+
return
|
144
|
+
else
|
145
|
+
raise
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
# Create join tables if needed. Join tables are used in
|
150
|
+
# 'many_to_many' relations.
|
151
|
+
|
152
|
+
if klass.__meta and join_tables = klass.__meta[:join_tables]
|
153
|
+
for info in join_tables
|
154
|
+
begin
|
155
|
+
create_join_table_sql(info).each do |sql|
|
156
|
+
@conn.query(sql).close
|
157
|
+
end
|
158
|
+
rescue Object => ex
|
159
|
+
# gmosx: any idea how to better test this?
|
160
|
+
if ex.to_s =~ /table .* already exists/i
|
161
|
+
Logger.debug 'Join table already exists' if $DBG
|
162
|
+
else
|
163
|
+
raise
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
def create_field_map(klass)
|
171
|
+
res = @conn.query "SELECT * FROM #{klass::OGTABLE} LIMIT 1"
|
172
|
+
map = {}
|
173
|
+
|
174
|
+
fields = res.columns
|
175
|
+
|
176
|
+
res.fields.size.times do |i|
|
177
|
+
map[fields[i].intern] = i
|
178
|
+
end
|
179
|
+
|
180
|
+
return map
|
181
|
+
ensure
|
182
|
+
res.close if res
|
183
|
+
end
|
184
|
+
|
185
|
+
def eval_og_insert(klass)
|
186
|
+
pk = klass.primary_key.first
|
187
|
+
props = klass.properties
|
188
|
+
values = props.collect { |p| write_prop(p) }.join(',')
|
189
|
+
|
190
|
+
if klass.metadata.superclass or klass.metadata.subclasses
|
191
|
+
props << Property.new(:ogtype, String)
|
192
|
+
values << ", '#{klass}'"
|
193
|
+
end
|
194
|
+
|
195
|
+
sql = "INSERT INTO #{klass::OGTABLE} (#{props.collect {|p| p.symbol.to_s}.join(',')}) VALUES (#{values})"
|
196
|
+
|
197
|
+
klass.class_eval %{
|
198
|
+
def og_insert(store)
|
199
|
+
#{Aspects.gen_advice_code(:og_insert, klass.advices, :pre) if klass.respond_to?(:advices)}
|
200
|
+
store.query("#{sql}").close
|
201
|
+
@#{pk} = store.last_insert_rowid
|
202
|
+
#{Aspects.gen_advice_code(:og_insert, klass.advices, :post) if klass.respond_to?(:advices)}
|
203
|
+
end
|
204
|
+
}
|
205
|
+
end
|
204
206
|
|
205
207
|
end
|
206
208
|
|
data/lib/og/store/sqlserver.rb
CHANGED
@@ -3,10 +3,10 @@
|
|
3
3
|
# DO NOT USE YET!
|
4
4
|
|
5
5
|
begin
|
6
|
-
|
6
|
+
require 'dbi'
|
7
7
|
rescue Object => ex
|
8
|
-
|
9
|
-
|
8
|
+
Logger.error 'Ruby-DBI bindings not present or ADO support not available.'
|
9
|
+
Logger.error ex
|
10
10
|
end
|
11
11
|
|
12
12
|
require 'og/store/sql'
|
@@ -15,55 +15,55 @@ require 'og/store/sql'
|
|
15
15
|
# more compatible with Og.
|
16
16
|
=begin
|
17
17
|
class Sqlserver::Result
|
18
|
-
|
19
|
-
|
20
|
-
|
18
|
+
def blank?
|
19
|
+
0 == num_rows
|
20
|
+
end
|
21
21
|
|
22
|
-
|
22
|
+
alias_method :next, :fetch_row
|
23
23
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
24
|
+
def each_row
|
25
|
+
each do |row|
|
26
|
+
yield(row, 0)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def first_value
|
31
|
+
val = fetch_row[0]
|
32
|
+
free
|
33
|
+
return val
|
34
|
+
end
|
35
|
+
|
36
|
+
alias_method :close, :free
|
37
37
|
end
|
38
38
|
=end
|
39
39
|
|
40
40
|
module Og
|
41
41
|
|
42
42
|
module SqlserverUtils
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
43
|
+
include SqlUtils
|
44
|
+
|
45
|
+
def escape(str)
|
46
|
+
return nil unless str
|
47
|
+
return Sqlserver.quote(str)
|
48
|
+
end
|
49
|
+
|
50
|
+
def quote(val)
|
51
|
+
case val
|
52
|
+
when Fixnum, Integer, Float
|
53
|
+
val ? val.to_s : 'NULL'
|
54
|
+
when String
|
55
|
+
val ? "'#{escape(val)}'" : 'NULL'
|
56
|
+
when Time
|
57
|
+
val ? "'#{timestamp(val)}'" : 'NULL'
|
58
|
+
when Date
|
59
|
+
val ? "'#{date(val)}'" : 'NULL'
|
60
|
+
when TrueClass
|
61
|
+
val ? "'1'" : 'NULL'
|
62
|
+
else
|
63
|
+
# gmosx: keep the '' for nil symbols.
|
64
|
+
val ? escape(val.to_yaml) : ''
|
65
|
+
end
|
66
|
+
end
|
67
67
|
end
|
68
68
|
|
69
69
|
# A Store that persists objects into a Sqlserver database.
|
@@ -71,195 +71,185 @@ end
|
|
71
71
|
# for SqlStore and Store.
|
72
72
|
|
73
73
|
class SqlserverStore < SqlStore
|
74
|
-
|
75
|
-
|
74
|
+
extend SqlserverUtils
|
75
|
+
include SqlserverUtils
|
76
76
|
|
77
|
-
|
78
|
-
|
79
|
-
|
77
|
+
def self.create(options)
|
78
|
+
raise 'Not implemented'
|
79
|
+
end
|
80
80
|
|
81
|
-
|
82
|
-
|
83
|
-
|
81
|
+
def self.destroy(options)
|
82
|
+
raise 'Not implemented'
|
83
|
+
end
|
84
84
|
|
85
|
-
|
86
|
-
|
85
|
+
def initialize(options)
|
86
|
+
super
|
87
87
|
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
88
|
+
begin
|
89
|
+
@conn = DBI.connect("DBI:ADO:Provider=SQLOLEDB;Data Source=#{options[:address]};Initial Catalog=#{options[:name]};User Id=#{options[:user]};Password=#{options[:password]};")
|
90
|
+
rescue => ex
|
91
|
+
# gmosx, FIXME: drak, fix this!
|
92
|
+
if ex.to_s =~ /database .* does not exist/i
|
93
|
+
Logger.info "Database '#{options[:name]}' not found!"
|
94
|
+
self.class.create(options)
|
95
|
+
retry
|
96
|
+
end
|
97
|
+
raise
|
98
|
+
end
|
99
|
+
end
|
100
100
|
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
101
|
+
def close
|
102
|
+
@conn.disconnect
|
103
|
+
super
|
104
|
+
end
|
105
105
|
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
#
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
106
|
+
def enchant(klass, manager)
|
107
|
+
klass.property :oid, Fixnum, :sql => 'integer AUTO_INCREMENT PRIMARY KEY'
|
108
|
+
super
|
109
|
+
end
|
110
|
+
|
111
|
+
def query(sql)
|
112
|
+
# Logger.debug sql if $DBG
|
113
|
+
return @conn.select_all(sql)
|
114
|
+
rescue => ex
|
115
|
+
handle_sql_exception(ex, sql)
|
116
|
+
end
|
117
117
|
|
118
|
-
|
119
|
-
#
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
118
|
+
def exec(sql)
|
119
|
+
# Logger.debug sql if $DBG
|
120
|
+
@conn.execute(sql).finish
|
121
|
+
rescue => ex
|
122
|
+
handle_sql_exception(ex, sql)
|
123
|
+
end
|
124
124
|
|
125
125
|
private
|
126
126
|
|
127
|
-
|
128
|
-
|
127
|
+
def create_table(klass)
|
128
|
+
fields = fields_for_class(klass)
|
129
129
|
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
130
|
+
sql = "CREATE TABLE #{klass::OGTABLE} (#{fields.join(', ')}"
|
131
|
+
|
132
|
+
# Create table constrains.
|
133
|
+
|
134
|
+
if klass.__meta and constrains = klass.__meta[:sql_constrain]
|
135
|
+
sql << ", #{constrains.join(', ')}"
|
136
|
+
end
|
137
|
+
|
138
|
+
sql << ");"
|
139
|
+
|
140
|
+
# Create indices.
|
141
|
+
|
142
|
+
if klass.__meta and indices = klass.__meta[:index]
|
143
|
+
for data in indices
|
144
|
+
idx, options = *data
|
145
|
+
idx = idx.to_s
|
146
|
+
pre_sql, post_sql = options[:pre], options[:post]
|
147
|
+
idxname = idx.gsub(/ /, "").gsub(/,/, "_").gsub(/\(.*\)/, "")
|
148
|
+
sql << " CREATE #{pre_sql} INDEX #{klass::OGTABLE}_#{idxname}_idx #{post_sql} ON #{klass::OGTABLE} (#{idx});"
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
conn.query_with_result = false
|
153
153
|
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
=begin
|
167
|
-
# Create join tables if needed. Join tables are used in
|
168
|
-
# 'many_to_many' relations.
|
169
|
-
|
170
|
-
if klass.__meta and joins = klass.__meta[:sql_join]
|
171
|
-
for data in joins
|
172
|
-
# the class to join to and some options.
|
173
|
-
join_name, join_class, options = *data
|
174
|
-
|
175
|
-
join_table = "#{self.class.join_table(klass, join_class, join_name)}"
|
176
|
-
join_src = "#{self.class.encode(klass)}_oid"
|
177
|
-
join_dst = "#{self.class.encode(join_class)}_oid"
|
154
|
+
begin
|
155
|
+
conn.query(sql)
|
156
|
+
Logger.info "Created table '#{klass::OGTABLE}'."
|
157
|
+
rescue => ex
|
158
|
+
# gmosx: any idea how to better test this?
|
159
|
+
if ex.errno == 1050 # table already exists.
|
160
|
+
Logger.debug 'Table already exists' if $DBG
|
161
|
+
return
|
162
|
+
else
|
163
|
+
raise
|
164
|
+
end
|
165
|
+
end
|
178
166
|
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
167
|
+
# Create join tables if needed. Join tables are used in
|
168
|
+
# 'many_to_many' relations.
|
169
|
+
|
170
|
+
if klass.__meta and join_tables = klass.__meta[:join_tables]
|
171
|
+
for join_table in join_tables
|
172
|
+
begin
|
173
|
+
conn.query(create_join_table_sql(join_table))
|
174
|
+
rescue => ex
|
175
|
+
# gmosx: any idea how to better test this?
|
176
|
+
if ex.errno == 1050 # table already exists.
|
177
|
+
Logger.debug 'Join table already exists'
|
178
|
+
else
|
179
|
+
raise
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
195
185
|
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
186
|
+
def create_field_map(klass)
|
187
|
+
conn.query_with_result = true
|
188
|
+
res = @conn.query "SELECT * FROM #{klass::OGTABLE} LIMIT 1"
|
189
|
+
map = {}
|
200
190
|
|
201
|
-
|
202
|
-
|
203
|
-
|
191
|
+
res.num_fields.times do |i|
|
192
|
+
map[res.fetch_field.name.intern] = i
|
193
|
+
end
|
204
194
|
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
195
|
+
return map
|
196
|
+
ensure
|
197
|
+
res.close if res
|
198
|
+
end
|
209
199
|
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
200
|
+
def write_prop(p)
|
201
|
+
if p.klass.ancestors.include?(Integer)
|
202
|
+
return "#\{@#{p.symbol} || 'NULL'\}"
|
203
|
+
elsif p.klass.ancestors.include?(Float)
|
204
|
+
return "#\{@#{p.symbol} || 'NULL'\}"
|
205
|
+
elsif p.klass.ancestors.include?(String)
|
206
|
+
return %|#\{@#{p.symbol} ? "'#\{#{self.class}.escape(@#{p.symbol})\}'" : 'NULL'\}|
|
207
|
+
elsif p.klass.ancestors.include?(Time)
|
208
|
+
return %|#\{@#{p.symbol} ? "'#\{#{self.class}.timestamp(@#{p.symbol})\}'" : 'NULL'\}|
|
209
|
+
elsif p.klass.ancestors.include?(Date)
|
210
|
+
return %|#\{@#{p.symbol} ? "'#\{#{self.class}.date(@#{p.symbol})\}'" : 'NULL'\}|
|
211
|
+
elsif p.klass.ancestors.include?(TrueClass)
|
212
|
+
return "#\{@#{p.symbol} ? \"'1'\" : 'NULL' \}"
|
213
|
+
else
|
214
|
+
# gmosx: keep the '' for nil symbols.
|
215
|
+
return %|#\{@#{p.symbol} ? "'#\{#{self.class}.escape(@#{p.symbol}.to_yaml)\}'" : "''"\}|
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
def read_prop(p, col)
|
220
|
+
if p.klass.ancestors.include?(Integer)
|
221
|
+
return "res[#{col} + offset].to_i"
|
222
|
+
elsif p.klass.ancestors.include?(Float)
|
223
|
+
return "res[#{col} + offset].to_f"
|
224
|
+
elsif p.klass.ancestors.include?(String)
|
225
|
+
return "res[#{col} + offset]"
|
226
|
+
elsif p.klass.ancestors.include?(Time)
|
227
|
+
return "#{self.class}.parse_timestamp(res[#{col} + offset])"
|
228
|
+
elsif p.klass.ancestors.include?(Date)
|
229
|
+
return "#{self.class}.parse_date(res[#{col} + offset])"
|
230
|
+
elsif p.klass.ancestors.include?(TrueClass)
|
231
|
+
return "('0' != res[#{col} + offset])"
|
232
|
+
else
|
233
|
+
return "YAML.load(res[#{col} + offset])"
|
234
|
+
end
|
235
|
+
end
|
246
236
|
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
237
|
+
def eval_og_insert(klass)
|
238
|
+
props = klass.properties
|
239
|
+
values = props.collect { |p| write_prop(p) }.join(',')
|
240
|
+
|
241
|
+
sql = "INSERT INTO #{klass::OGTABLE} (#{props.collect {|p| p.symbol.to_s}.join(',')}) VALUES (#{values})"
|
252
242
|
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
243
|
+
klass.class_eval %{
|
244
|
+
def og_insert(store)
|
245
|
+
#{Aspects.gen_advice_code(:og_insert, klass.advices, :pre) if klass.respond_to?(:advices)}
|
246
|
+
store.conn.query_with_result = false
|
247
|
+
store.conn.query "#{sql}"
|
248
|
+
@#{klass.pk_symbol} = store.conn.insert_id
|
249
|
+
#{Aspects.gen_advice_code(:og_insert, klass.advices, :post) if klass.respond_to?(:advices)}
|
250
|
+
end
|
251
|
+
}
|
252
|
+
end
|
263
253
|
|
264
254
|
end
|
265
255
|
|