sequel 0.4.1.1 → 0.4.1.2
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +10 -0
- data/Rakefile +1 -1
- data/lib/sequel/adapters/odbc.rb +1 -1
- data/lib/sequel/adapters/odbc_mssql.rb +98 -0
- data/lib/sequel/database.rb +1 -0
- data/lib/sequel/dataset/sql.rb +1 -1
- data/lib/sequel/model.rb +2 -45
- data/lib/sequel/model/plugins.rb +29 -0
- data/lib/sequel/model/record.rb +36 -0
- data/spec/model_spec.rb +38 -0
- metadata +4 -2
data/CHANGELOG
CHANGED
@@ -1,3 +1,13 @@
|
|
1
|
+
== 0.4.1.2 (2007-12-04)
|
2
|
+
|
3
|
+
* Changed Model.is to accept variable arity.
|
4
|
+
|
5
|
+
* Implemented plugin loading for model classes.
|
6
|
+
|
7
|
+
* Fixed odbc-mssql and odbc adapters (thanks Dusty.)
|
8
|
+
|
9
|
+
* Implemented odbc-mssql adapter (thanks Dusty.)
|
10
|
+
|
1
11
|
=== 0.4.1.1 (2007-11-27)
|
2
12
|
|
3
13
|
* Fixed #first and #last functionality in Informix::Dataset (thanks Gerardo Santana).
|
data/Rakefile
CHANGED
@@ -6,7 +6,7 @@ require 'fileutils'
|
|
6
6
|
include FileUtils
|
7
7
|
|
8
8
|
NAME = "sequel"
|
9
|
-
VERS = "0.4.1.
|
9
|
+
VERS = "0.4.1.2"
|
10
10
|
CLEAN.include ['**/.*.sw?', 'pkg/*', '.config', 'doc/*', 'coverage/*']
|
11
11
|
RDOC_OPTS = ['--quiet', '--title', "Sequel: Concise ORM for Ruby",
|
12
12
|
"--opname", "index.html",
|
data/lib/sequel/adapters/odbc.rb
CHANGED
@@ -0,0 +1,98 @@
|
|
1
|
+
if !Object.const_defined?('Sequel')
|
2
|
+
require File.join(File.dirname(__FILE__), '../../sequel')
|
3
|
+
end
|
4
|
+
|
5
|
+
if !Sequel.const_defined?('ODBC')
|
6
|
+
require File.join(File.dirname(__FILE__), 'odbc')
|
7
|
+
end
|
8
|
+
|
9
|
+
module Sequel
|
10
|
+
module ODBC
|
11
|
+
module MSSQL
|
12
|
+
class Database < ODBC::Database
|
13
|
+
set_adapter_scheme :odbc_mssql
|
14
|
+
# set_adapter_scheme :"odbc-mssql"
|
15
|
+
|
16
|
+
def dataset(opts = nil)
|
17
|
+
MSSQL::Dataset.new(self, opts)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
class Dataset < ODBC::Dataset
|
22
|
+
# Allows you to do .nolock on a query
|
23
|
+
def nolock
|
24
|
+
clone_merge(:with => "(NOLOCK)")
|
25
|
+
end
|
26
|
+
|
27
|
+
# Formats a SELECT statement using the given options and the dataset
|
28
|
+
# options.
|
29
|
+
def select_sql(opts = nil)
|
30
|
+
opts = opts ? @opts.merge(opts) : @opts
|
31
|
+
|
32
|
+
if sql = opts[:sql]
|
33
|
+
return sql
|
34
|
+
end
|
35
|
+
|
36
|
+
# ADD TOP to SELECT string for LIMITS
|
37
|
+
if limit = opts[:limit]
|
38
|
+
top = "TOP #{limit} "
|
39
|
+
raise SequelError, "Offset not supported" if opts[:offset]
|
40
|
+
end
|
41
|
+
|
42
|
+
columns = opts[:select]
|
43
|
+
select_columns = columns ? column_list(columns) : WILDCARD
|
44
|
+
|
45
|
+
if distinct = opts[:distinct]
|
46
|
+
distinct_clause = distinct.empty? ? "DISTINCT" : "DISTINCT ON (#{column_list(distinct)})"
|
47
|
+
sql = "SELECT #{top}#{distinct_clause} #{select_columns}"
|
48
|
+
else
|
49
|
+
sql = "SELECT #{top}#{select_columns}"
|
50
|
+
end
|
51
|
+
|
52
|
+
if opts[:from]
|
53
|
+
sql << " FROM #{source_list(opts[:from])}"
|
54
|
+
end
|
55
|
+
|
56
|
+
# ADD WITH to SELECT string for NOLOCK
|
57
|
+
if with = opts[:with]
|
58
|
+
sql << " WITH #{with}"
|
59
|
+
end
|
60
|
+
|
61
|
+
if join = opts[:join]
|
62
|
+
sql << join
|
63
|
+
end
|
64
|
+
|
65
|
+
if where = opts[:where]
|
66
|
+
sql << " WHERE #{where}"
|
67
|
+
end
|
68
|
+
|
69
|
+
if group = opts[:group]
|
70
|
+
sql << " GROUP BY #{column_list(group)}"
|
71
|
+
end
|
72
|
+
|
73
|
+
if order = opts[:order]
|
74
|
+
sql << " ORDER BY #{column_list(order)}"
|
75
|
+
end
|
76
|
+
|
77
|
+
if having = opts[:having]
|
78
|
+
sql << " HAVING #{having}"
|
79
|
+
end
|
80
|
+
|
81
|
+
if union = opts[:union]
|
82
|
+
sql << (opts[:union_all] ? \
|
83
|
+
" UNION ALL #{union.sql}" : " UNION #{union.sql}")
|
84
|
+
elsif intersect = opts[:intersect]
|
85
|
+
sql << (opts[:intersect_all] ? \
|
86
|
+
" INTERSECT ALL #{intersect.sql}" : " INTERSECT #{intersect.sql}")
|
87
|
+
elsif except = opts[:except]
|
88
|
+
sql << (opts[:except_all] ? \
|
89
|
+
" EXCEPT ALL #{except.sql}" : " EXCEPT #{except.sql}")
|
90
|
+
end
|
91
|
+
|
92
|
+
sql
|
93
|
+
end
|
94
|
+
alias_method :sql, :select_sql
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
data/lib/sequel/database.rb
CHANGED
@@ -257,6 +257,7 @@ module Sequel
|
|
257
257
|
end
|
258
258
|
|
259
259
|
def self.adapter_class(scheme)
|
260
|
+
scheme = scheme.to_s =~ /\-/ ? scheme.to_s.gsub('-', '_').to_sym : scheme.to_sym
|
260
261
|
unless c = @@adapters[scheme.to_sym]
|
261
262
|
require File.join(File.dirname(__FILE__), "adapters/#{scheme}")
|
262
263
|
c = @@adapters[scheme.to_sym]
|
data/lib/sequel/dataset/sql.rb
CHANGED
@@ -420,7 +420,7 @@ module Sequel
|
|
420
420
|
|
421
421
|
sql
|
422
422
|
end
|
423
|
-
|
423
|
+
alias_method :sql, :select_sql
|
424
424
|
|
425
425
|
# Formats an INSERT statement using the given values. If a hash is given,
|
426
426
|
# the resulting statement includes column names. If no values are given,
|
data/lib/sequel/model.rb
CHANGED
@@ -235,21 +235,15 @@ require File.join(File.dirname(__FILE__), 'model/record')
|
|
235
235
|
require File.join(File.dirname(__FILE__), 'model/schema')
|
236
236
|
require File.join(File.dirname(__FILE__), 'model/relations')
|
237
237
|
require File.join(File.dirname(__FILE__), 'model/caching')
|
238
|
+
require File.join(File.dirname(__FILE__), 'model/plugins')
|
238
239
|
|
239
240
|
module Sequel
|
240
241
|
class Model
|
241
|
-
|
242
242
|
# Defines a method that returns a filtered dataset.
|
243
243
|
def self.subset(name, *args, &block)
|
244
244
|
dataset.meta_def(name) {filter(*args, &block)}
|
245
245
|
end
|
246
|
-
|
247
|
-
# Comprehensive description goes here!
|
248
|
-
def primary_key_hash(value)
|
249
|
-
# stock implementation
|
250
|
-
{:id => value}
|
251
|
-
end
|
252
|
-
|
246
|
+
|
253
247
|
# Finds a single record according to the supplied filter, e.g.:
|
254
248
|
#
|
255
249
|
# Ticket.find :author => 'Sharon' # => record
|
@@ -310,42 +304,5 @@ module Sequel
|
|
310
304
|
def self.all
|
311
305
|
dataset.all
|
312
306
|
end
|
313
|
-
|
314
|
-
# Returns value of attribute.
|
315
|
-
def [](column)
|
316
|
-
@values[column]
|
317
|
-
end
|
318
|
-
# Sets value of attribute.
|
319
|
-
def []=(column, value)
|
320
|
-
@values[column] = value
|
321
|
-
end
|
322
|
-
|
323
|
-
# Enumerates through all attributes.
|
324
|
-
#
|
325
|
-
# === Example:
|
326
|
-
# Ticket.find(7).each { |k, v| puts "#{k} => #{v}" }
|
327
|
-
def each(&block)
|
328
|
-
@values.each(&block)
|
329
|
-
end
|
330
|
-
# Returns attribute names.
|
331
|
-
def keys
|
332
|
-
@values.keys
|
333
|
-
end
|
334
|
-
|
335
|
-
# Returns value for <tt>:id</tt> attribute.
|
336
|
-
def id
|
337
|
-
@values[:id]
|
338
|
-
end
|
339
|
-
|
340
|
-
# Compares model instances by values.
|
341
|
-
def ==(obj)
|
342
|
-
(obj.class == model) && (obj.values == @values)
|
343
|
-
end
|
344
|
-
|
345
|
-
# Compares model instances by pkey.
|
346
|
-
def ===(obj)
|
347
|
-
(obj.class == model) && (obj.pk == pk)
|
348
|
-
end
|
349
|
-
|
350
307
|
end
|
351
308
|
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Sequel
|
2
|
+
module Plugins; end
|
3
|
+
|
4
|
+
class Model
|
5
|
+
class << self
|
6
|
+
# Loads a plugin for use with the model class, passing optional arguments
|
7
|
+
# to the plugin.
|
8
|
+
def is(plugin, *args)
|
9
|
+
plugin_module(plugin).apply(self, *args)
|
10
|
+
end
|
11
|
+
alias_method :is_a, :is
|
12
|
+
|
13
|
+
# Returns the module for the specified plugin. If the module is not
|
14
|
+
# defined, the corresponding plugin gem is automatically loaded.
|
15
|
+
def plugin_module(plugin)
|
16
|
+
module_name = plugin.to_s.gsub(/(^|_)(.)/) {$2.upcase}
|
17
|
+
if not Sequel::Plugins.const_defined?(module_name)
|
18
|
+
require plugin_gem(plugin)
|
19
|
+
end
|
20
|
+
Sequel::Plugins.const_get(module_name)
|
21
|
+
end
|
22
|
+
|
23
|
+
# Returns the gem name for the given plugin.
|
24
|
+
def plugin_gem(plugin)
|
25
|
+
"sequel_#{plugin}"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/lib/sequel/model/record.rb
CHANGED
@@ -2,6 +2,42 @@ module Sequel
|
|
2
2
|
class Model
|
3
3
|
attr_reader :values
|
4
4
|
|
5
|
+
# Returns value of attribute.
|
6
|
+
def [](column)
|
7
|
+
@values[column]
|
8
|
+
end
|
9
|
+
# Sets value of attribute.
|
10
|
+
def []=(column, value)
|
11
|
+
@values[column] = value
|
12
|
+
end
|
13
|
+
|
14
|
+
# Enumerates through all attributes.
|
15
|
+
#
|
16
|
+
# === Example:
|
17
|
+
# Ticket.find(7).each { |k, v| puts "#{k} => #{v}" }
|
18
|
+
def each(&block)
|
19
|
+
@values.each(&block)
|
20
|
+
end
|
21
|
+
# Returns attribute names.
|
22
|
+
def keys
|
23
|
+
@values.keys
|
24
|
+
end
|
25
|
+
|
26
|
+
# Returns value for <tt>:id</tt> attribute.
|
27
|
+
def id
|
28
|
+
@values[:id]
|
29
|
+
end
|
30
|
+
|
31
|
+
# Compares model instances by values.
|
32
|
+
def ==(obj)
|
33
|
+
(obj.class == model) && (obj.values == @values)
|
34
|
+
end
|
35
|
+
|
36
|
+
# Compares model instances by pkey.
|
37
|
+
def ===(obj)
|
38
|
+
(obj.class == model) && (obj.pk == pk)
|
39
|
+
end
|
40
|
+
|
5
41
|
# Returns key for primary key.
|
6
42
|
def self.primary_key
|
7
43
|
:id
|
data/spec/model_spec.rb
CHANGED
@@ -1039,4 +1039,42 @@ context "Model magic methods" do
|
|
1039
1039
|
@m.last_by_name('sharon').values.should == {:id => 123, :name => 'hey'}
|
1040
1040
|
@c.sqls.should == ["SELECT * FROM items ORDER BY name DESC LIMIT 1"] * 2
|
1041
1041
|
end
|
1042
|
+
end
|
1043
|
+
|
1044
|
+
module Sequel::Plugins
|
1045
|
+
module Timestamped
|
1046
|
+
def self.apply(m, opts)
|
1047
|
+
m.class_def(:get_stamp) {@values[:stamp]}
|
1048
|
+
m.meta_def(:stamp_opts) {opts}
|
1049
|
+
m.before_save {@values[:stamp] = Time.now}
|
1050
|
+
end
|
1051
|
+
end
|
1052
|
+
end
|
1053
|
+
|
1054
|
+
context "A model using a plugin" do
|
1055
|
+
specify "should fail if the plugin is not found" do
|
1056
|
+
proc do
|
1057
|
+
c = Class.new(Sequel::Model) do
|
1058
|
+
is :something_or_other
|
1059
|
+
end
|
1060
|
+
end.should raise_error(LoadError)
|
1061
|
+
end
|
1062
|
+
|
1063
|
+
specify "should apply the plugin to the class" do
|
1064
|
+
c = nil
|
1065
|
+
proc do
|
1066
|
+
c = Class.new(Sequel::Model) do
|
1067
|
+
is :timestamped, :a => 1, :b => 2
|
1068
|
+
end
|
1069
|
+
end.should_not raise_error(LoadError)
|
1070
|
+
|
1071
|
+
c.should respond_to(:stamp_opts)
|
1072
|
+
c.stamp_opts.should == {:a => 1, :b => 2}
|
1073
|
+
|
1074
|
+
m = c.new
|
1075
|
+
m.should respond_to(:get_stamp)
|
1076
|
+
t = Time.now
|
1077
|
+
m[:stamp] = t
|
1078
|
+
m.get_stamp.should == t
|
1079
|
+
end
|
1042
1080
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sequel
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.1.
|
4
|
+
version: 0.4.1.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sharon Rosner
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2007-
|
12
|
+
date: 2007-12-04 00:00:00 +02:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -82,6 +82,7 @@ files:
|
|
82
82
|
- lib/sequel/adapters/informix.rb
|
83
83
|
- lib/sequel/adapters/mysql.rb
|
84
84
|
- lib/sequel/adapters/odbc.rb
|
85
|
+
- lib/sequel/adapters/odbc_mssql.rb
|
85
86
|
- lib/sequel/adapters/oracle.rb
|
86
87
|
- lib/sequel/adapters/postgres.rb
|
87
88
|
- lib/sequel/adapters/sqlite.rb
|
@@ -105,6 +106,7 @@ files:
|
|
105
106
|
- lib/sequel/model/base.rb
|
106
107
|
- lib/sequel/model/caching.rb
|
107
108
|
- lib/sequel/model/hooks.rb
|
109
|
+
- lib/sequel/model/plugins.rb
|
108
110
|
- lib/sequel/model/record.rb
|
109
111
|
- lib/sequel/model/relations.rb
|
110
112
|
- lib/sequel/model/schema.rb
|