swift 0.10.0 → 0.11.0

Sign up to get free protection for your applications and to get access to all the features.
data/API.rdoc CHANGED
@@ -13,29 +13,23 @@ Public API minus the optional stuff like Pool, IdentityMap, Migrations etc.
13
13
  # Abstract.
14
14
  Adapter
15
15
  .new #=> Adapter
16
- #all #=> Result
17
16
  #begin #=> Adapter
18
17
  #commit
19
18
  #create #=> Scheme or Result
20
- #destroy #=> Scheme or Result
19
+ #delete #=> Result
21
20
  #execute #=> Result
22
- #first #=> Scheme
23
21
  #get #=> Scheme
24
22
  #prepare #=> Statement
25
23
  #rollback
26
24
  #transaction #=> Adapter
27
25
  #update #=> Scheme or Result
28
26
  #reconnect
29
- #delete #=> Result
30
-
31
- # TODO: DBI < Adapter
32
- # returning? #=> true or false
33
27
 
34
28
  # Concrete.
35
29
  DB
36
- Mysql < Adapter # TODO: Adapter::DBI?
37
- Postgres < Adapter # TODO: Adapter::DBI?
38
- Sqlite3 < Adapter # TODO: Adapter::DBI?
30
+ Mysql < Adapter::Sql
31
+ Postgres < Adapter::Sql
32
+ Sqlite3 < Adapter::Sql
39
33
 
40
34
  # Enumerable collection of Scheme or Hash tuples.
41
35
  Result
@@ -48,21 +42,20 @@ Public API minus the optional stuff like Pool, IdentityMap, Migrations etc.
48
42
  #execute #=> Result
49
43
 
50
44
  Scheme
51
- .all #=> Result
52
45
  .attribute #=> Type
53
46
  .create #=> Scheme or Result
54
- .first #=> Scheme
55
47
  .get #=> Scheme
56
48
  .header #=> Header
57
49
  .load #=> Scheme
58
50
  .new #=> Scheme
59
- .scheme #=> Alias for self.class
60
51
  .store #=> Symbol
61
- #destroy #=> Scheme or Result
52
+ #execute #=> Result
53
+ #prepare #=> Statement
54
+ #scheme #=> Alias for self.class
62
55
  #tuple #=> Hash
63
56
  #update #=> Scheme or Result
64
57
 
65
- # Enumerable collection of Types for Scheme
58
+ # Enumerable collection of Types for Scheme.
66
59
  Header
67
60
  .new #=> Header
68
61
  #all #=> [Type, ...]
@@ -83,7 +76,7 @@ Public API minus the optional stuff like Pool, IdentityMap, Migrations etc.
83
76
  #default #=> Object
84
77
  #define_scheme_methods
85
78
 
86
- # Concrete
79
+ # Concrete.
87
80
  Type
88
81
  BigDecimal < Attribute
89
82
  Boolean < Attribute
data/README.rdoc CHANGED
@@ -121,12 +121,12 @@ Scheme/relation level helpers.
121
121
  user.update
122
122
 
123
123
  # Destroy
124
- user.destroy
124
+ user.delete
125
125
 
126
126
  === Conditions SQL syntax.
127
127
 
128
- SQL is easy and most people know it so Swift ORM provides a simple symbol like syntax to convert resource
129
- names to field names.
128
+ SQL is easy and most people know it so Swift ORM provides simple #to_s
129
+ attribute to field name typecasting.
130
130
 
131
131
  class User < Swift::Scheme
132
132
  store :users
@@ -138,7 +138,10 @@ names to field names.
138
138
 
139
139
  # Convert :name and :age to fields.
140
140
  # select * from users where eman like '%Arthurton' and ega > 20
141
- users = User.all(':name like ? and :age > ?', '%Arthurton', 20)
141
+ users = User.execute(
142
+ %Q{select * from #{User} where #{User.name} like ? and #{User.age} > ?},
143
+ '%Arthurton', 20
144
+ )
142
145
 
143
146
  === Identity Map
144
147
 
@@ -162,8 +165,9 @@ Swift comes with a simple identity map. Just require it after you load swift.
162
165
  # Create
163
166
  User.create name: 'James Arthurton', email: 'james@arthurton.local' # => User
164
167
 
165
- User.first(':name = ?', 'James Arthurton')
166
- User.first(':name = ?', 'James Arthurton') # Gets same object reference
168
+ find_user = User.prepare(%Q{select * from #{User} where #{User.name = ?})
169
+ find_user.execute('James Arthurton')
170
+ find_user.execute('James Arthurton') # Gets same object reference
167
171
 
168
172
  === Bulk inserts
169
173
 
@@ -265,7 +269,6 @@ The adapter level SELECT benchmarks without using ORM.
265
269
 
266
270
  * More tests.
267
271
  * Assertions for dumb stuff.
268
- * Abstract interface for other adapters? Move dbic++ to Swift::DBI::(Adapter, Pool, Result, Statment etc.)
269
272
 
270
273
  == Contributing
271
274
 
data/Rakefile CHANGED
@@ -32,6 +32,6 @@ task :default => :test
32
32
 
33
33
  require 'yard'
34
34
  YARD::Rake::YardocTask.new do |yard|
35
- yard.files = ['lib/**/*.rb']
35
+ yard.files = ['lib/**/*.rb', 'ext/*.cc']
36
36
  end
37
37
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.10.0
1
+ 0.11.0
data/ext/adapter.cc CHANGED
@@ -1,28 +1,40 @@
1
1
  #include "adapter.h"
2
2
 
3
- // extend the default dbi::FieldSet class with some ruby love.
3
+ // Extend the default dbi::FieldSet class with some ruby love.
4
4
  class Fields : public dbi::FieldSet {
5
5
  public:
6
- Fields() : dbi::FieldSet(0) {}
6
+ Fields() : dbi::FieldSet(0) {}
7
7
 
8
- void operator<<(VALUE v) {
9
- VALUE name = TO_S(v);
10
- fields.push_back(std::string(RSTRING_PTR(name), RSTRING_LEN(name)));
11
- }
8
+ void operator<<(VALUE v) {
9
+ VALUE name = TO_S(v);
10
+ fields.push_back(std::string(RSTRING_PTR(name), RSTRING_LEN(name)));
11
+ }
12
12
  };
13
13
 
14
14
  static VALUE cSwiftAdapter;
15
15
 
16
+ void build_extra_options_string(VALUE key, VALUE value, VALUE ptr) {
17
+ std::string *optstring = (std::string *)ptr;
18
+ *optstring += CSTRING(key) + std::string("=") + CSTRING(value) + std::string(";");
19
+ }
20
+
21
+ std::string parse_extra_options(VALUE options) {
22
+ std::string optstring = "";
23
+ if (!NIL_P(options))
24
+ rb_hash_foreach(options, RUBY_STATIC_FUNC(build_extra_options_string), (VALUE)&optstring);
25
+ return optstring;
26
+ }
27
+
16
28
  static void adapter_free(dbi::Handle *handle) {
17
- if (handle) {
18
- handle->conn()->cleanup();
19
- delete handle;
20
- }
29
+ if (handle) {
30
+ handle->conn()->cleanup();
31
+ delete handle;
32
+ }
21
33
  }
22
34
 
23
35
  VALUE adapter_alloc(VALUE klass) {
24
- dbi::Handle *handle = 0;
25
- return Data_Wrap_Struct(klass, 0, adapter_free, handle);
36
+ dbi::Handle *handle = 0;
37
+ return Data_Wrap_Struct(klass, 0, adapter_free, handle);
26
38
  }
27
39
 
28
40
  dbi::Handle* adapter_handle(VALUE self) {
@@ -33,6 +45,14 @@ dbi::Handle* adapter_handle(VALUE self) {
33
45
  return handle;
34
46
  }
35
47
 
48
+ /*
49
+ Begin a transaction (unit of work).
50
+
51
+ @overload commit(name = nil)
52
+ @param [Symbol, String] name Optional transaction name.
53
+
54
+ @see Swift::Adapter#transaction
55
+ */
36
56
  static VALUE adapter_begin(int argc, VALUE *argv, VALUE self) {
37
57
  VALUE save_point;
38
58
  rb_scan_args(argc, argv, "01", &save_point);
@@ -45,17 +65,31 @@ static VALUE adapter_begin(int argc, VALUE *argv, VALUE self) {
45
65
  return Qtrue;
46
66
  }
47
67
 
68
+ /*
69
+ Close the connection.
70
+ */
48
71
  static VALUE adapter_close(VALUE self) {
49
72
  dbi::Handle *handle = adapter_handle(self);
50
73
  try { handle->close(); } CATCH_DBI_EXCEPTIONS();
51
74
  return Qtrue;
52
75
  }
53
76
 
54
- // TODO:
77
+ /*
78
+ Shallow copy of adapter.
79
+
80
+ @note Currently not allowed.
81
+ @see Object.clone
82
+ */
55
83
  static VALUE adapter_clone(VALUE self) {
56
84
  rb_raise(eSwiftRuntimeError, "clone is not allowed.");
57
85
  }
58
86
 
87
+ /*
88
+ Commit a transaction (unit of work).
89
+
90
+ @overload commit(name = nil)
91
+ @param [Symbol, String] name Optional transaction name.
92
+ */
59
93
  static VALUE adapter_commit(int argc, VALUE *argv, VALUE self) {
60
94
  VALUE save_point;
61
95
  rb_scan_args(argc, argv, "01", &save_point);
@@ -68,14 +102,28 @@ static VALUE adapter_commit(int argc, VALUE *argv, VALUE self) {
68
102
  return Qtrue;
69
103
  }
70
104
 
71
- // TODO:
105
+ /*
106
+ Shallow copy of adapter.
107
+
108
+ @note Currently not allowed.
109
+ @see Object.dup
110
+ */
72
111
  static VALUE adapter_dup(VALUE self) {
73
112
  rb_raise(eSwiftRuntimeError, "dup is not allowed.");
74
113
  }
75
114
 
76
- // TODO: Attempt TO_S() before escaping?
115
+ /*
116
+ Escape a string.
117
+
118
+ @note Bind values do not need to be escaped.
119
+
120
+ @overload escape(value)
121
+ @param [String] value String to be escaped.
122
+ @return [String]
123
+ */
77
124
  static VALUE adapter_escape(VALUE self, VALUE value) {
78
- if (TYPE(value) != T_STRING) rb_raise(eSwiftArgumentError, "Cannot escape non-string value.");
125
+ if (TYPE(value) != T_STRING)
126
+ value = TO_S(value);
79
127
 
80
128
  dbi::Handle *handle = adapter_handle(self);
81
129
  try {
@@ -85,7 +133,19 @@ static VALUE adapter_escape(VALUE self, VALUE value) {
85
133
  CATCH_DBI_EXCEPTIONS();
86
134
  }
87
135
 
88
- // TODO: Change bind_values to an array in the interface? Avoid array -> splat -> array.
136
+ /*
137
+ Execute a single statement.
138
+
139
+ @example
140
+ result = User.execute("select * from #{User} where #{User.name} = ?", 'apple')
141
+ result.first # User object.
142
+
143
+ @overload execute(statement = '', *binds, &block)
144
+ @param [String] statement Query statement.
145
+ @param [*Object] binds Bind values.
146
+ @yield [Swift::Result]
147
+ @return [Swift::Result]
148
+ */
89
149
  static VALUE adapter_execute(int argc, VALUE *argv, VALUE self) {
90
150
  VALUE statement, bind_values, block, rows, scheme = Qnil;
91
151
 
@@ -116,12 +176,38 @@ static VALUE adapter_execute(int argc, VALUE *argv, VALUE self) {
116
176
  CATCH_DBI_EXCEPTIONS();
117
177
  }
118
178
 
179
+ /*
180
+ Reestablish a connection.
181
+ */
119
182
  static VALUE adapter_reconnect(VALUE self) {
120
183
  dbi::Handle *handle = adapter_handle(self);
121
184
  try { handle->reconnect(); } CATCH_DBI_EXCEPTIONS();
122
185
  return Qtrue;
123
186
  }
124
187
 
188
+ /*
189
+ Setup a new DB connection.
190
+
191
+ You almost certainly want to setup a <tt>:default</tt> named adapter. The <tt>:default</tt> scope will be used
192
+ for unscoped calls to <tt>Swift.db</tt>.
193
+
194
+ @example
195
+ Swift.setup :default, Swift::DB::Postgres, db: 'db1'
196
+ Swift.setup :other, Swift::DB::Postgres, db: 'db2'
197
+
198
+ @overload new(options = {})
199
+ @param [Hash] options Connection options
200
+ @option options [String] :db Name.
201
+ @option options [String] :user (*nix login user)
202
+ @option options [String] :password ('')
203
+ @option options [String] :host ('localhost')
204
+ @option options [Integer] :port (DB default)
205
+ @option options [String] :timezone (*nix TZ format) See http://en.wikipedia.org/wiki/List_of_tz_database_time_zones
206
+ @return [Swift::Adapter]
207
+
208
+ @see Swift::DB
209
+ @see Swift::Adapter
210
+ */
125
211
  static VALUE adapter_initialize(VALUE self, VALUE options) {
126
212
  VALUE db = rb_hash_aref(options, ID2SYM(rb_intern("db")));
127
213
  VALUE driver = rb_hash_aref(options, ID2SYM(rb_intern("driver")));
@@ -130,7 +216,18 @@ static VALUE adapter_initialize(VALUE self, VALUE options) {
130
216
  if (NIL_P(db)) rb_raise(eSwiftArgumentError, "Adapter#new called without :db");
131
217
  if (NIL_P(driver)) rb_raise(eSwiftArgumentError, "Adapter#new called without :driver");
132
218
 
133
- user = NIL_P(user) ? CURRENT_USER() : user;
219
+ user = NIL_P(user) ? current_user() : user;
220
+ VALUE extra = rb_hash_dup(options);
221
+
222
+ rb_hash_delete(extra, ID2SYM(rb_intern("db")));
223
+ rb_hash_delete(extra, ID2SYM(rb_intern("driver")));
224
+ rb_hash_delete(extra, ID2SYM(rb_intern("user")));
225
+ rb_hash_delete(extra, ID2SYM(rb_intern("password")));
226
+ rb_hash_delete(extra, ID2SYM(rb_intern("host")));
227
+ rb_hash_delete(extra, ID2SYM(rb_intern("port")));
228
+ rb_hash_delete(extra, ID2SYM(rb_intern("timezone")));
229
+
230
+ std::string extra_options_string = parse_extra_options(extra);
134
231
 
135
232
  try {
136
233
  DATA_PTR(self) = new dbi::Handle(
@@ -139,16 +236,30 @@ static VALUE adapter_initialize(VALUE self, VALUE options) {
139
236
  CSTRING(rb_hash_aref(options, ID2SYM(rb_intern("password")))),
140
237
  CSTRING(db),
141
238
  CSTRING(rb_hash_aref(options, ID2SYM(rb_intern("host")))),
142
- CSTRING(rb_hash_aref(options, ID2SYM(rb_intern("port"))))
239
+ CSTRING(rb_hash_aref(options, ID2SYM(rb_intern("port")))),
240
+ extra_options_string.size() > 0 ? (char*)extra_options_string.c_str() : 0
143
241
  );
144
242
  }
145
243
  CATCH_DBI_EXCEPTIONS();
146
244
 
147
- rb_iv_set(self, "@timezone", rb_hash_aref(options, ID2SYM(rb_intern("timezone"))));
148
245
  rb_iv_set(self, "@options", options);
246
+ rb_iv_set(self, "@timezone", rb_hash_aref(options, ID2SYM(rb_intern("timezone"))));
247
+
149
248
  return Qnil;
150
249
  }
151
250
 
251
+ /*
252
+ Prepare a statement for on or more executions.
253
+
254
+ @example
255
+ sth = User.prepare("select * from #{User} where #{User.name} = ?")
256
+ sth.execute('apple') #=> Result
257
+ sth.execute('benny') #=> Result
258
+
259
+ @overload prepare(statement, &block)
260
+ @param [String] statement Query statement.
261
+ @return [Swift::Statement]
262
+ */
152
263
  static VALUE adapter_prepare(int argc, VALUE *argv, VALUE self) {
153
264
  VALUE sql, scheme, prepared;
154
265
  dbi::AbstractStatement *statement;
@@ -170,6 +281,12 @@ static VALUE adapter_prepare(int argc, VALUE *argv, VALUE self) {
170
281
  CATCH_DBI_EXCEPTIONS();
171
282
  }
172
283
 
284
+ /*
285
+ Rollback the current transaction.
286
+
287
+ @overload rollback(name = nil)
288
+ @param [Symbol, String] name Optional transaction name.
289
+ */
173
290
  static VALUE adapter_rollback(int argc, VALUE *argv, VALUE self) {
174
291
  VALUE save_point;
175
292
  dbi::Handle *handle = adapter_handle(self);
@@ -182,12 +299,16 @@ static VALUE adapter_rollback(int argc, VALUE *argv, VALUE self) {
182
299
  return Qtrue;
183
300
  }
184
301
 
302
+ /*
303
+ Block form transaction sugar.
304
+
305
+ @overload transaction(name = nil, &block)
306
+ @param [Symbol, String] name Optional transaction name.
307
+ */
185
308
  static VALUE adapter_transaction(int argc, VALUE *argv, VALUE self) {
186
309
  int status;
187
310
  VALUE sp, block, block_result = Qnil;
188
-
189
311
  dbi::Handle *handle = adapter_handle(self);
190
-
191
312
  rb_scan_args(argc, argv, "01&", &sp, &block);
192
313
 
193
314
  if (NIL_P(block)) rb_raise(eSwiftArgumentError, "Transaction called without a block.");
@@ -209,6 +330,16 @@ static VALUE adapter_transaction(int argc, VALUE *argv, VALUE self) {
209
330
  return block_result;
210
331
  }
211
332
 
333
+ /*
334
+ Bulk insert resources.
335
+
336
+ @overload write(store, fields, stream)
337
+ @param [Swift::Scheme, String] store Write to store.
338
+ @param [Array<Swift::Attribute, String>] fields Write to fields in store.
339
+ @param [IO] stream IO to read from.
340
+
341
+ @note The format of the stream and bulk write performance are entirely down to each adapter.
342
+ */
212
343
  static VALUE adapter_write(int argc, VALUE *argv, VALUE self) {
213
344
  uint64_t rows = 0;
214
345
  VALUE stream, table, fields;
@@ -234,11 +365,11 @@ static VALUE adapter_write(int argc, VALUE *argv, VALUE self) {
234
365
 
235
366
  if (TYPE(stream) == T_STRING) {
236
367
  dbi::StringIO io(RSTRING_PTR(stream), RSTRING_LEN(stream));
237
- rows = handle->write(RSTRING_PTR(table), write_fields, &io);
368
+ rows = handle->write(RSTRING_PTR(TO_S(table)), write_fields, &io);
238
369
  }
239
370
  else {
240
371
  AdapterIO io(stream);
241
- rows = handle->write(RSTRING_PTR(table), write_fields, &io);
372
+ rows = handle->write(RSTRING_PTR(TO_S(table)), write_fields, &io);
242
373
  }
243
374
  return SIZET2NUM(rows);
244
375
  }
@@ -266,4 +397,3 @@ void init_swift_adapter() {
266
397
  rb_define_alloc_func(cSwiftAdapter, adapter_alloc);
267
398
  }
268
399
 
269
-
data/ext/extconf.rb CHANGED
@@ -1,17 +1,17 @@
1
- #!/usr/bin/ruby
1
+ #!/usr/bin/env ruby
2
2
  require 'mkmf'
3
3
 
4
4
  Config::CONFIG['CC'] = 'g++'
5
5
  Config::CONFIG['CPP'] = 'g++'
6
6
 
7
- $CFLAGS = '-fPIC -Os'
7
+ $CFLAGS = '-fPIC -Os -I/usr/include -I/opt/local/include -I/usr/local/include'
8
8
 
9
9
  def apt_install_hint pkg
10
10
  "sudo apt-get install #{pkg}"
11
11
  end
12
12
 
13
13
  def library_installed? name, hint
14
- if have_library(name)
14
+ if find_library(name, 'main', *%w(/usr/lib /usr/local/lib /opt/lib /opt/local/lib /sw/lib))
15
15
  true
16
16
  else
17
17
  $stderr.puts <<-ERROR
data/ext/pool.cc CHANGED
@@ -26,7 +26,7 @@ VALUE pool_init(VALUE self, VALUE n, VALUE options) {
26
26
  if (NIL_P(db)) rb_raise(eSwiftArgumentError, "Pool#new called without :db");
27
27
  if (NIL_P(driver)) rb_raise(eSwiftArgumentError, "#new called without :driver");
28
28
 
29
- user = NIL_P(user) ? CURRENT_USER() : user;
29
+ user = NIL_P(user) ? current_user() : user;
30
30
  if (NUM2INT(n) < 1) rb_raise(eSwiftArgumentError, "Pool#new called with invalid pool size.");
31
31
 
32
32
  try {
data/ext/result.cc CHANGED
@@ -45,12 +45,12 @@ dbi::AbstractResult* result_handle(VALUE self) {
45
45
  return handle->result;
46
46
  }
47
47
 
48
- // TODO:
48
+ // NOTE clone and dup cannot be allowed since the underlying c++ object needs to be cloned, which
49
+ // frankly is too much work :)
49
50
  static VALUE result_clone(VALUE self) {
50
51
  rb_raise(eSwiftRuntimeError, "clone is not allowed.");
51
52
  }
52
53
 
53
- // TODO:
54
54
  static VALUE result_dup(VALUE self) {
55
55
  rb_raise(eSwiftRuntimeError, "dup is not allowed.");
56
56
  }
data/ext/statement.cc CHANGED
@@ -43,7 +43,7 @@ dbi::AbstractStatement* statement_handle(VALUE self) {
43
43
  return handle->statement;
44
44
  }
45
45
 
46
- // TODO: Change bind_values to an array in the interface? Avoid array -> splat -> array.
46
+ // array -> splat -> array is an overhead, but it reads nicer.
47
47
  static VALUE statement_execute(int argc, VALUE *argv, VALUE self) {
48
48
  VALUE bind_values, block;
49
49
  rb_scan_args(argc, argv, "0*&", &bind_values, &block);
data/ext/swift.cc CHANGED
@@ -7,17 +7,45 @@ VALUE eSwiftArgumentError;
7
7
  VALUE eSwiftRuntimeError;
8
8
  VALUE eSwiftConnectionError;
9
9
 
10
+ /*
11
+ Initialize Swift with a non standard dbic++ path.
12
+
13
+ @note
14
+ By default Swift looks in '/usr/lib/dbic++/'. Not normally required unless you install dbic++ somewhere funny.
15
+
16
+ @overload init(path)
17
+ @param [path] path Non standard dbic++ path.
18
+ */
10
19
  VALUE swift_init(VALUE self, VALUE path) {
11
20
  try { dbi::dbiInitialize(CSTRING(path)); } CATCH_DBI_EXCEPTIONS();
12
21
  return Qtrue;
13
22
  }
14
23
 
24
+ /*
25
+ Trace statement execution.
26
+
27
+ @example Toggle tracing.
28
+ Swift.trace true
29
+ Swift.db.execute 'select * from users'
30
+ Swift.trace false
31
+ @example Block form.
32
+ Swift.trace true do
33
+ Swift.db.execute 'select * from users'
34
+ end
35
+
36
+ @overload trace(show = true, output = $stderr)
37
+ @param [true, false] show Optional trace toggle boolean.
38
+ @param [IO] output Optional output. Defaults to stderr.
39
+ */
15
40
  VALUE swift_trace(int argc, VALUE *argv, VALUE self) {
16
41
  VALUE flag, io;
17
42
  rb_io_t *fptr;
18
- int fd = 2; // defaults to stderr
43
+ int status, fd = 2; // defaults to stderr
19
44
 
20
- rb_scan_args(argc, argv, "11", &flag, &io);
45
+ rb_scan_args(argc, argv, "02", &flag, &io);
46
+
47
+ if (NIL_P(flag))
48
+ flag = Qtrue;
21
49
 
22
50
  if (TYPE(flag) != T_TRUE && TYPE(flag) != T_FALSE)
23
51
  rb_raise(eSwiftArgumentError, "Swift#trace expects a boolean flag, got %s", CSTRING(flag));
@@ -27,8 +55,25 @@ VALUE swift_trace(int argc, VALUE *argv, VALUE self) {
27
55
  fd = fptr->fd;
28
56
  }
29
57
 
30
- dbi::trace(flag == Qtrue ? true : false, fd);
31
- return flag;
58
+ // block form trace
59
+ if (rb_block_given_p()) {
60
+ // orig values
61
+ bool orig_trace = dbi::_trace;
62
+ int orig_trace_fd = dbi::_trace_fd;
63
+
64
+ dbi::trace(flag == Qtrue ? true : false, fd);
65
+ VALUE block_result = rb_protect(rb_yield, Qnil, &status);
66
+ dbi::trace(orig_trace, orig_trace_fd);
67
+
68
+ if (status)
69
+ rb_jump_tag(status);
70
+ else
71
+ return block_result;
72
+ }
73
+ else {
74
+ dbi::trace(flag == Qtrue ? true : false, fd);
75
+ return flag;
76
+ }
32
77
  }
33
78
 
34
79
  VALUE atexit_gc(...) {
data/ext/swift.h CHANGED
@@ -12,6 +12,7 @@
12
12
  #define CONST_GET(scope, constant) rb_funcall(scope, rb_intern("const_get"), 1, rb_str_new2(constant))
13
13
  #define TO_S(v) rb_funcall(v, rb_intern("to_s"), 0)
14
14
  #define CSTRING(v) RSTRING_PTR(TO_S(v))
15
+ #define RUBY_STATIC_FUNC(func) ((int (*)(ANYARGS))func)
15
16
 
16
17
  extern VALUE eSwiftError;
17
18
  extern VALUE eSwiftArgumentError;
@@ -31,7 +32,7 @@ extern VALUE eSwiftConnectionError;
31
32
 
32
33
 
33
34
  // works without a controlling tty, getlogin() will fail when process is daemonized.
34
- inline VALUE CURRENT_USER() {
35
+ inline VALUE current_user() {
35
36
  struct passwd *ptr = getpwuid(getuid());
36
37
  return ptr ? rb_str_new2(ptr->pw_name) : rb_str_new2("root");
37
38
  }
@@ -0,0 +1,69 @@
1
+ require 'swift/adapter'
2
+
3
+ module Swift
4
+ class Adapter
5
+
6
+ # Abstract SQL Adapter.
7
+ #
8
+ # @abstract
9
+ class Sql < Adapter
10
+ protected
11
+ def returning?
12
+ raise NotImplementedError
13
+ end
14
+
15
+ def prepare_cached scheme, name, &block
16
+ @prepared ||= Hash.new{|h,k| h[k] = Hash.new}
17
+ @prepared[scheme][name] ||= prepare(scheme, yield)
18
+ end
19
+
20
+ def prepare_get scheme
21
+ prepare_cached(scheme, :get) do
22
+ where = scheme.header.keys.map{|key| "#{key} = ?"}.join(' and ')
23
+ "select * from #{scheme.store} where #{where} limit 1"
24
+ end
25
+ end
26
+
27
+ def prepare_create scheme
28
+ prepare_cached(scheme, :create) do
29
+ values = (['?'] * scheme.header.insertable.size).join(', ')
30
+ returning = "returning #{scheme.header.serial}" if scheme.header.serial and returning?
31
+ "insert into #{scheme.store} (#{scheme.header.insertable.join(', ')}) values (#{values}) #{returning}"
32
+ end
33
+ end
34
+
35
+ def prepare_update scheme
36
+ prepare_cached(scheme, :update) do
37
+ set = scheme.header.updatable.map{|field| "#{field} = ?"}.join(', ')
38
+ where = scheme.header.keys.map{|key| "#{key} = ?"}.join(' and ')
39
+ "update #{scheme.store} set #{set} where #{where}"
40
+ end
41
+ end
42
+
43
+ def prepare_delete scheme
44
+ prepare_cached(scheme, :delete) do
45
+ where = scheme.header.keys.map{|key| "#{key} = ?"}.join(' and ')
46
+ "delete from #{scheme.store} where #{where}"
47
+ end
48
+ end
49
+
50
+ def field_definition attribute
51
+ "#{attribute.field} " + field_type(attribute)
52
+ end
53
+
54
+ def field_type attribute
55
+ case attribute
56
+ when Type::String then 'text'
57
+ when Type::Integer then attribute.serial ? 'serial' : 'integer'
58
+ when Type::Float then 'float'
59
+ when Type::BigDecimal then 'numeric'
60
+ when Type::Time then 'timestamp'
61
+ when Type::Date then 'date'
62
+ when Type::Boolean then 'boolean'
63
+ when Type::IO then 'blob'
64
+ else 'text'
65
+ end
66
+ end
67
+ end # Sql
68
+ end # Adapter
69
+ end # Swift