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.
- 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
|