nitro 0.10.0 → 0.11.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (99) hide show
  1. data/AUTHORS +4 -1
  2. data/ChangeLog +290 -7
  3. data/README +3 -3
  4. data/RELEASES +94 -0
  5. data/Rakefile +7 -7
  6. data/benchmark/og/bench.rb +11 -10
  7. data/{ChangeLog.1 → doc/ChangeLog.1} +0 -0
  8. data/doc/apache.txt +9 -0
  9. data/doc/architecture.txt +1 -27
  10. data/doc/bugs.txt +11 -4
  11. data/doc/config.txt +22 -0
  12. data/doc/og_config.txt +35 -0
  13. data/doc/og_tutorial.txt +595 -0
  14. data/doc/tutorial.txt +22 -0
  15. data/examples/blog/conf/apache.conf +30 -0
  16. data/examples/blog/conf/lhttpd.conf +2 -2
  17. data/examples/blog/lib/blog/controller.rb +11 -2
  18. data/examples/blog/log/apache.error_log +5528 -0
  19. data/examples/blog/root/fcgi.rb +1 -1
  20. data/examples/blog/run.rb +9 -3
  21. data/examples/flash/run.rb +2 -2
  22. data/examples/no_xsl_blog/conf/apache.conf +30 -0
  23. data/examples/no_xsl_blog/conf/lhttpd.conf +1 -1
  24. data/examples/no_xsl_blog/lib/blog/controller.rb +2 -2
  25. data/examples/no_xsl_blog/log/apache.error_log +68 -0
  26. data/examples/no_xsl_blog/root/fcgi.rb +2 -2
  27. data/examples/no_xsl_blog/run.rb +3 -3
  28. data/examples/og/run.rb +1 -1
  29. data/examples/tiny/conf/apache.conf +29 -4
  30. data/examples/tiny/conf/lhttpd.conf +1 -1
  31. data/examples/tiny/log/apache.error_log +30 -0
  32. data/examples/tiny/root/fcgi.rb +2 -2
  33. data/examples/tiny/root/index.xhtml +1 -1
  34. data/examples/tiny/run.rb +3 -2
  35. data/examples/wee_style/run.rb +7 -9
  36. data/examples/why_wiki/README +5 -0
  37. data/examples/why_wiki/run.rb +57 -0
  38. data/examples/why_wiki/wiki.yml +6 -0
  39. data/examples/wiki.yml +1 -0
  40. data/lib/glue/array.rb +14 -33
  41. data/lib/glue/hash.rb +32 -53
  42. data/lib/glue/pool.rb +9 -12
  43. data/lib/glue/property.rb +31 -9
  44. data/lib/nitro.rb +30 -8
  45. data/lib/nitro/adapters/cgi.rb +23 -3
  46. data/lib/nitro/adapters/webrick.rb +9 -3
  47. data/lib/nitro/builders/form.rb +21 -13
  48. data/lib/nitro/builders/rss.rb +20 -9
  49. data/lib/nitro/builders/table.rb +69 -10
  50. data/lib/nitro/builders/xhtml.rb +13 -4
  51. data/lib/nitro/component.rb +15 -0
  52. data/lib/nitro/conf.rb +4 -3
  53. data/lib/nitro/context.rb +22 -14
  54. data/lib/nitro/controller.rb +63 -5
  55. data/lib/nitro/dispatcher.rb +11 -6
  56. data/lib/nitro/output.rb +28 -0
  57. data/lib/nitro/render.rb +78 -59
  58. data/lib/nitro/request.rb +5 -1
  59. data/lib/nitro/runner.rb +20 -6
  60. data/lib/nitro/session.rb +89 -18
  61. data/lib/nitro/session/drb.rb +31 -0
  62. data/lib/nitro/session/drbserver.rb +71 -0
  63. data/lib/nitro/session/memory.rb +13 -0
  64. data/lib/nitro/simple.rb +7 -0
  65. data/lib/nitro/ui/date-select.rb +2 -5
  66. data/lib/nitro/ui/pager.rb +4 -4
  67. data/lib/nitro/ui/tabs.rb +2 -4
  68. data/lib/nitro/uri.rb +7 -4
  69. data/lib/og.rb +20 -12
  70. data/lib/og/adapter.rb +40 -13
  71. data/lib/og/adapters/filesys.rb +121 -0
  72. data/lib/og/adapters/mysql.rb +10 -5
  73. data/lib/og/adapters/oracle.rb +374 -0
  74. data/lib/og/adapters/psql.rb +10 -23
  75. data/lib/og/adapters/sqlite.rb +3 -3
  76. data/lib/og/backend.rb +2 -2
  77. data/lib/og/connection.rb +6 -6
  78. data/lib/og/database.rb +5 -5
  79. data/lib/og/enchant.rb +6 -2
  80. data/lib/og/meta.rb +56 -26
  81. data/lib/og/mock.rb +1 -1
  82. data/lib/og/typemacros.rb +23 -0
  83. data/lib/parts/content.rb +4 -10
  84. data/test/nitro/adapters/tc_cgi.rb +1 -1
  85. data/test/nitro/builders/tc_rss.rb +1 -1
  86. data/test/nitro/builders/tc_table.rb +30 -0
  87. data/test/nitro/tc_context.rb +4 -0
  88. data/test/nitro/tc_controller.rb +9 -2
  89. data/test/og/tc_filesys.rb +83 -0
  90. data/test/og/tc_meta.rb +55 -0
  91. data/test/tc_og.rb +115 -36
  92. data/vendor/README +11 -5
  93. data/vendor/breakpoint.rb +35 -38
  94. data/vendor/breakpoint_client.rb +119 -80
  95. data/vendor/composite_sexp_processor.rb +43 -0
  96. data/vendor/parse_tree.rb +745 -0
  97. data/vendor/sexp_processor.rb +453 -0
  98. metadata +34 -7
  99. data/examples/no_xsl_blog/conf/app.conf.rb +0 -47
@@ -1,6 +1,6 @@
1
1
  # * George Moschovitis <gm@navel.gr>
2
2
  # (c) 2004-2005 Navel, all rights reserved.
3
- # $Id: mysql.rb 259 2005-02-15 08:54:54Z gmosx $
3
+ # $Id: mysql.rb 266 2005-02-28 14:50:48Z gmosx $
4
4
 
5
5
  require 'mysql'
6
6
 
@@ -8,7 +8,7 @@ require 'og/adapter'
8
8
  require 'og/connection'
9
9
  require 'glue/attribute'
10
10
 
11
- class Og
11
+ module Og
12
12
 
13
13
  # The MySQL adapter. This adapter communicates with
14
14
  # an MySQL rdbms. For extra documentation see
@@ -18,7 +18,7 @@ class MysqlAdapter < Adapter
18
18
 
19
19
  def initialize
20
20
  super
21
- @typemap.update({TrueClass => 'tinyint'})
21
+ @typemap.update(TrueClass => 'tinyint')
22
22
  end
23
23
 
24
24
  def self.escape(str)
@@ -42,7 +42,7 @@ class MysqlAdapter < Adapter
42
42
  elsif p.klass.ancestors.include?(Float)
43
43
  return "#\{@#{p.symbol} || 'NULL'\}"
44
44
  elsif p.klass.ancestors.include?(String)
45
- return "'#\{#{self.class}.escape(@#{p.symbol})\}'"
45
+ return %|#\{@#{p.symbol} ? "'#\{#{self.class}.escape(@#{p.symbol})\}'" : 'NULL'\}|
46
46
  elsif p.klass.ancestors.include?(Time)
47
47
  return %|#\{@#{p.symbol} ? "'#\{#{self.class}.timestamp(@#{p.symbol})\}'" : 'NULL'\}|
48
48
  elsif p.klass.ancestors.include?(Date)
@@ -50,6 +50,7 @@ class MysqlAdapter < Adapter
50
50
  elsif p.klass.ancestors.include?(TrueClass)
51
51
  return "#\{@#{p.symbol} ? 1 : 0 \}"
52
52
  else
53
+ # gmosx: keep the '' for nil symbols.
53
54
  return %|#\{@#{p.symbol} ? "'#\{#{self.class}.escape(@#{p.symbol}.to_yaml)\}'" : "''"\}|
54
55
  end
55
56
  end
@@ -82,6 +83,10 @@ class MysqlAdapter < Adapter
82
83
  super
83
84
  end
84
85
 
86
+ def props_for_insert(klass)
87
+ klass.__props.reject { |p| :oid == p.symbol }
88
+ end
89
+
85
90
  def insert_code(klass, db, pre_cb, post_cb)
86
91
  props = props_for_insert(klass)
87
92
  values = props.collect { |p| write_prop(p) }.join(',')
@@ -98,7 +103,7 @@ class MysqlAdapter < Adapter
98
103
  end
99
104
 
100
105
  def new_connection(db)
101
- return Og::MysqlConnection.new(db)
106
+ return MysqlConnection.new(db)
102
107
  end
103
108
 
104
109
  def calc_field_index(klass, db)
@@ -0,0 +1,374 @@
1
+ # * Matt Bowen <matt.bowen@farweststeel.com>
2
+ # * George Moschovitis <gm@navel.gr>
3
+ # (c) 2004-2005 Navel, all rights reserved.
4
+ # $Id: oracle.rb 266 2005-02-28 14:50:48Z gmosx $
5
+
6
+ require 'oracle'
7
+
8
+ require 'og/adapter'
9
+ require 'og/connection'
10
+ require 'glue/attribute'
11
+
12
+ module Og
13
+
14
+ # The Oracle adapter. This adapter communicates with
15
+ # an Oracle rdbms. For extra documentation see
16
+ # lib/og/adapter.rb
17
+
18
+ class OracleAdapter < Adapter
19
+
20
+ def initialize
21
+ super
22
+ @typemap.update(
23
+ Integer => 'number',
24
+ Fixnum => 'number',
25
+ String => 'varchar2(512)',
26
+ TrueClass => 'number',
27
+ Object => 'varchar2(1024)',
28
+ Array => 'varchar2(1024)',
29
+ Hash => 'varchar2(1024)'
30
+ )
31
+ end
32
+
33
+ def self.timestamp(time = Time.now)
34
+ return nil unless time
35
+ return time.strftime("%Y-%m-%d %H:%M:%S")
36
+ end
37
+
38
+ def self.date(date)
39
+ return nil unless date
40
+ return "#{date.year}-#{date.month}-#{date.mday}"
41
+ end
42
+
43
+ def write_prop(p)
44
+ if p.klass.ancestors.include?(Integer)
45
+ return "#\{@#{p.symbol} || 'NULL'\}"
46
+ elsif p.klass.ancestors.include?(Float)
47
+ return "#\{@#{p.symbol} || 'NULL'\}"
48
+ elsif p.klass.ancestors.include?(String)
49
+ return "'#\{#{self.class}.escape(@#{p.symbol})\}'"
50
+ elsif p.klass.ancestors.include?(Time)
51
+ return %|#\{@#{p.symbol} ? "'#\{#{self.class}.timestamp(@#{p.symbol})\}'" : 'NULL'\}|
52
+ elsif p.klass.ancestors.include?(Date)
53
+ return %|#\{@#{p.symbol} ? "'#\{#{self.class}.date(@#{p.symbol})\}'" : 'NULL'\}|
54
+ elsif p.klass.ancestors.include?(TrueClass)
55
+ return "#\{@#{p.symbol} ? \"1\" : 'NULL' \}"
56
+ else
57
+ return %|#\{@#{p.symbol} ? "'#\{#{self.class}.escape(@#{p.symbol}.to_yaml)\}'" : "''"\}|
58
+ end
59
+ end
60
+
61
+ #--
62
+ # mcb:
63
+ # Unlike MySQL or Postgres, Oracle database/schema creation is a big deal.
64
+ # I don't know how to do it from the command line. I use Oracle's Database
65
+ # Configuration Assistant utility (dbca). I takes 30min - 1hr to create
66
+ # a full blown schema. So, your FIXME comments are fine. I'm thinking you
67
+ # won't be able to do this via Og, but once created, Og will be able to create
68
+ # tables, indexes, and other objects.
69
+ #++
70
+
71
+ def create_db(database, user = nil, password = nil)
72
+ # FIXME: what is appropriate for oracle?
73
+ # `createdb #{database} -U #{user}`
74
+ super
75
+ end
76
+
77
+ def drop_db(database, user = nil, password = nil)
78
+ # FIXME: what is appropriate for oracle?
79
+ # `dropdb #{database} -U #{user}`
80
+ super
81
+ end
82
+
83
+ def insert_code(klass, db, pre_cb, post_cb)
84
+ props = props_for_insert(klass)
85
+ values = props.collect { |p| write_prop(p) }.join(',')
86
+
87
+ sql = "INSERT INTO #{klass::DBTABLE} (#{props.collect {|p| p.name}.join(',')}) VALUES (#{values})"
88
+
89
+ %{
90
+ #{pre_cb}
91
+ res = conn.store.exec("SELECT #{klass::DBSEQ}.nextval FROM DUAL")
92
+ @oid = res.fetch[0].to_i
93
+ res.close
94
+ conn.exec "#{sql}"
95
+ #{post_cb}
96
+ }
97
+ end
98
+
99
+ def new_connection(db)
100
+ return OracleConnection.new(db)
101
+ end
102
+
103
+ def calc_field_index(klass, db)
104
+ # gmosx: This is incredible!!! argh!
105
+ # res = db.query "SELECT * FROM #{klass::DBTABLE} # LIMIT 1"
106
+ res = db.query "SELECT * FROM (SELECT * FROM #{klass::DBTABLE}) WHERE ROWNUM <= 1"
107
+ meta = db.managed_classes[klass]
108
+
109
+ columns = res.getColNames
110
+
111
+ for idx in (0...columns.size)
112
+ # mcb: Oracle will return column names in uppercase.
113
+ meta.field_index[columns[idx].downcase] = idx
114
+ end
115
+
116
+ ensure
117
+ res.close if res
118
+ end
119
+
120
+ def eval_og_oid(klass)
121
+ klass.class_eval %{
122
+ prop_accessor :oid, Fixnum, :sql => "number PRIMARY KEY"
123
+ }
124
+ end
125
+
126
+ def create_table(klass, db)
127
+ conn = db.get_connection
128
+
129
+ fields = create_fields(klass)
130
+
131
+ sql = "CREATE TABLE #{klass::DBTABLE} (#{fields.join(', ')}"
132
+
133
+ # Create table constrains.
134
+
135
+ if klass.__meta and constrains = klass.__meta[:sql_constrain]
136
+ sql << ", #{constrains.join(', ')}"
137
+ end
138
+
139
+ # mcb: Oracle driver chokes on semicolon.
140
+ sql << ")"
141
+
142
+ # mcb:
143
+ # Oracle driver appears to have problems executing multiple SQL
144
+ # statements in single exec() call. Chokes with or without semicolon
145
+ # delimiter. Solution: make separate calls for each statement.
146
+
147
+ begin
148
+ conn.store.exec(sql).close
149
+ Logger.info "Created table '#{klass::DBTABLE}'."
150
+
151
+ # Create indices.
152
+
153
+ if klass.__meta and indices = klass.__meta[:sql_index]
154
+ for data in indices
155
+ idx, options = *data
156
+ idx = idx.to_s
157
+ pre_sql, post_sql = options[:pre], options[:post]
158
+ idxname = idx.gsub(/ /, "").gsub(/,/, "_").gsub(/\(.*\)/, "")
159
+ sql = " CREATE #{pre_sql} INDEX #{klass::DBTABLE}_#{idxname}_idx #{post_sql} ON #{klass::DBTABLE} (#{idx})"
160
+ conn.store.exec(sql).close
161
+ Logger.info "Created index '#{klass::DBTABLE}_#{idxname}_idx'."
162
+ end
163
+ end
164
+ rescue Exception => ex
165
+ # gmosx: any idea how to better test this?
166
+ if ex.to_s =~ /ORA-00955/i
167
+ Logger.debug 'Table or index already exists' if $DBG
168
+ return
169
+ else
170
+ raise
171
+ end
172
+ end
173
+
174
+ # Create the sequence for this table.
175
+ begin
176
+ conn.store.exec("CREATE SEQUENCE #{klass::DBSEQ}").close
177
+ Logger.info "Created sequence '#{klass::DBSEQ}'."
178
+ rescue Exception => ex
179
+ # gmosx: any idea how to better test this?
180
+ if ex.to_s =~ /ORA-00955/i
181
+ Logger.debug "Sequence already exists" if $DBG
182
+ else
183
+ raise
184
+ end
185
+ end
186
+
187
+ # Create join tables if needed. Join tables are used in
188
+ # 'many_to_many' relations.
189
+
190
+ if klass.__meta and joins = klass.__meta[:sql_join]
191
+ for data in joins
192
+ # the class to join to and some options.
193
+ join_class, options = *data
194
+
195
+ # gmosx: dont use DBTABLE here, perhaps the join class
196
+ # is not managed yet.
197
+ join_table = "#{self.class.join_table(klass, join_class)}"
198
+ join_src = "#{self.class.encode(klass)}_oid"
199
+ join_dst = "#{self.class.encode(join_class)}_oid"
200
+ begin
201
+ conn.store.exec("CREATE TABLE #{join_table} ( key1 integer NOT NULL, key2 integer NOT NULL )").close
202
+ conn.store.exec("CREATE INDEX #{join_table}_key1_idx ON #{join_table} (key1)").close
203
+ conn.store.exec("CREATE INDEX #{join_table}_key2_idx ON #{join_table} (key2)").close
204
+ rescue Exception => ex
205
+ # gmosx: any idea how to better test this?
206
+ if ex.to_s =~ /ORA-00955/i
207
+ Logger.debug "Join table already exists" if $DBG
208
+ else
209
+ raise
210
+ end
211
+ end
212
+ end
213
+ end
214
+
215
+ ensure
216
+ db.put_connection
217
+ end
218
+
219
+ def drop_table(klass)
220
+ super
221
+ exec "DROP SEQUENCE #{klass::DBSEQ}"
222
+ end
223
+
224
+ # Generate the property for oid.
225
+
226
+ #--
227
+ # mcb:
228
+ # Oracle doesn't have a "serial" datatype. Replace with
229
+ # integer (which is probably just a synonym for NUMBER(38,0))
230
+ # A sequence is created automatically by Og.
231
+ #++
232
+
233
+ def eval_og_oid(klass)
234
+ klass.class_eval %{
235
+ prop_accessor :oid, Fixnum, :sql => 'integer PRIMARY KEY'
236
+ }
237
+ end
238
+ end
239
+
240
+ # The Oracle connection.
241
+
242
+ class OracleConnection < Connection
243
+
244
+ # mcb:
245
+ # The database connection details are tucked away in a
246
+ # TNS entry (Transparent Network Substrate) which specifies host,
247
+ # port, protocol, and database instance. Here is a sample TNS
248
+ # entry:
249
+ #
250
+ # File: tns_names.ora
251
+ #
252
+ # KBSID =
253
+ # (DESCRIPTION =
254
+ # (ADDRESS_LIST =
255
+ # (ADDRESS = (PROTOCOL = TCP)(HOST = keebler.farweststeel.com)(PORT = 1521))
256
+ # )
257
+ # (CONNECT_DATA =
258
+ # (SID = KBSID)
259
+ # )
260
+ # )
261
+
262
+ def initialize(db)
263
+ super
264
+ config = db.config
265
+
266
+ begin
267
+ # FIXME: how to pass address etc?
268
+ @store = Oracle.new(config[:user], config[:password], config[:database])
269
+ # gmosx: better use this???
270
+ # @store = Oracle.new(config[:tns])
271
+
272
+ # gmosx: does this work?
273
+ @store.autocommit = true
274
+ rescue Exception => ex
275
+ # mcb:
276
+ # Oracle will raise a ORA-01017 if username, password, or
277
+ # SID aren't valid. I verified this for all three.
278
+ # irb(main):002:0> conn = Oracle.new('keebler', 'dfdfd', 'kbsid')
279
+ # /usr/local/lib/ruby/site_ruby/1.8/oracle.rb:27:in `logon': ORA-01017: invalid username/password; logon denied (OCIError)
280
+ # gmosx:
281
+ # any idea how to better test this? an integer error id?
282
+ if ex.to_s =~ /ORA-01017/i
283
+ Logger.info "Database '#{config[:database]}' not found!"
284
+ @db.adapter.create_db(config[:database], config[:user])
285
+ retry
286
+ end
287
+ raise
288
+ end
289
+ end
290
+
291
+ def close
292
+ @store.logoff
293
+ super
294
+ end
295
+
296
+ def query(sql)
297
+ Logger.debug sql if $DBG
298
+ begin
299
+ return @store.exec(sql)
300
+ rescue Exception => ex
301
+ Logger.error "DB error #{ex}, [#{sql}]"
302
+ Logger.error ex.backtrace.join("\n")
303
+ raise
304
+ # return nil
305
+ end
306
+ end
307
+
308
+ def exec(sql)
309
+ Logger.debug sql if $DBG
310
+ begin
311
+ @store.exec(sql)
312
+ rescue Exception => ex
313
+ Logger.error "DB error #{ex}, [#{sql}]"
314
+ Logger.error ex.backtrace.join("\n")
315
+ raise
316
+ end
317
+ end
318
+
319
+ def start
320
+ @store.autocommit = false
321
+ end
322
+
323
+ def commit
324
+ @store.commit
325
+ ensure
326
+ @store.autocommit = true
327
+ end
328
+
329
+ def rollback
330
+ @store.rollback
331
+ ensure
332
+ @store.autocommit = true
333
+ end
334
+
335
+ def valid_res?(res)
336
+ return !(res.nil?)
337
+ end
338
+
339
+ def read_one(res, klass)
340
+ return nil unless valid_res?(res)
341
+
342
+ row = res.fetch
343
+ return nil unless row
344
+
345
+ obj = klass.new
346
+ obj.og_read(row)
347
+
348
+ res.close
349
+ return obj
350
+ end
351
+
352
+ def read_all(res, klass)
353
+ return [] unless valid_res?(res)
354
+ objects = []
355
+
356
+ while row = res.fetch
357
+ obj = klass.new
358
+ obj.og_read(row)
359
+ objects << obj
360
+ end
361
+
362
+ res.close
363
+ return objects
364
+ end
365
+
366
+ def read_int(res, idx = 0)
367
+ val = res.fetch[idx].to_i
368
+ res.close
369
+ return val
370
+ end
371
+
372
+ end
373
+
374
+ end
@@ -1,6 +1,6 @@
1
1
  # * George Moschovitis <gm@navel.gr>
2
2
  # (c) 2004-2005 Navel, all rights reserved.
3
- # $Id: psql.rb 259 2005-02-15 08:54:54Z gmosx $
3
+ # $Id: psql.rb 266 2005-02-28 14:50:48Z gmosx $
4
4
 
5
5
  require 'postgres'
6
6
 
@@ -8,7 +8,7 @@ require 'og/adapter'
8
8
  require 'og/connection'
9
9
  require 'glue/attribute'
10
10
 
11
- class Og
11
+ module Og
12
12
 
13
13
  # The PostgreSQL adapter. This adapter communicates with
14
14
  # an PostgreSQL rdbms. For extra documentation see
@@ -30,24 +30,6 @@ class PsqlAdapter < Adapter
30
30
  return nil unless date
31
31
  return "#{date.year}-#{date.month}-#{date.mday}"
32
32
  end
33
-
34
- def write_prop(p)
35
- if p.klass.ancestors.include?(Integer)
36
- return "#\{@#{p.symbol} || 'NULL'\}"
37
- elsif p.klass.ancestors.include?(Float)
38
- return "#\{@#{p.symbol} || 'NULL'\}"
39
- elsif p.klass.ancestors.include?(String)
40
- return "'#\{#{self.class}.escape(@#{p.symbol})\}'"
41
- elsif p.klass.ancestors.include?(Time)
42
- return %|#\{@#{p.symbol} ? "'#\{#{self.class}.timestamp(@#{p.symbol})\}'" : 'NULL'\}|
43
- elsif p.klass.ancestors.include?(Date)
44
- return %|#\{@#{p.symbol} ? "'#\{#{self.class}.date(@#{p.symbol})\}'" : 'NULL'\}|
45
- elsif p.klass.ancestors.include?(TrueClass)
46
- return "#\{@#{p.symbol} ? \"'t'\" : 'NULL' \}"
47
- else
48
- return %|#\{@#{p.symbol} ? "'#\{#{self.class}.escape(@#{p.symbol}.to_yaml)\}'" : "''"\}|
49
- end
50
- end
51
33
 
52
34
  def read_prop(p, idx)
53
35
  if p.klass.ancestors.include?(Integer)
@@ -94,7 +76,7 @@ class PsqlAdapter < Adapter
94
76
  end
95
77
 
96
78
  def new_connection(db)
97
- return Og::PsqlConnection.new(db)
79
+ return PsqlConnection.new(db)
98
80
  end
99
81
 
100
82
  def calc_field_index(klass, db)
@@ -116,7 +98,7 @@ class PsqlAdapter < Adapter
116
98
 
117
99
  sql = "CREATE TABLE #{klass::DBTABLE} (#{fields.join(', ')}"
118
100
 
119
- # Create table constrains
101
+ # Create table constrains.
120
102
 
121
103
  if klass.__meta and constrains = klass.__meta[:sql_constrain]
122
104
  sql << ", #{constrains.join(', ')}"
@@ -124,7 +106,7 @@ class PsqlAdapter < Adapter
124
106
 
125
107
  sql << ") WITHOUT OIDS;"
126
108
 
127
- # Create indices
109
+ # Create indices.
128
110
 
129
111
  if klass.__meta and indices = klass.__meta[:sql_index]
130
112
  for data in indices
@@ -226,6 +208,11 @@ class PsqlConnection < Connection
226
208
  end
227
209
  end
228
210
 
211
+ def close
212
+ @store.close
213
+ super
214
+ end
215
+
229
216
  def query(sql)
230
217
  Logger.debug sql if $DBG
231
218
  begin