swift 0.10.0 → 0.11.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 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