og 0.17.0 → 0.18.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.
@@ -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