swift 0.14.0 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/API.rdoc +14 -14
- data/README.md +110 -61
- data/Rakefile +2 -5
- data/VERSION +1 -1
- data/lib/swift/adapter/mysql.rb +30 -0
- data/lib/swift/adapter/postgres.rb +27 -0
- data/lib/swift/adapter/sql.rb +23 -29
- data/lib/swift/adapter/sqlite3.rb +59 -0
- data/lib/swift/adapter.rb +129 -70
- data/lib/swift/attribute.rb +19 -8
- data/lib/swift/eventmachine.rb +49 -0
- data/lib/swift/identity_map.rb +7 -7
- data/lib/swift/migrations.rb +12 -12
- data/lib/swift/{scheme.rb → record.rb} +16 -17
- data/lib/swift/result.rb +24 -0
- data/lib/swift/statement.rb +25 -0
- data/lib/swift/synchrony.rb +38 -0
- data/lib/swift/validations.rb +2 -2
- data/lib/swift.rb +8 -6
- data/swift.gemspec +19 -31
- data/test/helper.rb +11 -6
- data/test/test_adapter.rb +11 -25
- data/test/test_async.rb +9 -12
- data/test/test_encoding.rb +2 -2
- data/test/test_error.rb +8 -8
- data/test/test_io.rb +2 -2
- data/test/{test_scheme.rb → test_record.rb} +6 -6
- data/test/test_swift.rb +9 -51
- data/test/test_timestamps.rb +1 -1
- data/test/test_transactions.rb +2 -2
- data/test/test_types.rb +3 -3
- data/test/test_validations.rb +2 -2
- metadata +20 -27
- data/ext/adapter.cc +0 -479
- data/ext/adapter.h +0 -13
- data/ext/adapter_io.cc +0 -62
- data/ext/adapter_io.h +0 -24
- data/ext/attribute.cc +0 -22
- data/ext/attribute.h +0 -8
- data/ext/datetime.cc +0 -96
- data/ext/datetime.h +0 -12
- data/ext/extconf.rb +0 -61
- data/ext/query.cc +0 -104
- data/ext/query.h +0 -20
- data/ext/result.cc +0 -229
- data/ext/result.h +0 -27
- data/ext/statement.cc +0 -116
- data/ext/statement.h +0 -22
- data/ext/swift.cc +0 -114
- data/ext/swift.h +0 -60
- 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 #=> [
|
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 #=>
|
18
|
+
#create #=> Record or Result
|
19
19
|
#delete #=> Result
|
20
20
|
#execute #=> Result
|
21
21
|
#async_execute #=> Result
|
22
|
-
#get #=>
|
22
|
+
#get #=> Record
|
23
23
|
#prepare #=> Statement
|
24
24
|
#rollback
|
25
25
|
#transaction #=> Adapter
|
26
|
-
#update #=>
|
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
|
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
|
-
|
49
|
+
Record
|
50
50
|
.attribute #=> Type
|
51
|
-
.create #=>
|
52
|
-
.get #=>
|
51
|
+
.create #=> Record or Result
|
52
|
+
.get #=> Record
|
53
53
|
.header #=> Header
|
54
|
-
.load #=>
|
55
|
-
.new #=>
|
54
|
+
.load #=> Record
|
55
|
+
.new #=> Record
|
56
56
|
.store #=> Symbol
|
57
57
|
#execute #=> Result
|
58
58
|
#prepare #=> Statement
|
59
|
-
#
|
59
|
+
#record #=> Alias for self.class
|
60
60
|
#tuple #=> Hash
|
61
|
-
#update #=>
|
61
|
+
#update #=> Record or Result
|
62
62
|
|
63
|
-
# Enumerable collection of Types for
|
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
|
-
#
|
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
|
-
*
|
14
|
-
*
|
15
|
-
|
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::
|
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
|
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::
|
85
|
+
Swift.setup :default, Swift::Adapter::Postgres, db: 'swift'
|
76
86
|
|
77
|
-
class User < Swift::
|
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
|
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
|
-
###
|
111
|
+
### Record CRUD
|
102
112
|
|
103
|
-
|
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::
|
120
|
+
Swift.setup :default, Swift::Adapter::Postgres, db: 'swift'
|
111
121
|
|
112
|
-
class User < Swift::
|
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::
|
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::
|
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::
|
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::
|
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
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
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
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
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
|
-
|
288
|
-
|
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
|
304
|
-
|
305
|
-
ar #
|
306
|
-
ar #
|
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
|
309
|
-
dm #select
|
310
|
-
dm #update
|
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
|
313
|
-
sequel #select
|
314
|
-
sequel #update
|
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
|
317
|
-
swift #select
|
318
|
-
swift #update
|
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.
|
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
|
32
|
+
yard.files = Dir["lib/**/*.rb"].reject {|file| %r{eventmachine|synchrony}.match(file)}
|
35
33
|
end
|
36
|
-
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
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
|
data/lib/swift/adapter/sql.rb
CHANGED
@@ -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.
|
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
|
25
|
-
|
26
|
-
|
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
|
37
|
-
|
38
|
-
|
39
|
-
|
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
|
45
|
-
|
46
|
-
|
47
|
-
|
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
|
53
|
-
|
54
|
-
|
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
|