swift 0.14.0 → 1.0.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.
Files changed (51) hide show
  1. data/API.rdoc +14 -14
  2. data/README.md +110 -61
  3. data/Rakefile +2 -5
  4. data/VERSION +1 -1
  5. data/lib/swift/adapter/mysql.rb +30 -0
  6. data/lib/swift/adapter/postgres.rb +27 -0
  7. data/lib/swift/adapter/sql.rb +23 -29
  8. data/lib/swift/adapter/sqlite3.rb +59 -0
  9. data/lib/swift/adapter.rb +129 -70
  10. data/lib/swift/attribute.rb +19 -8
  11. data/lib/swift/eventmachine.rb +49 -0
  12. data/lib/swift/identity_map.rb +7 -7
  13. data/lib/swift/migrations.rb +12 -12
  14. data/lib/swift/{scheme.rb → record.rb} +16 -17
  15. data/lib/swift/result.rb +24 -0
  16. data/lib/swift/statement.rb +25 -0
  17. data/lib/swift/synchrony.rb +38 -0
  18. data/lib/swift/validations.rb +2 -2
  19. data/lib/swift.rb +8 -6
  20. data/swift.gemspec +19 -31
  21. data/test/helper.rb +11 -6
  22. data/test/test_adapter.rb +11 -25
  23. data/test/test_async.rb +9 -12
  24. data/test/test_encoding.rb +2 -2
  25. data/test/test_error.rb +8 -8
  26. data/test/test_io.rb +2 -2
  27. data/test/{test_scheme.rb → test_record.rb} +6 -6
  28. data/test/test_swift.rb +9 -51
  29. data/test/test_timestamps.rb +1 -1
  30. data/test/test_transactions.rb +2 -2
  31. data/test/test_types.rb +3 -3
  32. data/test/test_validations.rb +2 -2
  33. metadata +20 -27
  34. data/ext/adapter.cc +0 -479
  35. data/ext/adapter.h +0 -13
  36. data/ext/adapter_io.cc +0 -62
  37. data/ext/adapter_io.h +0 -24
  38. data/ext/attribute.cc +0 -22
  39. data/ext/attribute.h +0 -8
  40. data/ext/datetime.cc +0 -96
  41. data/ext/datetime.h +0 -12
  42. data/ext/extconf.rb +0 -61
  43. data/ext/query.cc +0 -104
  44. data/ext/query.h +0 -20
  45. data/ext/result.cc +0 -229
  46. data/ext/result.h +0 -27
  47. data/ext/statement.cc +0 -116
  48. data/ext/statement.h +0 -22
  49. data/ext/swift.cc +0 -114
  50. data/ext/swift.h +0 -60
  51. data/lib/swift/db.rb +0 -89
data/API.rdoc CHANGED
@@ -7,7 +7,7 @@ Public API minus the optional stuff like Pool, IdentityMap, Migrations etc.
7
7
  Swift
8
8
  .setup #=> Adapter
9
9
  .db #=> Adapter
10
- .schema #=> [Scheme, ...]
10
+ .schema #=> [Record, ...]
11
11
  .trace
12
12
 
13
13
  # Abstract.
@@ -15,15 +15,15 @@ Public API minus the optional stuff like Pool, IdentityMap, Migrations etc.
15
15
  .new #=> Adapter
16
16
  #begin #=> Adapter
17
17
  #commit
18
- #create #=> Scheme or Result
18
+ #create #=> Record or Result
19
19
  #delete #=> Result
20
20
  #execute #=> Result
21
21
  #async_execute #=> Result
22
- #get #=> Scheme
22
+ #get #=> Record
23
23
  #prepare #=> Statement
24
24
  #rollback
25
25
  #transaction #=> Adapter
26
- #update #=> Scheme or Result
26
+ #update #=> Record or Result
27
27
  #reconnect
28
28
 
29
29
  # Concrete.
@@ -32,7 +32,7 @@ Public API minus the optional stuff like Pool, IdentityMap, Migrations etc.
32
32
  Postgres < Adapter::Sql
33
33
  Sqlite3 < Adapter::Sql
34
34
 
35
- # Enumerable collection of Scheme or Hash tuples.
35
+ # Enumerable collection of Record or Hash tuples.
36
36
  Result
37
37
  .new #=> Result
38
38
  #insert_id #=> Numeric
@@ -46,21 +46,21 @@ Public API minus the optional stuff like Pool, IdentityMap, Migrations etc.
46
46
  #execute #=> Result
47
47
  #command #=> String # The SQL command executed or to be executed
48
48
 
49
- Scheme
49
+ Record
50
50
  .attribute #=> Type
51
- .create #=> Scheme or Result
52
- .get #=> Scheme
51
+ .create #=> Record or Result
52
+ .get #=> Record
53
53
  .header #=> Header
54
- .load #=> Scheme
55
- .new #=> Scheme
54
+ .load #=> Record
55
+ .new #=> Record
56
56
  .store #=> Symbol
57
57
  #execute #=> Result
58
58
  #prepare #=> Statement
59
- #scheme #=> Alias for self.class
59
+ #record #=> Alias for self.class
60
60
  #tuple #=> Hash
61
- #update #=> Scheme or Result
61
+ #update #=> Record or Result
62
62
 
63
- # Enumerable collection of Types for Scheme.
63
+ # Enumerable collection of Types for Record.
64
64
  Header
65
65
  .new #=> Header
66
66
  #all #=> [Type, ...]
@@ -79,7 +79,7 @@ Public API minus the optional stuff like Pool, IdentityMap, Migrations etc.
79
79
  #key #=> true or false
80
80
  #serial #=> Symbol or nil
81
81
  #default #=> Object
82
- #define_scheme_methods
82
+ #define_record_methods
83
83
 
84
84
  # Concrete.
85
85
  Type
data/README.md CHANGED
@@ -10,9 +10,26 @@ A rational rudimentary object relational mapper.
10
10
 
11
11
  ## Dependencies
12
12
 
13
- * ruby >= 1.9.1
14
- * [dbic++](http://github.com/deepfryed/dbicpp) >= 0.6.0
15
- * mysql >= 5.0.17, postgresql >= 8.4 or sqlite3 >= 3.7
13
+ * MRI Ruby >= 1.9.1
14
+ * swift-db-sqlite3 or swift-db-postgres or swift-db-mysql
15
+
16
+ ## Installation
17
+
18
+ ### Dependencies
19
+
20
+ Install one of the following drivers you would like to use.
21
+
22
+ ```
23
+ gem install swift-db-sqlite3
24
+ gem install swift-db-postgres
25
+ gem install swift-db-mysql
26
+ ```
27
+
28
+ ### Install Swift
29
+
30
+ ```
31
+ gem install swift
32
+ ```
16
33
 
17
34
  ## Features
18
35
 
@@ -24,20 +41,13 @@ A rational rudimentary object relational mapper.
24
41
  * IdentityMap.
25
42
  * Migrations.
26
43
 
27
- ## Performance notes
28
-
29
- 1. The current version creates DateTime objects for timestamp fields and this is roughly 80% slower on
30
- rubies older than 1.9.3.
31
- 2. On rubies older than 1.9.3, Swift will try using [home_run](https://github.com/jeremyevans/home_run)
32
- for performance.
33
-
34
44
  ### DB
35
45
 
36
46
  ```ruby
37
47
  require 'swift'
38
48
 
39
49
  Swift.trace true # Debugging.
40
- Swift.setup :default, Swift::DB::Postgres, db: 'swift'
50
+ Swift.setup :default, Swift::Adapter::Postgres, db: 'swift'
41
51
 
42
52
  # Block form db context.
43
53
  Swift.db do |db|
@@ -62,7 +72,7 @@ A rational rudimentary object relational mapper.
62
72
  end
63
73
  ```
64
74
 
65
- ### DB Scheme Operations
75
+ ### DB Record Operations
66
76
 
67
77
  Rudimentary object mapping. Provides a definition to the db methods for prepared (and cached) statements plus native
68
78
  primitive Ruby type conversion.
@@ -72,9 +82,9 @@ primitive Ruby type conversion.
72
82
  require 'swift/migrations'
73
83
 
74
84
  Swift.trace true # Debugging.
75
- Swift.setup :default, Swift::DB::Postgres, db: 'swift'
85
+ Swift.setup :default, Swift::Adapter::Postgres, db: 'swift'
76
86
 
77
- class User < Swift::Scheme
87
+ class User < Swift::Record
78
88
  store :users
79
89
  attribute :id, Swift::Type::Integer, serial: true, key: true
80
90
  attribute :name, Swift::Type::String
@@ -85,7 +95,7 @@ primitive Ruby type conversion.
85
95
  Swift.db do |db|
86
96
  db.migrate! User
87
97
 
88
- # Select Scheme instance (relation) instead of Hash.
98
+ # Select Record instance (relation) instead of Hash.
89
99
  users = db.prepare(User, 'select * from users limit 1').execute
90
100
 
91
101
  # Make a change and update.
@@ -98,18 +108,18 @@ primitive Ruby type conversion.
98
108
  end
99
109
  ```
100
110
 
101
- ### Scheme CRUD
111
+ ### Record CRUD
102
112
 
103
- Scheme/relation level helpers.
113
+ Record/relation level helpers.
104
114
 
105
115
  ```ruby
106
116
  require 'swift'
107
117
  require 'swift/migrations'
108
118
 
109
119
  Swift.trace true # Debugging.
110
- Swift.setup :default, Swift::DB::Postgres, db: 'swift'
120
+ Swift.setup :default, Swift::Adapter::Postgres, db: 'swift'
111
121
 
112
- class User < Swift::Scheme
122
+ class User < Swift::Record
113
123
  store :users
114
124
  attribute :id, Swift::Type::Integer, serial: true, key: true
115
125
  attribute :name, Swift::Type::String
@@ -142,7 +152,7 @@ SQL is easy and most people know it so Swift ORM provides simple #to_s
142
152
  attribute to table and field name typecasting.
143
153
 
144
154
  ```ruby
145
- class User < Swift::Scheme
155
+ class User < Swift::Record
146
156
  store :users
147
157
  attribute :id, Swift::Type::Integer, serial: true, key: true
148
158
  attribute :age, Swift::Type::Integer, field: 'ega'
@@ -167,7 +177,7 @@ Swift comes with a simple identity map. Just require it after you load swift.
167
177
  require 'swift/identity_map'
168
178
  require 'swift/migrations'
169
179
 
170
- class User < Swift::Scheme
180
+ class User < Swift::Record
171
181
  store :users
172
182
  attribute :id, Swift::Type::Integer, serial: true, key: true
173
183
  attribute :age, Swift::Type::Integer, field: 'ega'
@@ -204,7 +214,7 @@ But you can do it almost as fast in ruby,
204
214
  ```ruby
205
215
  require 'swift'
206
216
 
207
- Swift.setup :default, Swift::DB::Mysql, db: 'swift'
217
+ Swift.setup :default, Swift::Adapter::Mysql, db: 'swift'
208
218
 
209
219
  # MySQL packet size is the usual limit, 8k is the packet size by default.
210
220
  Swift.db do |db|
@@ -226,7 +236,7 @@ which implicitly uses `rb_thread_wait_fd`
226
236
  ```ruby
227
237
  require 'swift'
228
238
 
229
- pool = 3.times.map.with_index {|n| Swift.setup n, Swift::DB::Postgres, db: 'swift' }
239
+ pool = 3.times.map.with_index {|n| Swift.setup n, Swift::Adapter::Postgres, db: 'swift' }
230
240
 
231
241
  Thread.new do
232
242
  pool[0].async_execute('select pg_sleep(3), 1 as qid') {|row| p row}
@@ -243,31 +253,43 @@ which implicitly uses `rb_thread_wait_fd`
243
253
  Thread.list.reject {|thread| Thread.current == thread}.each(&:join)
244
254
  ```
245
255
 
256
+ or use the `swift/eventmachine` api.
257
+
246
258
  ```ruby
247
- require 'swift'
248
- require 'eventmachine'
249
-
250
- pool = 3.times.map.with_index {|n| Swift.setup n, Swift::DB::Postgres, db: 'swift'}
251
-
252
- module Handler
253
- attr_reader :result
254
-
255
- def initialize result
256
- @result = result
257
- end
258
-
259
- def notify_readable
260
- result.retrieve
261
- result.each {|row| p row }
262
- unbind
259
+ require 'swift/eventmachine'
260
+
261
+ EM.run do
262
+ pool = 3.times.map { Swift.setup(:default, Swift::Adapter::Postgres, db: "swift") }
263
+
264
+ 3.times.each do |n|
265
+ defer = pool[n].execute("select pg_sleep(3 - #{n}), #{n + 1} as qid")
266
+
267
+ defer.callback do |res|
268
+ p res.first
269
+ end
270
+
271
+ defer.errback do |e|
272
+ p 'error', e
273
+ end
263
274
  end
264
275
  end
265
-
276
+ ```
277
+
278
+ or use the `em-synchrony` api for `swift`
279
+
280
+ ```ruby
281
+ require 'swift/synchrony'
282
+
266
283
  EM.run do
267
- EM.watch(pool[0].fileno, Handler, pool[0].async_execute('select pg_sleep(3), 1 as qid')){|c| c.notify_readable = true}
268
- EM.watch(pool[1].fileno, Handler, pool[1].async_execute('select pg_sleep(2), 2 as qid')){|c| c.notify_readable = true}
269
- EM.watch(pool[2].fileno, Handler, pool[2].async_execute('select pg_sleep(1), 3 as qid')){|c| c.notify_readable = true}
270
- EM.add_timer(4) { EM.stop }
284
+ 3.times.each do |n|
285
+ EM.synchrony do
286
+ db = Swift.setup(:default, Swift::Adapter::Postgres, db: "swift")
287
+ result = db.execute("select pg_sleep(3 - #{n}), #{n + 1} as qid")
288
+
289
+ p result.first
290
+ EM.stop if n == 0
291
+ end
292
+ end
271
293
  end
272
294
  ```
273
295
 
@@ -284,8 +306,35 @@ http://github.com/shanna/swift/tree/master/benchmarks
284
306
 
285
307
  The test environment:
286
308
 
287
- * ruby 1.9.3p0
288
- * Intel Core2Duo P8700 2.53GHz, 4G RAM and Kingston SATA2 SSD
309
+ ```
310
+ $ uname -a
311
+
312
+ Linux deepfryed.local 3.0.0-1-amd64 #1 SMP Sun Jul 24 02:24:44 UTC 2011 x86_64 GNU/Linux
313
+
314
+ $ cat /proc/cpuinfo | grep "processor\|model name"
315
+
316
+ processor : 0
317
+ model name : Intel(R) Core(TM) i7-2677M CPU @ 1.80GHz
318
+ processor : 1
319
+ model name : Intel(R) Core(TM) i7-2677M CPU @ 1.80GHz
320
+ processor : 2
321
+ model name : Intel(R) Core(TM) i7-2677M CPU @ 1.80GHz
322
+ processor : 3
323
+ model name : Intel(R) Core(TM) i7-2677M CPU @ 1.80GHz
324
+
325
+ $ ruby -v
326
+
327
+ ruby 1.9.3p125 (2012-02-16 revision 34643) [x86_64-linux]
328
+ ```
329
+
330
+ PostgreSQL config:
331
+
332
+ ```
333
+ shared_buffers = 800MB # min 128kB
334
+ effective_cache_size = 512MB
335
+ work_mem = 64MB # min 64kB
336
+ maintenance_work_mem = 64MB # min 1MB
337
+ ```
289
338
 
290
339
  The test setup:
291
340
 
@@ -300,25 +349,25 @@ The test setup:
300
349
  ```
301
350
  ./simple.rb -n1 -r10000 -s ar -s dm -s sequel -s swift
302
351
 
303
- benchmark sys user total real rss
304
- ar #create 0.75 7.18 7.93 10.5043 366.95m
305
- ar #select 0.07 0.26 0.33 0.3680 40.71m
306
- ar #update 0.96 7.92 8.88 11.7537 436.38m
352
+ benchmark sys user total real rss
353
+
354
+ ar #create 1.960000 15.81000 17.770000 22.753109 266.21m
355
+ ar #select 0.020000 0.38000 0.400000 0.433041 50.82m
356
+ ar #update 2.000000 17.90000 19.900000 26.674921 317.48m
307
357
 
308
- dm #create 0.33 3.73 4.06 5.0908 245.68m
309
- dm #select 0.08 1.51 1.59 1.6154 87.95m
310
- dm #update 0.44 7.09 7.53 8.8685 502.77m
358
+ dm #create 0.660000 11.55000 12.210000 15.592424 236.86m
359
+ dm #select 0.030000 1.30000 1.330000 1.351911 87.18m
360
+ dm #update 0.950000 17.25000 18.200000 22.109859 474.81m
311
361
 
312
- sequel #create 0.60 5.07 5.67 7.9804 236.69m
313
- sequel #select 0.02 0.12 0.14 0.1778 12.75m
314
- sequel #update 0.82 4.95 5.77 8.2062 230.00m
362
+ sequel #create 1.960000 14.48000 16.440000 23.004864 226.68m
363
+ sequel #select 0.000000 0.09000 0.090000 0.134619 12.77m
364
+ sequel #update 1.900000 14.37000 16.270000 22.945636 200.20m
315
365
 
316
- swift #create 0.27 0.59 0.86 1.5085 84.85m
317
- swift #select 0.03 0.06 0.09 0.1037 11.24m
318
- swift #update 0.20 0.69 0.89 1.5867 62.19m
366
+ swift #create 0.520000 1.95000 2.470000 5.828846 75.26m
367
+ swift #select 0.010000 0.070000 0.080000 0.095124 11.23m
368
+ swift #update 0.440000 1.95000 2.390000 6.044971 59.35m
369
+ swift #write 0.010000 0.050000 0.060000 0.117195 13.46m
319
370
 
320
- -- bulk insert api --
321
- swift #write 0.04 0.06 0.10 0.1699 14.05m
322
371
  ```
323
372
 
324
373
  ## TODO
data/Rakefile CHANGED
@@ -9,8 +9,7 @@ begin
9
9
  gem.email = %w{shane.hanna@gmail.com deepfryed@gmail.com}
10
10
  gem.homepage = 'http://github.com/shanna/swift'
11
11
  gem.authors = ["Shane Hanna", "Bharanee 'Barney' Rathna"]
12
- gem.extensions = FileList['ext/extconf.rb']
13
- gem.files.reject!{|f| f =~ %r{\.gitignore|examples|benchmarks|memory/.*}}
12
+ gem.files.reject!{|f| f =~ %r{\.gitignore|examples|benchmarks|memory|gems/.*|Gemfile}}
14
13
 
15
14
  gem.add_development_dependency 'minitest', '>= 1.7.0'
16
15
  end
@@ -26,11 +25,9 @@ Rake::TestTask.new(:test) do |test|
26
25
  test.verbose = true
27
26
  end
28
27
 
29
- task :test => :check_dependencies
30
28
  task :default => :test
31
29
 
32
30
  require 'yard'
33
31
  YARD::Rake::YardocTask.new do |yard|
34
- yard.files = ['lib/**/*.rb', 'ext/*.cc']
32
+ yard.files = Dir["lib/**/*.rb"].reject {|file| %r{eventmachine|synchrony}.match(file)}
35
33
  end
36
-
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.14.0
1
+ 1.0.0
@@ -0,0 +1,30 @@
1
+ require 'swift/db/mysql'
2
+ require 'swift/adapter/sql'
3
+
4
+ module Swift
5
+ class Adapter
6
+ class Mysql < Sql
7
+ def initialize options = {}
8
+ super Swift::DB::Mysql.new(options)
9
+ end
10
+
11
+ def returning?
12
+ false
13
+ end
14
+
15
+ # TODO Swift::Type::Bignum ?
16
+ # serial is an alias for bigint in mysql, we want integer type to be migrated as integer
17
+ # type in the database (not bigint or smallint or shortint or whatever).
18
+ def field_type attribute
19
+ case attribute
20
+ when Type::Integer then attribute.serial ? 'integer auto_increment' : 'integer'
21
+ else super
22
+ end
23
+ end
24
+
25
+ def tables
26
+ execute("show tables").map(&:values).flatten
27
+ end
28
+ end # Mysql
29
+ end # Adapter
30
+ end # Swift
@@ -0,0 +1,27 @@
1
+ require 'swift/db/postgres'
2
+ require 'swift/adapter/sql'
3
+
4
+ module Swift
5
+ class Adapter
6
+ class Postgres < Sql
7
+ def initialize options = {}
8
+ super Swift::DB::Postgres.new(options)
9
+ end
10
+
11
+ def returning?
12
+ true
13
+ end
14
+
15
+ def field_type attribute
16
+ case attribute
17
+ when Type::IO then 'bytea'
18
+ else super
19
+ end
20
+ end
21
+
22
+ def tables
23
+ execute('select tablename from pg_tables where schemaname = current_schema').map(&:values).flatten
24
+ end
25
+ end # Postgres
26
+ end # Adapter
27
+ end # Swift
@@ -1,19 +1,26 @@
1
1
  require 'swift/adapter'
2
+ require 'forwardable'
2
3
 
3
4
  module Swift
4
5
  class Adapter
5
-
6
6
  # Abstract SQL Adapter.
7
7
  #
8
8
  # @abstract
9
9
  class Sql < Adapter
10
+ extend Forwardable
11
+ def_delegators :db, :begin, :commit, :rollback, :close, :closed?, :query, :fileno, :result, :write
12
+
10
13
  def tables
11
14
  raise NotImplementedError
12
15
  end
13
16
 
14
17
  def fields table
15
18
  result = execute("select * from #{table} limit 0")
16
- Hash[result.fields.map(&:to_sym).zip(result.field_types)]
19
+ Hash[result.fields.map(&:to_sym).zip(result.types)]
20
+ end
21
+
22
+ def transaction *args
23
+ db.transaction(*args) {|db| yield self}
17
24
  end
18
25
 
19
26
  protected
@@ -21,39 +28,26 @@ module Swift
21
28
  raise NotImplementedError
22
29
  end
23
30
 
24
- def prepare_cached scheme, name, &block
25
- @prepared ||= Hash.new{|h,k| h[k] = Hash.new}
26
- @prepared[scheme][name] ||= prepare(scheme, yield)
27
- end
28
-
29
- def prepare_get scheme
30
- prepare_cached(scheme, :get) do
31
- where = scheme.header.keys.map{|key| "#{key} = ?"}.join(' and ')
32
- "select * from #{scheme.store} where #{where} limit 1"
33
- end
31
+ def command_get record
32
+ where = record.header.keys.map{|key| "#{key} = ?"}.join(' and ')
33
+ "select * from #{record.store} where #{where} limit 1"
34
34
  end
35
35
 
36
- def prepare_create scheme
37
- prepare_cached(scheme, :create) do
38
- values = (['?'] * scheme.header.insertable.size).join(', ')
39
- returning = "returning #{scheme.header.serial}" if scheme.header.serial and returning?
40
- "insert into #{scheme.store} (#{scheme.header.insertable.join(', ')}) values (#{values}) #{returning}"
41
- end
36
+ def command_create record
37
+ values = (['?'] * record.header.insertable.size).join(', ')
38
+ returning = "returning #{record.header.serial}" if record.header.serial and returning?
39
+ "insert into #{record.store} (#{record.header.insertable.join(', ')}) values (#{values}) #{returning}"
42
40
  end
43
41
 
44
- def prepare_update scheme
45
- prepare_cached(scheme, :update) do
46
- set = scheme.header.updatable.map{|field| "#{field} = ?"}.join(', ')
47
- where = scheme.header.keys.map{|key| "#{key} = ?"}.join(' and ')
48
- "update #{scheme.store} set #{set} where #{where}"
49
- end
42
+ def command_update record
43
+ set = record.header.updatable.map{|field| "#{field} = ?"}.join(', ')
44
+ where = record.header.keys.map{|key| "#{key} = ?"}.join(' and ')
45
+ "update #{record.store} set #{set} where #{where}"
50
46
  end
51
47
 
52
- def prepare_delete scheme
53
- prepare_cached(scheme, :delete) do
54
- where = scheme.header.keys.map{|key| "#{key} = ?"}.join(' and ')
55
- "delete from #{scheme.store} where #{where}"
56
- end
48
+ def command_delete record
49
+ where = record.header.keys.map{|key| "#{key} = ?"}.join(' and ')
50
+ "delete from #{record.store} where #{where}"
57
51
  end
58
52
 
59
53
  def field_definition attribute
@@ -0,0 +1,59 @@
1
+ require 'swift/db/sqlite3'
2
+ require 'swift/adapter/sql'
3
+
4
+ module Swift
5
+ class Adapter
6
+ class Sqlite3 < Sql
7
+ def initialize options = {}
8
+ super Swift::DB::Sqlite3.new(options)
9
+ end
10
+
11
+ def returning?
12
+ false
13
+ end
14
+
15
+ def migrate! record
16
+ keys = record.header.keys
17
+ serial = record.header.find(&:serial)
18
+ fields = record.header.map{|p| field_definition(p)}.join(', ')
19
+ fields += ", primary key (#{keys.join(', ')})" unless serial or keys.empty?
20
+
21
+ execute("drop table if exists #{record.store}")
22
+ execute("create table #{record.store} (#{fields})")
23
+ end
24
+
25
+ def field_type attribute
26
+ case attribute
27
+ when Type::String then 'text'
28
+ when Type::Integer then attribute.serial ? 'integer primary key' : 'integer'
29
+ when Type::Float then 'float'
30
+ when Type::BigDecimal then 'numeric'
31
+ when Type::Time then 'timestamp' # deprecated
32
+ when Type::DateTime then 'timestamp'
33
+ when Type::Date then 'date'
34
+ when Type::Boolean then 'boolean'
35
+ when Type::IO then 'blob'
36
+ else 'text'
37
+ end
38
+ end
39
+
40
+ def tables
41
+ execute('select name from sqlite_master where type = ?', 'table').map(&:values).flatten
42
+ end
43
+
44
+ def write table, fields = nil, io
45
+ fields = execute("select * from #{table} limit 0").fields if fields.nil? or fields.empty?
46
+ statement = prepare("insert into #{table}(#{fields.join(',')}) values (%s)" % (['?'] * fields.size).join(','))
47
+
48
+ r = 0
49
+ io = io.read if io.respond_to?(:read)
50
+ io.split(/\n+/).each do |line|
51
+ r += statement.execute(*line.split(/\t/).map {|value| value == '\N' ? nil : value}).affected_rows
52
+ end
53
+
54
+ # TODO: a better way to return a pretend result
55
+ Struct.new(:affected_rows).new(r)
56
+ end
57
+ end # Sqlite3
58
+ end # Adapter
59
+ end # Swift