og 0.14.0 → 0.15.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 +68 -0
- data/README +16 -7
- data/doc/AUTHORS +3 -6
- data/doc/RELEASES +44 -1
- data/examples/run.rb +1 -1
- data/examples/test.db +0 -0
- data/lib/og.rb +2 -2
- data/lib/og/adapters/oracle.rb +1 -7
- data/lib/og/adapters/sqlserver.rb +360 -0
- data/lib/og/meta.rb +1 -4
- data/lib/og/mixins/hierarchical.rb +134 -0
- data/lib/og/mixins/{list.rb → orderable.rb} +25 -23
- data/lib/og/typemacros.rb +4 -3
- data/test/og/mixins/tc_hierarchical.rb +79 -0
- data/test/og/mixins/{tc_list.rb → tc_orderable.rb} +5 -2
- data/test/og/tc_sqlserver.rb +93 -0
- metadata +10 -7
- data/lib/og/backend.rb +0 -297
- data/test/og/mixins/tc_tree.rb +0 -59
data/CHANGELOG
CHANGED
@@ -1,5 +1,73 @@
|
|
1
|
+
04-04-2005 George Moschovitis <gm@navel.gr>
|
2
|
+
|
3
|
+
* examples/run.rb: small fix.
|
4
|
+
|
5
|
+
* test/og/mixins/tc_tree.rb: removed.
|
6
|
+
|
7
|
+
* test/og/mixins/tc_list.rb: removed.
|
8
|
+
|
9
|
+
03-04-2005 George Moschovitis <gm@navel.gr>
|
10
|
+
|
11
|
+
* doc/RELEASES: updated.
|
12
|
+
|
13
|
+
* lib/og/backend.rb: removed.
|
14
|
+
|
15
|
+
* test/og/mixins/tc_hierarchical: implemented,
|
16
|
+
dont use article.
|
17
|
+
|
18
|
+
* lib/og/mixins/orderable.rb: fixed 1=1 scope.
|
19
|
+
|
20
|
+
* lib/og/mixins/hierarchical.rb (Hierarchical): implemented,
|
21
|
+
(#add_child): implemented.
|
22
|
+
after some fixes, it works!!
|
23
|
+
fixed 1=1 scope.
|
24
|
+
added :root.
|
25
|
+
|
26
|
+
02-04-2005 George Moschovitis <gm@navel.gr>
|
27
|
+
|
28
|
+
* lib/og/typemacros.rb: small update.
|
29
|
+
|
30
|
+
* test/og/mixins/tc_hierarchical: introduced.
|
31
|
+
|
32
|
+
* lib/og/mixins/hierarchical.rb: introduced,
|
33
|
+
(Hierarchical): introduced,
|
34
|
+
(NestedSets): introduced,
|
35
|
+
added enchant methods for nested sets.
|
36
|
+
|
37
|
+
* lib/og/mixins/tree.rb: deprecated.
|
38
|
+
|
39
|
+
01-04-2005 George Moschovitis <gm@navel.gr>
|
40
|
+
|
41
|
+
* lib/og/adapters/sqlserver.rb: small fixes.
|
42
|
+
|
43
|
+
* doc/README: updated.
|
44
|
+
|
45
|
+
* doc/RELEASES: updated.
|
46
|
+
|
47
|
+
* doc/AUTHORS: updated.
|
48
|
+
|
49
|
+
01-04-2005 Anastasios Koutoumanos <drak@navel.gr>
|
50
|
+
|
51
|
+
* lib/og/adapters/sqlserver.rb: implemented.
|
52
|
+
|
53
|
+
* test/og/tc_sqlserver.rb: implemented.
|
54
|
+
|
55
|
+
31-03-2005 George Moschovitis <gm@navel.gr>
|
56
|
+
|
57
|
+
* lib/og/mixins/orderable.rb: implemented using dynamic_include.
|
58
|
+
|
59
|
+
* lib/og/meta.rb: removed inclusion of Og::List.
|
60
|
+
|
61
|
+
* lib/og/mixins/list.rb: deprecated in favour of the superior implementation.
|
62
|
+
|
63
|
+
31-03-2005 Anastasios Koutoumanos <drak@navel.gr>
|
64
|
+
|
65
|
+
* lib/og/adapters/oracle.rb: removed duplicate eval_og_oid.
|
66
|
+
|
1
67
|
28-03-2005 George Moschovitis <gm@navel.gr>
|
2
68
|
|
69
|
+
* --- VERSION 0.14.0 ---
|
70
|
+
|
3
71
|
* test/og/mixins/tc_list.rb: implemented tests.
|
4
72
|
|
5
73
|
* lib/og/connection.rb (#delete): passs obj_or_oid to the callback.
|
data/README
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
= Og 0.
|
1
|
+
= Og 0.15.0
|
2
2
|
|
3
3
|
Og (ObjectGraph) is a powerfull object-relational mapping library. Og provides
|
4
4
|
transparent serialization of object graphs to a RDBMS
|
@@ -27,10 +27,10 @@ The library provides the following features:
|
|
27
27
|
|
28
28
|
+ Object-Relational mapping.
|
29
29
|
+ Absolutely no configuration files.
|
30
|
-
+ Multiple backend adapters (PostgreSQL, MySQL,
|
30
|
+
+ Multiple backend adapters (PostgreSQL, MySQL, SQLite3, Oracle, SqlServer).
|
31
31
|
+ ActiveRecord-style meta language and db aware methods.
|
32
32
|
+ Automatially generates join-tables for many_to_many relations.
|
33
|
-
+ Deserialize sql join queries to Ruby Objects.
|
33
|
+
+ Deserialize sql join queries to Ruby Objects (coming soon).
|
34
34
|
+ Serialize arbitrary ruby object graphs through YAML.
|
35
35
|
+ Connection pooling.
|
36
36
|
+ Thread safety.
|
@@ -38,18 +38,21 @@ The library provides the following features:
|
|
38
38
|
+ Lifecycle callbacks.
|
39
39
|
+ Lifecycle observers.
|
40
40
|
+ Transparent support for cascading deletes for all backends.
|
41
|
-
+
|
41
|
+
+ Dynamic db related mixins (Orderable, etc).
|
42
|
+
+ Hierarchical structures (nested sets, more coming soon).
|
42
43
|
+ Works safely as part of a distributed application.
|
43
44
|
+ Automatic Validation/Constraints.
|
44
45
|
+ Simple and clean implementation.
|
45
46
|
|
47
|
+
|
46
48
|
== Download
|
47
49
|
|
48
50
|
The latest version of Og can be found at
|
49
51
|
|
50
|
-
* http://
|
52
|
+
* http://nitro.rubyforge.org
|
51
53
|
|
52
|
-
Documentation for Og can be found in the distribution.
|
54
|
+
Documentation for Og can be found in the distribution. You can find
|
55
|
+
a nice tutorial at www.rubygarden.com
|
53
56
|
|
54
57
|
|
55
58
|
== Requirements
|
@@ -88,7 +91,7 @@ installed RubyGems on your system. Then run the following command:
|
|
88
91
|
|
89
92
|
gem install og
|
90
93
|
|
91
|
-
Then try to run the examples
|
94
|
+
Then try to run the examples in the examples directory.
|
92
95
|
|
93
96
|
A tar.gz distribution is also available on http://www.rubyforge.com/projects/nitro.
|
94
97
|
|
@@ -99,6 +102,12 @@ For any questions regarding Og, feel free to ask on the ruby-talk
|
|
99
102
|
mailing list (which is mirrored to comp.lang.ruby) or contact
|
100
103
|
mailto:gm@navel.gr.
|
101
104
|
|
105
|
+
An Og specific mailing list is also available. Please subscribe
|
106
|
+
to nitro-general@rubyforge.com. The homepage for this list
|
107
|
+
is available here:
|
108
|
+
|
109
|
+
http://rubyforge.org/mailman/listinfo/nitro-general
|
110
|
+
|
102
111
|
|
103
112
|
== Licence
|
104
113
|
|
data/doc/AUTHORS
CHANGED
@@ -6,17 +6,14 @@ MAIN DEVELOPER:
|
|
6
6
|
|
7
7
|
IDEAS, ADDITIONAL CODING, SUPPORT:
|
8
8
|
|
9
|
+
* Anastasios Koutoumanos <ak@navel.gr>
|
10
|
+
Design, additional coding.
|
11
|
+
|
9
12
|
* Michael Neumann <mneumann@ntecs.de>
|
10
13
|
Design, additional coding and bug reports.
|
11
14
|
|
12
15
|
* Matt Bowen <matt.bowen@farweststeel.com>
|
13
16
|
Additional code and documentation.
|
14
17
|
|
15
|
-
* Anastasios Koutoumanos <ak@navel.gr>
|
16
|
-
Design, additional coding.
|
17
|
-
|
18
|
-
* Elias Athanasopoulos <elathan@navel.gr>
|
19
|
-
Additional coding.
|
20
|
-
|
21
18
|
* Thomas Quas <tquas@yahoo.com>
|
22
19
|
Ideas, bug reports, unit tests.
|
data/doc/RELEASES
CHANGED
@@ -1,10 +1,53 @@
|
|
1
|
+
== Version 0.15.0 was released on 4/03/2005.
|
2
|
+
|
3
|
+
A great release. Many cool new features and tons of subtle
|
4
|
+
improvements. We also welcome a new core developer, Anastastios
|
5
|
+
Koutoumanos, who started contributing with a new SqlServer adapter.
|
6
|
+
|
7
|
+
Most notable additions:
|
8
|
+
|
9
|
+
* NestedSets mixin:
|
10
|
+
|
11
|
+
class Comment
|
12
|
+
include NestedSets
|
13
|
+
end
|
14
|
+
|
15
|
+
or
|
16
|
+
|
17
|
+
class Comment
|
18
|
+
include Hierarchical, :method => :nested_sets
|
19
|
+
end
|
20
|
+
|
21
|
+
c.add_comment(child_comment)
|
22
|
+
c.full_children
|
23
|
+
c.direct_children
|
24
|
+
c.children
|
25
|
+
|
26
|
+
this is a reimplementation of the SqlTraversable mixin
|
27
|
+
available in older versions.
|
28
|
+
|
29
|
+
* New implementation of Orderable mixin:
|
30
|
+
|
31
|
+
class Comment
|
32
|
+
property :body, String
|
33
|
+
belongs_to :article, Article
|
34
|
+
include Orderable, :scope => article
|
35
|
+
end
|
36
|
+
|
37
|
+
c.move_higher
|
38
|
+
|
39
|
+
The Orderable mixin uses the :scope parameter to dynamically alter
|
40
|
+
the methods appended to the Comment class.
|
41
|
+
|
42
|
+
* New SqlServer adapter.
|
43
|
+
|
1
44
|
== Version 0.14.0 was released on 18/03/2005.
|
2
45
|
|
3
46
|
Many many important fixes, and many small additions
|
4
47
|
and improvements. Og mixins are introduced with
|
5
48
|
an experimental List mixin implementation.
|
6
49
|
|
7
|
-
Most notable
|
50
|
+
Most notable additions:
|
8
51
|
|
9
52
|
* Support for objects that participate in list
|
10
53
|
(ordering/removal etc)
|
data/examples/run.rb
CHANGED
@@ -221,7 +221,7 @@ Article.all.each { |a| puts a }
|
|
221
221
|
# The previous command updates the whole object. It is used
|
222
222
|
# when there are many updates or you dont care about speed.
|
223
223
|
# To update only specific fields use pupdate or properties_update
|
224
|
-
a2.pupdate
|
224
|
+
a2.pupdate "title='A specific title'"
|
225
225
|
|
226
226
|
puts "\n\n"
|
227
227
|
Article.all.each { |a| puts a }
|
data/examples/test.db
ADDED
Binary file
|
data/lib/og.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# * George Moschovitis <gm@navel.gr>
|
2
2
|
# (c) 2004-2005 Navel, all rights reserved.
|
3
|
-
# $Id: og.rb
|
3
|
+
# $Id: og.rb 340 2005-04-04 08:26:58Z gmosx $
|
4
4
|
|
5
5
|
require 'glue'
|
6
6
|
require 'glue/logger'
|
@@ -107,7 +107,7 @@ module Og
|
|
107
107
|
|
108
108
|
# The version.
|
109
109
|
|
110
|
-
Version = '0.
|
110
|
+
Version = '0.15.0'
|
111
111
|
|
112
112
|
# Library path.
|
113
113
|
|
data/lib/og/adapters/oracle.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# * Matt Bowen <matt.bowen@farweststeel.com>
|
2
2
|
# * George Moschovitis <gm@navel.gr>
|
3
3
|
# (c) 2004-2005 Navel, all rights reserved.
|
4
|
-
# $Id: oracle.rb
|
4
|
+
# $Id: oracle.rb 337 2005-03-31 16:20:40Z gmosx $
|
5
5
|
|
6
6
|
begin
|
7
7
|
require 'oracle'
|
@@ -123,12 +123,6 @@ class OracleAdapter < Adapter
|
|
123
123
|
res.close if res
|
124
124
|
end
|
125
125
|
|
126
|
-
def eval_og_oid(klass)
|
127
|
-
klass.class_eval %{
|
128
|
-
prop_accessor :oid, Fixnum, :sql => "number PRIMARY KEY"
|
129
|
-
}
|
130
|
-
end
|
131
|
-
|
132
126
|
def create_table(klass, db)
|
133
127
|
conn = db.get_connection
|
134
128
|
|
@@ -0,0 +1,360 @@
|
|
1
|
+
# * Anastasios Koutoumanos <ak@navel.gr>
|
2
|
+
# (c) 2004-2005 Navel, all rights reserved.
|
3
|
+
# $Id: sqlserver.rb 341 2005-04-04 08:28:54Z gmosx $
|
4
|
+
|
5
|
+
begin
|
6
|
+
require 'dbi'
|
7
|
+
rescue Object => ex
|
8
|
+
Logger.error 'Ruby-DBI bindings not present or ADO support not available.'
|
9
|
+
Logger.error ex
|
10
|
+
end
|
11
|
+
|
12
|
+
require 'glue/attribute'
|
13
|
+
require 'og/adapter'
|
14
|
+
require 'og/connection'
|
15
|
+
|
16
|
+
module Og
|
17
|
+
|
18
|
+
# The Microsoft SQL Server Sql Server adapter. This adapter
|
19
|
+
# communicates with a Microsoft SQL Server sql server rdbms.
|
20
|
+
# This adapter will ONLY work on Windows systems, since it
|
21
|
+
# relies on Win32OLE is apparently only available on Windows.
|
22
|
+
# It relies on the ADO support in the DBI module. If you are using the
|
23
|
+
# one-click installer of Ruby, then you already have DBI installed, but
|
24
|
+
# the ADO module is *NOT* installed. You will need to get the latest
|
25
|
+
# source distribution of Ruby-DBI from http://ruby-dbi.sourceforge.net/
|
26
|
+
# unzip it, and copy the file <tt>src/lib/dbd_ado/ADO.rb</tt> to
|
27
|
+
# <tt>X:/Ruby/lib/ruby/site_ruby/1.8/DBD/ADO/ADO.rb</tt>
|
28
|
+
# (you will need to create the ADO directory). Once you've installed
|
29
|
+
# that file, you are ready to go.
|
30
|
+
# Originally based on the sqlserver_adapter.rb -- the ActiveRecord
|
31
|
+
# adapter for Microsoft SQL Server by Joey Gibson and DeLynn Berry.
|
32
|
+
# Information related to the SQL Server datatypes:
|
33
|
+
# http://msdn.microsoft.com/library/default.asp?url=/library/en-us/architec/8_ar_da_4ucz.asp
|
34
|
+
# For extra documentation see lib/og/adapter.rb
|
35
|
+
|
36
|
+
class SqlserverAdapter < Adapter
|
37
|
+
|
38
|
+
def initialize
|
39
|
+
super
|
40
|
+
@typemap.update(
|
41
|
+
Integer => 'int', # drak: maybe smallint?
|
42
|
+
Fixnum => 'int',
|
43
|
+
Float => 'float',
|
44
|
+
String => 'varchar(1024)', # drak: maybe nvarchar for unicode
|
45
|
+
Time => 'datetime', # drak: maybe smalldatime?
|
46
|
+
Date => 'smalldatetime',
|
47
|
+
TrueClass => 'bit'
|
48
|
+
)
|
49
|
+
|
50
|
+
@typecast.update(TrueClass => "#\{:s: ? \'1\' : '0' \}")
|
51
|
+
end
|
52
|
+
|
53
|
+
|
54
|
+
def self.timestamp(time = Time.now)
|
55
|
+
return nil unless time
|
56
|
+
return time.strftime("%Y-%m-%d %H:%M:%S")
|
57
|
+
end
|
58
|
+
|
59
|
+
def self.date(date)
|
60
|
+
return nil unless date
|
61
|
+
return "#{date.year}-#{date.month}-#{date.mday}"
|
62
|
+
end
|
63
|
+
|
64
|
+
def read_prop(p, idx)
|
65
|
+
if p.klass.ancestors.include?(Integer)
|
66
|
+
return "res[tuple][#{idx}].to_i"
|
67
|
+
elsif p.klass.ancestors.include?(Float)
|
68
|
+
return "res[tuple][#{idx}].to_f"
|
69
|
+
elsif p.klass.ancestors.include?(String)
|
70
|
+
return "res[tuple][#{idx}]"
|
71
|
+
elsif p.klass.ancestors.include?(Time)
|
72
|
+
return "#{self.class}.parse_timestamp(res[tuple][#{idx}])"
|
73
|
+
elsif p.klass.ancestors.include?(Date)
|
74
|
+
return "#{self.class}.parse_date(res[tuple][#{idx}])"
|
75
|
+
elsif p.klass.ancestors.include?(TrueClass)
|
76
|
+
return "('0' != res[tuple][#{idx}])"
|
77
|
+
else
|
78
|
+
return "YAML::load(res[tuple][#{idx}])"
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def create_db(database, user = nil, password = nil)
|
83
|
+
raise 'Not implemented!'
|
84
|
+
|
85
|
+
### how can we get a valid connection when the database does not already exist?
|
86
|
+
begin
|
87
|
+
conn = DBI.connect("DBI:ADO:Provider=SQLOLEDB;Data Source=localhost;Initial Catalog=master;User Id=sa;Password=sa;")
|
88
|
+
conn["AutoCommit"] = true
|
89
|
+
conn.execute("CREATE DATABASE #{database}")
|
90
|
+
conn.commit
|
91
|
+
Logger.warn "Ignoring credentials for database creation (not implemented)" if user
|
92
|
+
Logger.info "Created database '#{database}'."
|
93
|
+
super
|
94
|
+
rescue Exception => ex
|
95
|
+
# gmosx: any idea how to better test this?
|
96
|
+
if ex.to_s =~ /0x80020009/i
|
97
|
+
Logger.warn "Cannot drop database '#{database}', it does not exist!"
|
98
|
+
super
|
99
|
+
else
|
100
|
+
raise
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def drop_db(database, user = nil, password = nil)
|
106
|
+
raise 'Not implemented!'
|
107
|
+
|
108
|
+
begin
|
109
|
+
conn = DBI.connect("DBI:ADO:Provider=SQLOLEDB;Data Source=localhost;Initial Catalog=master;User Id=sa;Password=sa;")
|
110
|
+
conn["AutoCommit"] = true
|
111
|
+
# FIXME: why no drop?
|
112
|
+
# conn.execute("DROP DATABASE #{database}")
|
113
|
+
Logger.warn "Ignoring credentials for database drop (not implemented)" if user
|
114
|
+
Logger.info "Dropped database '#{database}'."
|
115
|
+
super
|
116
|
+
rescue Exception => ex
|
117
|
+
# gmosx: any idea how to better test this?
|
118
|
+
if ex.to_s =~ /0x80020009/i
|
119
|
+
Logger.warn "Cannot drop database '#{database}', it does not exist!"
|
120
|
+
super
|
121
|
+
else
|
122
|
+
raise
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
def props_for_insert(klass)
|
128
|
+
klass.__props.reject { |p| :oid == p.symbol }
|
129
|
+
end
|
130
|
+
|
131
|
+
def insert_code(klass, db, pre_cb, post_cb="123")
|
132
|
+
props = props_for_insert(klass)
|
133
|
+
values = props.collect { |p| write_prop(p) }.join(',')
|
134
|
+
|
135
|
+
sql = "INSERT INTO #{klass::DBTABLE} (#{props.collect {|p| p.name}.join(',')}) VALUES (#{values});"
|
136
|
+
|
137
|
+
%{
|
138
|
+
#{pre_cb}
|
139
|
+
conn.exec "#{sql}"
|
140
|
+
conn.commit
|
141
|
+
res = conn.query("SELECT IDENT_CURRENT('#{klass::DBTABLE}')")
|
142
|
+
@oid = res[0][0].to_i
|
143
|
+
#res.finish
|
144
|
+
#{post_cb}
|
145
|
+
}
|
146
|
+
end
|
147
|
+
|
148
|
+
def new_connection(db)
|
149
|
+
return SqlserverConnection.new(db)
|
150
|
+
end
|
151
|
+
|
152
|
+
def calc_field_index(klass, db)
|
153
|
+
res = db.get_connection.store.execute("SELECT TOP 1 * FROM #{klass::DBTABLE}")
|
154
|
+
meta = db.managed_classes[klass]
|
155
|
+
columns = res.column_names
|
156
|
+
|
157
|
+
for idx in (0...columns.size)
|
158
|
+
meta.field_index[columns[idx]] = idx
|
159
|
+
end
|
160
|
+
|
161
|
+
ensure
|
162
|
+
res.finish
|
163
|
+
end
|
164
|
+
|
165
|
+
def create_table(klass, db)
|
166
|
+
conn = db.get_connection
|
167
|
+
|
168
|
+
fields = create_fields(klass)
|
169
|
+
|
170
|
+
sql = "CREATE TABLE #{klass::DBTABLE} (#{fields.join(', ')}"
|
171
|
+
|
172
|
+
# Create table constrains.
|
173
|
+
if klass.__meta and constrains = klass.__meta[:sql_constrain]
|
174
|
+
sql << ", #{constrains.join(', ')}"
|
175
|
+
end
|
176
|
+
sql << ");"
|
177
|
+
|
178
|
+
begin
|
179
|
+
conn.store.execute(sql)
|
180
|
+
conn.commit
|
181
|
+
Logger.info "Created table '#{klass::DBTABLE}'."
|
182
|
+
rescue => ex
|
183
|
+
if ex.to_s =~ /80040E14/i
|
184
|
+
Logger.debug 'Table already exists' if $DBG
|
185
|
+
else
|
186
|
+
raise
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
# Create indices.
|
191
|
+
|
192
|
+
if klass.__meta and indices = klass.__meta[:sql_index]
|
193
|
+
for data in indices
|
194
|
+
idx, options = *data
|
195
|
+
idx = idx.to_s
|
196
|
+
pre_sql, post_sql = options[:pre], options[:post]
|
197
|
+
idxname = idx.gsub(/ /, "").gsub(/,/, "_").gsub(/\(.*\)/, "")
|
198
|
+
sql << " CREATE #{pre_sql} INDEX #{klass::DBTABLE}_#{idxname}_idx #{post_sql} ON #{klass::DBTABLE} (#{idx});"
|
199
|
+
begin
|
200
|
+
conn.store.execute(sql)
|
201
|
+
conn.commit
|
202
|
+
rescue => ex
|
203
|
+
if ex.to_s =~ /80040E14/i
|
204
|
+
Logger.debug 'Table already exists' if $DBG
|
205
|
+
else
|
206
|
+
raise
|
207
|
+
end
|
208
|
+
end
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
# Create join tables if needed. Join tables are used in
|
213
|
+
# 'many_to_many' relations.
|
214
|
+
|
215
|
+
if klass.__meta and joins = klass.__meta[:sql_join]
|
216
|
+
for data in joins
|
217
|
+
# the class to join to and some options.
|
218
|
+
join_name, join_class, options = *data
|
219
|
+
|
220
|
+
# gmosx: dont use DBTABLE here, perhaps the join class
|
221
|
+
# is not managed yet.
|
222
|
+
join_table = "#{self.class.join_table(klass, join_class, join_name)}"
|
223
|
+
join_src = "#{self.class.encode(klass)}_oid"
|
224
|
+
join_dst = "#{self.class.encode(join_class)}_oid"
|
225
|
+
begin
|
226
|
+
conn.store.execute("CREATE TABLE #{join_table} ( key1 integer NOT NULL, key2 integer NOT NULL )").finish
|
227
|
+
conn.store.execute("CREATE INDEX #{join_table}_key1_idx ON #{join_table} (key1)").finish
|
228
|
+
conn.store.execute("CREATE INDEX #{join_table}_key2_idx ON #{join_table} (key2)").finish
|
229
|
+
conn.commit
|
230
|
+
rescue => ex
|
231
|
+
# gmosx: any idea how to better test this?
|
232
|
+
if ex.to_s =~ /80040E14/i
|
233
|
+
Logger.debug "Join table already exists" if $DBG
|
234
|
+
else
|
235
|
+
raise
|
236
|
+
end
|
237
|
+
end
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
ensure
|
242
|
+
db.put_connection
|
243
|
+
end
|
244
|
+
|
245
|
+
def drop_table(klass)
|
246
|
+
super
|
247
|
+
exec "DROP TABLE #{klass::DBTABLE}"
|
248
|
+
end
|
249
|
+
|
250
|
+
# Generate the property for oid.
|
251
|
+
|
252
|
+
def eval_og_oid(klass)
|
253
|
+
klass.class_eval %{
|
254
|
+
prop_accessor :oid, Fixnum, :sql => 'int NOT NULL IDENTITY(1, 1) PRIMARY KEY'
|
255
|
+
}
|
256
|
+
end
|
257
|
+
|
258
|
+
end
|
259
|
+
|
260
|
+
# The SqlserverConnection connection.
|
261
|
+
|
262
|
+
class SqlserverConnection < Connection
|
263
|
+
|
264
|
+
def initialize(db)
|
265
|
+
super
|
266
|
+
config = db.config
|
267
|
+
|
268
|
+
begin
|
269
|
+
@store = DBI.connect("DBI:ADO:Provider=SQLOLEDB;Data Source=#{config[:address]};Initial Catalog=#{config[:database]};User Id=#{config[:user].to_s};Password=#{config[:password].to_s};")
|
270
|
+
rescue => ex
|
271
|
+
# gmosx, FIXME: drak, fix this!
|
272
|
+
if ex.to_s =~ /database .* does not exist/i
|
273
|
+
Logger.info "Database '#{config[:database]}' not found!"
|
274
|
+
@db.adapter.create_db(config[:database], config[:user])
|
275
|
+
retry
|
276
|
+
end
|
277
|
+
raise
|
278
|
+
end
|
279
|
+
end
|
280
|
+
|
281
|
+
def close
|
282
|
+
@store.disconnect
|
283
|
+
super
|
284
|
+
end
|
285
|
+
|
286
|
+
def prepare(sql)
|
287
|
+
@store.prepare(sql)
|
288
|
+
end
|
289
|
+
|
290
|
+
def query(sql)
|
291
|
+
Logger.debug sql if $DBG
|
292
|
+
begin
|
293
|
+
res = @store.select_all(sql)
|
294
|
+
return res
|
295
|
+
rescue => ex
|
296
|
+
handle_db_exception(ex, sql)
|
297
|
+
end
|
298
|
+
end
|
299
|
+
|
300
|
+
def exec(sql)
|
301
|
+
Logger.debug sql if $DBG
|
302
|
+
begin
|
303
|
+
@store.execute(sql).finish
|
304
|
+
rescue => ex
|
305
|
+
handle_db_exception(ex, sql)
|
306
|
+
end
|
307
|
+
end
|
308
|
+
|
309
|
+
def start
|
310
|
+
# no need to do something.
|
311
|
+
end
|
312
|
+
|
313
|
+
def commit
|
314
|
+
@store.commit
|
315
|
+
end
|
316
|
+
|
317
|
+
def rollback
|
318
|
+
@store.rollback
|
319
|
+
end
|
320
|
+
|
321
|
+
def valid_res?(res)
|
322
|
+
return !(res.nil?)
|
323
|
+
end
|
324
|
+
|
325
|
+
def read_one(res, klass)
|
326
|
+
return nil unless valid_res?(res)
|
327
|
+
return nil unless res
|
328
|
+
|
329
|
+
obj = klass.new
|
330
|
+
obj.og_read(res)
|
331
|
+
|
332
|
+
return obj
|
333
|
+
end
|
334
|
+
|
335
|
+
def read_all(res, klass)
|
336
|
+
return [] unless valid_res?(res)
|
337
|
+
objects = []
|
338
|
+
|
339
|
+
for tuple in (0...res.size)
|
340
|
+
obj = klass.new
|
341
|
+
obj.og_read(res, tuple)
|
342
|
+
objects << obj
|
343
|
+
end
|
344
|
+
|
345
|
+
return objects
|
346
|
+
end
|
347
|
+
|
348
|
+
def read_int(res, idx = 0)
|
349
|
+
val = res.next[idx].to_i
|
350
|
+
res.finish
|
351
|
+
return val
|
352
|
+
end
|
353
|
+
|
354
|
+
def get_row(res)
|
355
|
+
res.next
|
356
|
+
end
|
357
|
+
|
358
|
+
end
|
359
|
+
|
360
|
+
end
|