og 0.17.0 → 0.18.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,63 @@
1
+ KirbyBase 2.2
2
+
3
+ A small, plain-text, dbms written in Ruby. It can be used either embedded
4
+ or client/server. Version 2 is a complete re-write with a completely new
5
+ interface. It is NOT backwards compatible. If you need backwards
6
+ compatibility, please use version 1.6.
7
+
8
+
9
+ *Installation:
10
+
11
+ Unpack the file you downloaded. Execute "ruby install.rb" or simply make
12
+ sure kirbybase.rb is somewhere in your Ruby library path.
13
+
14
+
15
+ *Documentation:
16
+
17
+ Documentation is in manual.html. Also, RDoc generated documentation is in
18
+ the doc directory.
19
+
20
+ See kbtest.rb for examples of how to use KirbyBase.
21
+
22
+
23
+ *Manifest:
24
+
25
+ readme.txt - this file
26
+ install.rb - install script
27
+ changes.txt - history of changes.
28
+ manual.html - documentation
29
+ kirbybase.rb - dbms library
30
+ kbserver.rb - multi-threaded database server script.
31
+ kbtest.rb - test script with examples.
32
+ record_class_test.rb - script showing how to have KB return class instances.
33
+ csv_import_test.rb - script showing how to have KB import a csv file.
34
+ plane.csv - sample csv file used in csv_import_test.rb
35
+ doc directory - RDoc generated documentation in html format.
36
+
37
+
38
+ *License:
39
+
40
+ KirbyBase is distributed under the same license as Ruby.
41
+
42
+
43
+ *Warranty:
44
+
45
+ I should probably put something more legalese here but let me just say:
46
+
47
+ KirbyBase carries no warranty! Use at your own risk. If it eats your
48
+ data, please don't come after me. :)
49
+
50
+
51
+ That being said, please send any bug reports, suggestions, ideas,
52
+ improvements, to:
53
+
54
+ jcribbs@twmi.rr.com
55
+
56
+ You can find more info about KirbyBase at:
57
+
58
+ http://www.netpromi.com/kirbybase.html
59
+
60
+
61
+ Thanks for trying KirbyBase.
62
+
63
+ Jamey Cribbs
@@ -1,4 +1,2 @@
1
- # $Id$
2
-
3
1
  module Og
4
2
  end
@@ -152,9 +152,9 @@ class MysqlStore < SqlStore
152
152
  private
153
153
 
154
154
  def create_table(klass)
155
- columns = columns_for_class(klass)
155
+ fields = fields_for_class(klass)
156
156
 
157
- sql = "CREATE TABLE #{klass::OGTABLE} (#{columns.join(', ')}"
157
+ sql = "CREATE TABLE #{klass::OGTABLE} (#{fields.join(', ')}"
158
158
 
159
159
  # Create table constrains.
160
160
 
@@ -210,7 +210,7 @@ private
210
210
  end
211
211
  end
212
212
 
213
- def create_column_map(klass)
213
+ def create_field_map(klass)
214
214
  conn.query_with_result = true
215
215
  res = @conn.query "SELECT * FROM #{klass::OGTABLE} LIMIT 1"
216
216
  map = {}
@@ -245,9 +245,9 @@ private
245
245
 
246
246
  def read_prop(p, col)
247
247
  if p.klass.ancestors.include?(Integer)
248
- return "res[#{col} + offset].to_i"
248
+ return "#{self.class}.parse_int(res[#{col} + offset])"
249
249
  elsif p.klass.ancestors.include?(Float)
250
- return "res[#{col} + offset].to_f"
250
+ return "#{self.class}.parse_float(res[#{col} + offset])"
251
251
  elsif p.klass.ancestors.include?(String)
252
252
  return "res[#{col} + offset]"
253
253
  elsif p.klass.ancestors.include?(Time)
data/lib/og/store/psql.rb CHANGED
@@ -79,6 +79,14 @@ class PsqlStore < SqlStore
79
79
  options[:user].to_s,
80
80
  options[:password].to_s
81
81
  )
82
+
83
+ schema_order = options[:schema_order]
84
+ encoding = options[:encoding]
85
+ min_messages = options[:min_messages]
86
+
87
+ @conn.exec("SET search_path TO #{schema_order}") if schema_order
88
+ @conn.exec("SET client_encoding TO '#{encoding}'") if encoding
89
+ @conn.exec("SET client_min_messages TO '#{min_messages}'") if min_messages
82
90
  rescue => ex
83
91
  # gmosx: any idea how to better test this?
84
92
  if ex.to_s =~ /database .* does not exist/i
@@ -117,9 +125,9 @@ class PsqlStore < SqlStore
117
125
  private
118
126
 
119
127
  def create_table(klass)
120
- columns = columns_for_class(klass)
128
+ fields = fields_for_class(klass)
121
129
 
122
- sql = "CREATE TABLE #{klass::OGTABLE} (#{columns.join(', ')}"
130
+ sql = "CREATE TABLE #{klass::OGTABLE} (#{fields.join(', ')}"
123
131
 
124
132
  # Create table constrains.
125
133
 
@@ -180,12 +188,12 @@ private
180
188
  exec "DROP SEQUENCE #{klass::OGSEQ}"
181
189
  end
182
190
 
183
- def create_column_map(klass)
191
+ def create_field_map(klass)
184
192
  res = @conn.exec "SELECT * FROM #{klass::OGTABLE} LIMIT 1"
185
193
  map = {}
186
194
 
187
- for column in res.fields
188
- map[column.intern] = res.fieldnum(column)
195
+ for field in res.fields
196
+ map[field.intern] = res.fieldnum(field)
189
197
  end
190
198
 
191
199
  return map
@@ -195,9 +203,9 @@ private
195
203
 
196
204
  def read_prop(p, col)
197
205
  if p.klass.ancestors.include?(Integer)
198
- return "res.getvalue(row, #{col} + offset).to_i"
206
+ return "#{self.class}.parse_int(res.getvalue(row, #{col} + offset))"
199
207
  elsif p.klass.ancestors.include?(Float)
200
- return "res.getvalue(row, #{col} + offset).to_f"
208
+ return "#{self.class}.parse_float(res.getvalue(row, #{col} + offset))"
201
209
  elsif p.klass.ancestors.include?(String)
202
210
  return "res.getvalue(row, #{col} + offset)"
203
211
  elsif p.klass.ancestors.include?(Time)
data/lib/og/store/sql.rb CHANGED
@@ -30,6 +30,20 @@ module SqlUtils
30
30
  return nil unless date
31
31
  return "#{date.year}-#{date.month}-#{date.mday}"
32
32
  end
33
+
34
+ # Parse an integer.
35
+
36
+ def parse_int(int)
37
+ int = int.to_i if int
38
+ int
39
+ end
40
+
41
+ # Parse a float.
42
+
43
+ def parse_float(fl)
44
+ fl = fl.to_f if fl
45
+ fl
46
+ end
33
47
 
34
48
  # Parse sql datetime
35
49
  #--
@@ -246,7 +260,18 @@ class SqlStore < Store
246
260
 
247
261
  exec "INSERT INTO #{table} (key1, key2) VALUES (#{obj1.pk}, #{obj2.pk})"
248
262
  end
249
-
263
+
264
+ # Unrelate two objects be removing their relation from the
265
+ # join table.
266
+
267
+ def unjoin(obj1, obj2, table)
268
+ if obj1.class.to_s > obj2.class.to_s
269
+ obj1, obj2 = obj2, obj1
270
+ end
271
+
272
+ exec "DELETE FROM #{table} WHERE key1=#{obj1.pk} AND key2=#{obj2.pk}"
273
+ end
274
+
250
275
  # :section: Transaction methods.
251
276
 
252
277
  # Start a new transaction.
@@ -280,42 +305,42 @@ private
280
305
  exec "DROP TABLE #{klass.table}"
281
306
  end
282
307
 
283
- # Create the columns that correpsond to the klass properties.
284
- # The generated columns array is used in create_table.
308
+ # Create the fields that correpsond to the klass properties.
309
+ # The generated fields array is used in create_table.
285
310
  # If the property has an :sql metadata this overrides the
286
311
  # default mapping. If the property has an :extra_sql metadata
287
312
  # the extra sql is appended after the default mapping.
288
313
 
289
- def columns_for_class(klass)
290
- columns = []
314
+ def fields_for_class(klass)
315
+ fields = []
291
316
 
292
- klass.__props.each do |p|
317
+ klass.properties.each do |p|
293
318
  klass.index(p.symbol) if p.meta[:index]
294
319
 
295
- column = p.symbol.to_s
320
+ field = p.symbol.to_s
296
321
 
297
322
  if p.meta and p.meta[:sql]
298
- column << " #{p.meta[:sql]}"
323
+ field << " #{p.meta[:sql]}"
299
324
  else
300
- column << " #{type_for_class(p.klass)}"
325
+ field << " #{type_for_class(p.klass)}"
301
326
 
302
327
  if p.meta
303
328
  if default = p.meta[:default]
304
- column << " DEFAULT #{default.inspect} NOT NULL"
329
+ field << " DEFAULT #{default.inspect} NOT NULL"
305
330
  end
306
331
 
307
- column << " UNIQUE" if p.meta[:unique]
332
+ field << " UNIQUE" if p.meta[:unique]
308
333
 
309
334
  if extra_sql = p.meta[:extra_sql]
310
- column << " #{extra_sql}"
335
+ field << " #{extra_sql}"
311
336
  end
312
337
  end
313
338
  end
314
339
 
315
- columns << column
340
+ fields << field
316
341
  end
317
342
 
318
- return columns
343
+ return fields
319
344
  end
320
345
 
321
346
  def type_for_class(klass)
@@ -354,9 +379,9 @@ private
354
379
 
355
380
  def read_prop(p, col)
356
381
  if p.klass.ancestors.include?(Integer)
357
- return "res[#{col} + offset].to_i"
382
+ return "#{self.class}.parse_int(res[#{col} + offset])"
358
383
  elsif p.klass.ancestors.include?(Float)
359
- return "res[#{col} + offset].to_f"
384
+ return "#{self.class}.parse_float(res[#{col} + offset])"
360
385
  elsif p.klass.ancestors.include?(String)
361
386
  return "res[#{col} + offset]"
362
387
  elsif p.klass.ancestors.include?(Time)
@@ -413,16 +438,16 @@ private
413
438
 
414
439
  # Compile the og_read method for the class. This method is
415
440
  # used to read (deserialize) the given class from the store.
416
- # In order to allow for changing column/attribute orders a
417
- # column mapping hash is used.
441
+ # In order to allow for changing field/attribute orders a
442
+ # field mapping hash is used.
418
443
 
419
444
  def eval_og_read(klass)
420
445
  code = []
421
446
  props = klass.properties
422
- column_map = create_column_map(klass)
447
+ field_map = create_field_map(klass)
423
448
 
424
449
  props.each do |p|
425
- if col = column_map[p.symbol]
450
+ if col = field_map[p.symbol]
426
451
  code << "@#{p.symbol} = #{read_prop(p, col)}"
427
452
  end
428
453
  end
@@ -487,7 +512,7 @@ private
487
512
  end
488
513
  end
489
514
 
490
- columns = tables.collect { |t| "#{t}.*" }.join(',')
515
+ fields = tables.collect { |t| "#{t}.*" }.join(',')
491
516
 
492
517
  if options[:condition]
493
518
  options[:condition] += " AND #{join_conditions.join(' AND ')}"
@@ -495,7 +520,7 @@ private
495
520
  options[:condition] = join_conditions.join(' AND ')
496
521
  end
497
522
  else
498
- columns = '*'
523
+ fields = '*'
499
524
  end
500
525
 
501
526
  if join_table = options[:join_table]
@@ -507,7 +532,7 @@ private
507
532
  end
508
533
  end
509
534
 
510
- sql = "SELECT #{columns} FROM #{tables.join(',')}"
535
+ sql = "SELECT #{fields} FROM #{tables.join(',')}"
511
536
 
512
537
  if condition = options[:condition] || options[:where]
513
538
  sql << " WHERE #{condition}"
@@ -597,3 +622,5 @@ private
597
622
  end
598
623
 
599
624
  end
625
+
626
+ # * George Moschovitis <gm@navel.gr>
@@ -9,13 +9,11 @@ require 'fileutils'
9
9
 
10
10
  require 'og/store/sql'
11
11
 
12
- # Customize the standard postgres resultset to make
12
+ # Customize the standard Sqlite3 resultset to make
13
13
  # more compatible with Og.
14
14
 
15
15
  class SQLite3::ResultSet
16
- def blank?
17
- false
18
- end
16
+ alias_method :blank?, :eof?
19
17
 
20
18
  def each_row
21
19
  each do |row|
@@ -38,9 +36,15 @@ module Og
38
36
 
39
37
  class SqliteStore < SqlStore
40
38
 
39
+ # Override if needed.
40
+
41
+ def self.db_filename(options)
42
+ "#{options[:name]}.db"
43
+ end
44
+
41
45
  def self.destroy(options)
42
46
  begin
43
- FileUtils.rm("#{options[:name]}.db")
47
+ FileUtils.rm(db_filename(options))
44
48
  super
45
49
  rescue Object
46
50
  Logger.info "Cannot drop '#{options[:name]}'!"
@@ -49,7 +53,7 @@ class SqliteStore < SqlStore
49
53
 
50
54
  def initialize(options)
51
55
  super
52
- @conn = SQLite3::Database.new("#{options[:name]}.db")
56
+ @conn = SQLite3::Database.new(self.class.db_filename(options))
53
57
  end
54
58
 
55
59
  def close
@@ -95,9 +99,9 @@ class SqliteStore < SqlStore
95
99
  private
96
100
 
97
101
  def create_table(klass)
98
- columns = columns_for_class(klass)
102
+ fields = fields_for_class(klass)
99
103
 
100
- sql = "CREATE TABLE #{klass::OGTABLE} (#{columns.join(', ')}"
104
+ sql = "CREATE TABLE #{klass::OGTABLE} (#{fields.join(', ')}"
101
105
 
102
106
  # Create table constrains.
103
107
 
@@ -153,14 +157,14 @@ private
153
157
  end
154
158
  end
155
159
 
156
- def create_column_map(klass)
160
+ def create_field_map(klass)
157
161
  res = @conn.query "SELECT * FROM #{klass::OGTABLE} LIMIT 1"
158
162
  map = {}
159
163
 
160
- columns = res.columns
164
+ fields = res.fields
161
165
 
162
- columns.size.times do |i|
163
- map[columns[i].intern] = i
166
+ fields.size.times do |i|
167
+ map[fields[i].intern] = i
164
168
  end
165
169
 
166
170
  return map
@@ -1,3 +1,7 @@
1
+ # WARNING:
2
+ # This store is not converted to the latest Og codebase.
3
+ # DO NOT USE YET!
4
+
1
5
  begin
2
6
  require 'dbi'
3
7
  rescue Object => ex
@@ -121,9 +125,9 @@ class SqlserverStore < SqlStore
121
125
  private
122
126
 
123
127
  def create_table(klass)
124
- columns = columns_for_class(klass)
128
+ fields = fields_for_class(klass)
125
129
 
126
- sql = "CREATE TABLE #{klass::OGTABLE} (#{columns.join(', ')}"
130
+ sql = "CREATE TABLE #{klass::OGTABLE} (#{fields.join(', ')}"
127
131
 
128
132
  # Create table constrains.
129
133
 
@@ -189,7 +193,7 @@ private
189
193
  =end
190
194
  end
191
195
 
192
- def create_column_map(klass)
196
+ def create_field_map(klass)
193
197
  conn.query_with_result = true
194
198
  res = @conn.query "SELECT * FROM #{klass::OGTABLE} LIMIT 1"
195
199
  map = {}
data/test/og/tc_store.rb CHANGED
@@ -64,20 +64,33 @@ class TCOgStore < Test::Unit::TestCase # :nodoc: all
64
64
  @og.store.class.destroy(@og.options)
65
65
  @og = nil
66
66
  end
67
-
67
+
68
68
  =begin
69
+ def test_kirby
70
+ @og = Og.setup(
71
+ :destroy => true,
72
+ :store => :kirby,
73
+ :name => 'test',
74
+ :embedded => true
75
+ )
76
+ features_test
77
+ # conversions_test
78
+ end
79
+ =end
80
+ #=begin
69
81
  def test_psql
70
82
  @og = Og.setup(
71
83
  :destroy => true,
72
84
  :store => :psql,
73
85
  :name => 'test',
86
+ :min_messages => 'ERROR',
74
87
  :user => 'postgres',
75
88
  :password => 'navelrulez'
76
89
  )
77
90
  features_test
78
91
  conversions_test
79
92
  end
80
- =end
93
+ #=end
81
94
  =begin
82
95
  def test_mysql
83
96
  @og = Og.setup(
@@ -91,7 +104,7 @@ class TCOgStore < Test::Unit::TestCase # :nodoc: all
91
104
  # conversions_test
92
105
  end
93
106
  =end
94
- #=begin
107
+ =begin
95
108
  def test_sqlite
96
109
  @og = Og.setup(
97
110
  :destroy => true,
@@ -101,7 +114,7 @@ class TCOgStore < Test::Unit::TestCase # :nodoc: all
101
114
  features_test
102
115
  conversions_test
103
116
  end
104
- #=end
117
+ =end
105
118
  =begin
106
119
  def test_memory
107
120
  @og = Og.setup(
@@ -134,7 +147,7 @@ class TCOgStore < Test::Unit::TestCase # :nodoc: all
134
147
  @og.store.delete(a3)
135
148
 
136
149
  assert @og.store.load(1, Article)
137
- # assert !Article[2]
150
+ assert !Article[2]
138
151
  assert Article.load(1)
139
152
 
140
153
  a2.delete
@@ -220,7 +233,7 @@ class TCOgStore < Test::Unit::TestCase # :nodoc: all
220
233
 
221
234
  assert_equal 3, @og.store.count(:class => Comment)
222
235
 
223
- a4.comments.clear
236
+ a4.comments.delete_all
224
237
  assert_equal 0, a4.comments.size
225
238
 
226
239
  # has_one