yql-query 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,5 @@
1
+ pkg/*
2
+ Gemfile.lock
3
+ coverage/*
4
+ .yardoc
5
+ doc/*
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --color
2
+ --format=nested
3
+ --backtrace
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in yql-query.gemspec
4
+ gemspec
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 Steve Agalloco
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,21 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ require 'rspec/core/rake_task'
5
+ RSpec::Core::RakeTask.new(:spec)
6
+
7
+ task :default => :spec
8
+ task :test => :spec
9
+
10
+ namespace :doc do
11
+ require 'yard'
12
+ YARD::Rake::YardocTask.new do |task|
13
+ task.files = ['lib/**/*.rb']
14
+ task.options = [
15
+ '--protected',
16
+ '--output-dir', 'doc/yard',
17
+ '--markup', 'markdown',
18
+ '--readme', 'Readme.md'
19
+ ]
20
+ end
21
+ end
@@ -0,0 +1,94 @@
1
+ YqlQuery
2
+ ========
3
+
4
+ A simple [YQL query](http://developer.yahoo.com/yql/guide/index.html) generation library written in ruby, providing a chainable query builder capable of generating the most complex query conditions you can throw at it.
5
+
6
+ Installation
7
+ ------------
8
+
9
+ (sudo) gem install yql-query
10
+
11
+ Documentation
12
+ -------------
13
+
14
+ [http://rdoc.info/gems/yql-query](http://rdoc.info/gems/yql-query)
15
+
16
+ Usage
17
+ -----
18
+
19
+ yql-query's primary interface is the Builder class. Once you've instantiated a builder, you can pretty much generate whatever query you'd like using it.
20
+
21
+ builder = YqlQuery::Builder.new
22
+ builder.table('music.artists')
23
+
24
+ to generate a query, the Builder class provides a number of methods to construct it's arguments:
25
+
26
+ builder.table('music.artists')
27
+ builder.select('name, genre')
28
+ builder.conditions("bands = 'false'")
29
+ builder.sort('age')
30
+
31
+ conditions are also aliased as 'where':
32
+
33
+ #using 'where'
34
+ builder.where("bands = 'true'")
35
+
36
+ # is the same thing as
37
+ builder.conditions("bands = 'true'")
38
+
39
+ conditions can be passed as either a string, an array or
40
+
41
+ builder.conditions(["name = 'Erykah Badu'", "release_year > '2005'"])
42
+
43
+ methods can be chained together:
44
+
45
+ builder.table('music.artists').select('name').where("genre = 'jazz'")
46
+
47
+ to generate the query, just call to_s or to_query:
48
+
49
+ builder.to_s
50
+ # => 'select * from tablename...'
51
+
52
+ builder.to_query
53
+ # => 'select * from tablename...'
54
+
55
+ passing a hash with a Builder instance to creates sub-select:
56
+
57
+ guid_query = Builder.new.table('users').select('guid').where("role = 'admin'")
58
+
59
+ builder = Builder.new.table('actions).where(:guid => guid_query)
60
+ builder.to_s
61
+ # => "select * from actions where guid in (select guid from users where role = 'admin')"
62
+
63
+ The full list of methods available:
64
+
65
+ table('music.albums')
66
+ use('http://somedomain.com/table.xml', 'othersource')
67
+ select('name')
68
+ conditions("genre = 'jazz'")
69
+ sort('albumName')
70
+ sort_descending('albumName')
71
+ limit(5)
72
+ offset(10)
73
+ tail(5)
74
+ truncate(10)
75
+ unique('format')
76
+ sanitize('description')
77
+
78
+ Refer to the [documentation](http://rdoc.info/gems/yql-query) for complete usage and more examples.
79
+
80
+ Note on Patches/Pull Requests
81
+ -----------------------------
82
+
83
+ * Fork the project.
84
+ * Make your feature addition or bug fix.
85
+ * Add tests for it. This is important so I don't break it in a
86
+ future version unintentionally.
87
+ * Commit, do not mess with rakefile, version, or history.
88
+ (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
89
+ * Send me a pull request. Bonus points for topic branches.
90
+
91
+ Copyright
92
+ ---------
93
+
94
+ Copyright (c) 2011 Steve Agalloco. See LICENSE for details.
@@ -0,0 +1 @@
1
+ require 'yql_query'
@@ -0,0 +1,4 @@
1
+ require 'hashie/mash'
2
+ require 'yql_query/source'
3
+ require 'yql_query/query'
4
+ require 'yql_query/builder'
@@ -0,0 +1,244 @@
1
+ module YqlQuery
2
+
3
+ # The primary query builder class, wraps a {Query} object and provides methods to assign query arguments.
4
+ class Builder
5
+
6
+ attr_accessor :query
7
+
8
+ # Instantiates a new Builder instance.
9
+ # @param
10
+ def initialize(options={})
11
+ self.query = Query.new
12
+ self.query.table = options.delete(:table)
13
+ self.query.limit = options.delete(:limit)
14
+ self.query.offset = options.delete(:offset)
15
+ self.query.select = options.delete(:select)
16
+ self.query.conditions = options.delete(:conditions) || []
17
+ self.query.uses = options.delete(:uses) || []
18
+ self.query.tail = options.delete(:tail)
19
+ self.query.truncate = options.delete(:truncate)
20
+ self.query.reverse = options.delete(:reverse)
21
+ self.query.unique = options.delete(:unique)
22
+ self.query.sanitize = options.delete(:sanitize)
23
+ end
24
+
25
+ # Assigns the table for the query being constructed
26
+ #
27
+ # @param [String] table The name of the table.
28
+ # @return [YqlQuery::Builder] YqlQuery::Builder instance reflecting the table assigned.
29
+ def table(table)
30
+ self.query.table = table
31
+ self
32
+ end
33
+
34
+ # Assigns the limit for the query being constructed
35
+ #
36
+ # @param [Object] limit The limit for the query.
37
+ # @return [YqlQuery::Builder] YqlQuery::Builder instance reflecting the limit assigned.
38
+ #
39
+ # @example The limit may be passed as either a string or fixnum:
40
+ # base = Builder.new.limit(5)
41
+ # base = Builder.new.limit('5')
42
+ def limit(limit)
43
+ self.query.limit = limit
44
+ self
45
+ end
46
+
47
+ # Assigns the offset for the query being constructed
48
+ #
49
+ # @param [Object] offset The offset for the query.
50
+ # @return [YqlQuery::Builder] YqlQuery::Builder instance reflecting the offset assigned.
51
+ #
52
+ # @example The offset may be passed as either a string or fixnum:
53
+ # base = Builder.new.offset(5)
54
+ # base = Builder.new.offset('5')
55
+ def offset(offset)
56
+ self.query.offset = offset
57
+ self
58
+ end
59
+
60
+ # Assigns the columns to select for the query being constructed
61
+ #
62
+ # @param [Object] select The select arguments for the query.
63
+ # @return [YqlQuery::Builder] YqlQuery::Builder instance reflecting the select arguments assigned.
64
+ #
65
+ # @example The select may be passed as either a string or an array:
66
+ # base = Builder.new.select('name')
67
+ # base = Builder.new.select('name, age')
68
+ # base = Builder.new.select(['name', 'age'])
69
+ def select(select)
70
+ self.query.select = select
71
+ self
72
+ end
73
+
74
+ # Assigns additional datatable sources for use with the query being constructed
75
+ #
76
+ # @param [String] source The url of the data source.
77
+ # @param [String] as The name the data source will be referenced as in queries.
78
+ # @return [YqlQuery::Builder] YqlQuery::Builder instance reflecting the data source arguments assigned.
79
+ #
80
+ # @example The select may be passed as either a string or an array:
81
+ # base = Builder.new.use('http://anothersource/sometable.xml', 'sometable')
82
+ # base.to_s
83
+ # # => "use http://anothersource/sometable.xml as sometable; select * from tablename"
84
+ def use(source, as)
85
+ self.query.uses << Source.new(source, as)
86
+ self
87
+ end
88
+
89
+ # Assigns additional datatable sources for use with the query being constructed.
90
+ # Conditions are combined. Hashes assume equivalency when generating queries, except when passed a
91
+ # {Builder} instance in which case a sub-select is assumed using an 'in'.
92
+ #
93
+ # @param [Objct] conditions The conditions of the query.
94
+ # @return [YqlQuery::Builder] YqlQuery::Builder instance reflecting the data conditions assigned.
95
+ #
96
+ # @example The conditions may be passed as either a string, array or a hash:
97
+ # base = Builder.new.conditions("sub_genre = 'bebop'")
98
+ # base.to_s
99
+ # # => "select * from tablename where sub_genre = 'bebop'"
100
+ #
101
+ # base.conditions("genre = 'jazz'").conditions("sub_genre = 'bebop'")
102
+ # base.to_s
103
+ # # => "select * from tablename where genre = 'jazz' and sub_genre = 'bebop'"
104
+ #
105
+ # base.conditions(["genre = 'jazz'", "sub_genre = 'bebop'"])
106
+ # # => "select * from tablename where genre = 'jazz' and sub_genre = 'bebop'"
107
+ #
108
+ # # conditions are also aliased as 'where'
109
+ # base.where("genre = 'jazz'")
110
+ #
111
+ # guid_query = Builder.new.table('users').select('guid').where("role = 'admin'")
112
+ # base = Builder.new.table('actions).where(:guid => guid_query)
113
+ # base.to_s
114
+ # => "select * from actions where guid in (select guid from users where role = 'admin')"
115
+ def conditions(conditions)
116
+ if conditions.kind_of?(String)
117
+ self.query.conditions << conditions
118
+ elsif conditions.kind_of?(Array)
119
+ self.query.conditions += conditions
120
+ elsif conditions.kind_of?(Hash)
121
+ conditions.each do |key, value|
122
+ if value.kind_of?(YqlQuery::Builder)
123
+ self.query.conditions << "#{key} in (#{value})"
124
+ else
125
+ self.query.conditions << "#{key} = '#{value}'"
126
+ end
127
+ end
128
+ end
129
+ self
130
+ end
131
+ alias :where :conditions
132
+
133
+ # Assigns the field to be sorted for the query being constructed
134
+ #
135
+ # @param [Object] sort The column to sort for the query.
136
+ # @return [YqlQuery::Builder] YqlQuery::Builder instance reflecting the sort assigned.
137
+ #
138
+ # @example
139
+ # base = Builder.new.sort('name)
140
+ def sort(sort)
141
+ self.query.sort = sort
142
+ self.query.sort_descending = false
143
+ self
144
+ end
145
+
146
+ # Assigns the field to be sorted for the query being constructed
147
+ #
148
+ # @param [Object] sort The column to sort descending for the query.
149
+ # @return [YqlQuery::Builder] YqlQuery::Builder instance reflecting the sort assigned.
150
+ #
151
+ # @example
152
+ # base = Builder.new.sort('name)
153
+ def sort_descending(sort)
154
+ self.query.sort = sort
155
+ self.query.sort_descending = true
156
+ self
157
+ end
158
+
159
+ # Assigns the tail argument for the query being constructed
160
+ #
161
+ # @param [Object] tail The tail argument for the query.
162
+ # @return [YqlQuery::Builder] YqlQuery::Builder instance reflecting the tail filter assigned.
163
+ #
164
+ # @example The tail argument may be passed as either a string or fixnum:
165
+ # base = Builder.new.tail(5)
166
+ # base = Builder.new.tail('5')
167
+ def tail(tail)
168
+ self.query.tail = tail
169
+ self
170
+ end
171
+
172
+ # Assigns the truncate argument for the query being constructed
173
+ #
174
+ # @param [Object] truncate The truncate argument for the query.
175
+ # @return [YqlQuery::Builder] YqlQuery::Builder instance reflecting the truncate filter assigned.
176
+ #
177
+ # @example The truncate argument may be passed as either a string or fixnum:
178
+ # base = Builder.new.truncate(5)
179
+ # base = Builder.new.truncate('5')
180
+ # base.to_s
181
+ # # => "select * from tablename | truncate(5)"
182
+ def truncate(truncate)
183
+ self.query.truncate = truncate
184
+ self
185
+ end
186
+
187
+ # Adds the reverse filter to the query being constructed
188
+ #
189
+ # @return [YqlQuery::Builder] YqlQuery::Builder instance reflecting the offset assigned.
190
+ #
191
+ # @example
192
+ # base = Builder.new.reverse
193
+ # base.to_s
194
+ # # => "select * from tablename | reverse"
195
+ def reverse
196
+ self.query.reverse = true
197
+ self
198
+ end
199
+
200
+ # Assigns the unique argument for the query being constructed
201
+ #
202
+ # @param [Object] truncate The unique argument for the query.
203
+ # @return [YqlQuery::Builder] YqlQuery::Builder instance reflecting the unique filter assigned.
204
+ #
205
+ # @example
206
+ # base = Builder.new.unique('genre')
207
+ # base.to_s
208
+ # # => "select * from tablename | unique(field='genre')"
209
+ def unique(unique)
210
+ self.query.unique = unique
211
+ self
212
+ end
213
+
214
+ # Assigns the sanitize argument for the query being constructed
215
+ #
216
+ # @param [Object] sanitize The sanitize argument for the query.
217
+ # @return [YqlQuery::Builder] YqlQuery::Builder instance reflecting the sanitize filter assigned.
218
+ #
219
+ # @example Sanitize accepts either a string representing the column name or a boolean 'true' to sanitize all
220
+ # base = Builder.new.sanitize('genre')
221
+ # base.to_s
222
+ # # => "select * from tablename | sanitize(field='genre')"
223
+ #
224
+ # base = Builder.new.sanitize(true)
225
+ # base.to_s
226
+ # # => "select * from tablename | sanitize()"
227
+ def sanitize(sanitize=true)
228
+ self.query.sanitize = sanitize
229
+ self
230
+ end
231
+
232
+ # Returns the generated YQL query based on the arguments provided
233
+ def to_s
234
+ self.query.to_s
235
+ end
236
+ alias :to_query :to_s
237
+
238
+ # Resets all arguments to the query
239
+ def reset
240
+ self.query = Query.new
241
+ end
242
+
243
+ end
244
+ end
@@ -0,0 +1,70 @@
1
+ module YqlQuery
2
+
3
+ # The object underlying {Builder} which stores and generates the query.
4
+ class Query
5
+ attr_accessor :table, :limit, :offset, :select, :uses, :conditions
6
+ attr_accessor :sort, :tail, :truncate, :reverse, :unique, :sanitize
7
+ attr_accessor :sort_descending
8
+
9
+ def initialize
10
+ self.conditions = []
11
+ self.uses = []
12
+ end
13
+
14
+ # generates a query based on it's attributes
15
+ def to_s
16
+ [use_statement, select_statement, conditions_statement, limit_offset_statement, filter_statement].join(' ').squeeze(' ').strip
17
+ end
18
+
19
+ private
20
+ def use_statement
21
+ @uses.map { |use| "use #{use.source} as #{use.as};" }.join(' ')
22
+ end
23
+
24
+ def select_statement
25
+ stmt = 'select '
26
+ stmt << case @select
27
+ when String
28
+ @select
29
+ when Array
30
+ @select.join(', ')
31
+ else
32
+ '*'
33
+ end
34
+ stmt << " from "
35
+ stmt << @table if @table
36
+ stmt
37
+ end
38
+
39
+ def conditions_statement
40
+ @conditions.uniq.any? ? "where #{@conditions.uniq.join(' and ')}" : ""
41
+ end
42
+
43
+ def limit_offset_statement
44
+ stmt = ''
45
+ stmt << "limit #{@limit}" if @limit
46
+ stmt << "offset #{@offset}" if @offset
47
+ stmt
48
+ end
49
+
50
+ def filter_statement
51
+ statements = []
52
+ if @sort && @sort_descending
53
+ statements << "sort(field='#{@sort}', descending='true')"
54
+ elsif @sort
55
+ statements << "sort(field='#{@sort}')"
56
+ end
57
+
58
+ statements << "tail(count=#{@tail})" if @tail
59
+ statements << "truncate(count=#{@truncate})" if @truncate
60
+ statements << "reverse()" if @reverse
61
+ statements << "unique(field='#{@unique}')" if @unique
62
+ if @sanitize && @sanitize == true
63
+ statements << "sanitize()"
64
+ elsif @sanitize
65
+ statements << "sanitize(field='#{@sanitize}')"
66
+ end
67
+ statements.any? ? "| #{statements.join(' | ')}" : ''
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,17 @@
1
+ module YqlQuery
2
+
3
+ # A class used by {Builder} to store additional data sources.
4
+ class Source
5
+ attr_accessor :source, :as
6
+
7
+ def initialize(source, as)
8
+ @source = source
9
+ @as = as
10
+ end
11
+
12
+ # Sources are equal if both their 'source' and 'as' attributes are equivalent.
13
+ def ==(b)
14
+ self.source == b.source && self.as == b.as
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,4 @@
1
+ module YqlQuery
2
+ # The version of the gem
3
+ VERSION = "1.0.0"
4
+ end
@@ -0,0 +1,9 @@
1
+ require 'simplecov'
2
+ SimpleCov.start do
3
+ add_group 'YQL Query', 'lib/yql_query'
4
+ add_group 'Specs', 'spec'
5
+ end
6
+
7
+ require File.expand_path('../../lib/yql_query', __FILE__)
8
+
9
+ require 'rspec'
@@ -0,0 +1,330 @@
1
+ require File.expand_path('../spec_helper', __FILE__)
2
+
3
+ describe YqlQuery::Builder do
4
+ before(:each) do
5
+ @builder = YqlQuery::Builder.new
6
+ end
7
+
8
+ describe "#table()" do
9
+ it "should set the table" do
10
+ @builder.table('music.artists')
11
+ @builder.query.table.should == 'music.artists'
12
+ end
13
+
14
+ it "should return the builder" do
15
+ @builder.table('music.artists').should be_kind_of(YqlQuery::Builder)
16
+ end
17
+ end
18
+
19
+ describe "#limit()" do
20
+ it "should set the limit" do
21
+ @builder.limit(5)
22
+ @builder.query.limit.should == 5
23
+ end
24
+
25
+ it "should return the builder" do
26
+ @builder.limit(5).should be_kind_of(YqlQuery::Builder)
27
+ end
28
+ end
29
+
30
+ describe "#offset()" do
31
+ it "should set the offset" do
32
+ @builder.offset(10)
33
+ @builder.query.offset.should == 10
34
+ end
35
+
36
+ it "should return the builder" do
37
+ @builder.offset(10).should be_kind_of(YqlQuery::Builder)
38
+ end
39
+ end
40
+
41
+ describe "#select()" do
42
+ it "should set the select" do
43
+ @builder.select('name')
44
+ @builder.query.select.should == 'name'
45
+ end
46
+
47
+ it "should accept select as an array" do
48
+ @builder.select(['age', 'sex', 'language', 'other'])
49
+ @builder.query.select.should == ['age', 'sex', 'language', 'other']
50
+ end
51
+
52
+ it "should return the builder" do
53
+ @builder.select('name').should be_kind_of(YqlQuery::Builder)
54
+ end
55
+ end
56
+
57
+ describe "#use()" do
58
+ it "should set the use" do
59
+ @builder.use('http://namedata.com', 'names')
60
+ @builder.query.uses.include?(YqlQuery::Source.new('http://namedata.com', 'names')).should be_true
61
+ end
62
+
63
+ it "should return the builder" do
64
+ @builder.use('http://namedata.com', 'names').should be_kind_of(YqlQuery::Builder)
65
+ end
66
+ end
67
+
68
+ describe "#conditions()" do
69
+ it "should set the conditions" do
70
+ @builder.conditions("name = 'fred'")
71
+ @builder.query.conditions.include?("name = 'fred'").should be_true
72
+ end
73
+
74
+ it "should return the builder" do
75
+ @builder.conditions("name = 'fred'").should be_kind_of(YqlQuery::Builder)
76
+ end
77
+
78
+ it "should be aliased as #where()" do
79
+ @builder.where("name = 'jeff'")
80
+ @builder.query.conditions.include?("name = 'jeff'").should be_true
81
+ end
82
+
83
+ it "should store all conditions" do
84
+ @builder.conditions("name = 'fred'")
85
+ @builder.conditions("age = 22")
86
+ @builder.query.conditions.include?("name = 'fred'").should be_true
87
+ @builder.query.conditions.include?("age = 22").should be_true
88
+ end
89
+
90
+ it "should accept conditions as an array" do
91
+ @builder.conditions(["name = 'greg'", "age = 34"])
92
+ @builder.query.conditions.include?("name = 'greg'").should be_true
93
+ @builder.query.conditions.include?("age = 34").should be_true
94
+ end
95
+
96
+ it "should accept conditions as a hash" do
97
+ @builder.conditions({ :genre => 'jazz', :type => 'bebop'})
98
+ @builder.query.conditions.include?("genre = 'jazz'").should be_true
99
+ @builder.query.conditions.include?("type = 'bebop'").should be_true
100
+ end
101
+
102
+ it "should accept conditions as a hash when passed another query" do
103
+ @builder.conditions({ :artist_id => YqlQuery::Builder.new.table('music.amg.artists').select('artist_id')})
104
+ @builder.query.conditions.include?("artist_id in (select artist_id from music.amg.artists)").should be_true
105
+ end
106
+ end
107
+
108
+ describe "#sort()" do
109
+ it "should set the sort" do
110
+ @builder.sort('nickname')
111
+ @builder.query.sort.should == 'nickname'
112
+ end
113
+
114
+ it "should return the builder" do
115
+ @builder.sort('nickname').should be_kind_of(YqlQuery::Builder)
116
+ end
117
+ end
118
+
119
+ describe "#sort_descending()" do
120
+ it "should set the sort" do
121
+ @builder.sort_descending('nickname')
122
+ @builder.query.sort.should == 'nickname'
123
+ end
124
+
125
+ it "should return the builder" do
126
+ @builder.sort('nickname').should be_kind_of(YqlQuery::Builder)
127
+ end
128
+ end
129
+
130
+ describe "#tail()" do
131
+ it "should set the tail" do
132
+ @builder.tail(3)
133
+ @builder.query.tail.should == 3
134
+ end
135
+
136
+ it "should return the builder" do
137
+ @builder.tail(3).should be_kind_of(YqlQuery::Builder)
138
+ end
139
+ end
140
+
141
+ describe "#truncate()" do
142
+ it "should set the truncate option" do
143
+ @builder.truncate(3)
144
+ @builder.query.truncate.should == 3
145
+ end
146
+
147
+ it "should return the builder" do
148
+ @builder.truncate(3).should be_kind_of(YqlQuery::Builder)
149
+ end
150
+ end
151
+
152
+ describe "#reverse" do
153
+ it "should set the reverse option" do
154
+ @builder.reverse
155
+ @builder.query.reverse.should be_true
156
+ end
157
+
158
+ it "should return the builder" do
159
+ @builder.reverse.should be_kind_of(YqlQuery::Builder)
160
+ end
161
+ end
162
+
163
+ describe "#unique()" do
164
+ it "should set the unique option" do
165
+ @builder.unique("Rating.AverageRating")
166
+ @builder.query.unique.should == "Rating.AverageRating"
167
+ end
168
+
169
+ it "should return the builder" do
170
+ @builder.unique("Rating.AverageRating").should be_kind_of(YqlQuery::Builder)
171
+ end
172
+ end
173
+
174
+ describe "#sanitize()" do
175
+ it "should set the unique option" do
176
+ @builder.sanitize("Rating.Description")
177
+ @builder.query.sanitize.should == "Rating.Description"
178
+ end
179
+
180
+ it "should default sanitize to true" do
181
+ @builder.sanitize
182
+ @builder.query.sanitize.should be_true
183
+ end
184
+
185
+ it "should return the builder" do
186
+ @builder.sanitize("Rating.Description").should be_kind_of(YqlQuery::Builder)
187
+ end
188
+ end
189
+
190
+ context "chaining" do
191
+ it "should combine query options" do
192
+ @builder.table('music.artists').limit(5).conditions("name = 'Jose James'")
193
+ @builder.query.limit.should == 5
194
+ @builder.query.table.should == 'music.artists'
195
+ @builder.query.conditions.include?("name = 'Jose James'").should be_true
196
+ end
197
+ end
198
+
199
+ describe "#to_s" do
200
+ it "should return the generated query" do
201
+ @builder.table('music.artists').limit(5).conditions("name = 'Jose James'")
202
+ @builder.to_s.should == "select * from music.artists where name = 'Jose James' limit 5"
203
+ end
204
+
205
+ it "should be aliased as to_query" do
206
+ @builder.table('music.artists').limit(5).conditions("name = 'Jose James'")
207
+ @builder.to_s.should == @builder.to_query
208
+ end
209
+ end
210
+
211
+ describe "#reset" do
212
+ it "should reset all query conditions" do
213
+ @builder.table('Rating')
214
+ @builder.limit(5)
215
+ @builder.offset(5)
216
+ @builder.select('Rating.Description, Rating.SomethingElse')
217
+ @builder.use('http://namedata.com', 'names')
218
+ @builder.conditions("name = 'fred'")
219
+ @builder.sort('nickname')
220
+ @builder.tail(5)
221
+ @builder.truncate(3)
222
+ @builder.reverse
223
+ @builder.unique("Rating.AverageRating")
224
+ @builder.sanitize("Rating.Description")
225
+
226
+ @builder.reset
227
+
228
+ @builder.query.table.should be_nil
229
+ @builder.query.limit.should be_nil
230
+ @builder.query.offset.should be_nil
231
+ @builder.query.select.should be_nil
232
+ @builder.query.limit.should be_nil
233
+ @builder.query.uses.should be_empty
234
+ @builder.query.conditions.should be_empty
235
+ @builder.query.sort.should be_nil
236
+ @builder.query.tail.should be_nil
237
+ @builder.query.truncate.should be_nil
238
+ @builder.query.reverse.should be_nil
239
+ @builder.query.unique.should be_nil
240
+ @builder.query.sanitize.should be_nil
241
+ end
242
+ end
243
+
244
+ context "generating queries" do
245
+ before(:each) do
246
+ @builder.table('music.artists')
247
+ end
248
+
249
+ it "should generate ther right query when given a different data source to use" do
250
+ @builder.conditions("name = 'Jose James'").use('http://musicbrainz.org/data.xml', 'musicBrainzArtists').table('musicBrainzArtists')
251
+ @builder.to_s.should == "use http://musicbrainz.org/data.xml as musicBrainzArtists; select * from musicBrainzArtists where name = 'Jose James'"
252
+ end
253
+
254
+ it "should generate ther right query when given multiple data sources to use" do
255
+ @builder.conditions("name = 'Jose James'").use('http://musicbrainz.org/data.xml', 'musicBrainzArtists').use('http://musicbrainz.org/albums.xml', 'musicBrainzAlbums').table('musicBrainzArtists')
256
+ @builder.to_s.should == "use http://musicbrainz.org/data.xml as musicBrainzArtists; use http://musicbrainz.org/albums.xml as musicBrainzAlbums; select * from musicBrainzArtists where name = 'Jose James'"
257
+ end
258
+
259
+ it "should generate the right query when given a single condition" do
260
+ @builder.conditions("name = 'Jose James'")
261
+ @builder.to_s.should == "select * from music.artists where name = 'Jose James'"
262
+ end
263
+
264
+ it "should generate the right query when given multiple conditions" do
265
+ @builder.conditions("name = 'Jose James'").conditions("genre = 'Jazz'")
266
+ @builder.to_s.should == "select * from music.artists where name = 'Jose James' and genre = 'Jazz'"
267
+ end
268
+
269
+ it "should generate the right query when given a limit" do
270
+ @builder.conditions("name = 'John'").limit(5)
271
+ @builder.to_s.should == "select * from music.artists where name = 'John' limit 5"
272
+ end
273
+
274
+ it "should generate the right query when given an offset" do
275
+ @builder.conditions("name = 'John'").offset(15)
276
+ @builder.to_s.should == "select * from music.artists where name = 'John' offset 15"
277
+ end
278
+
279
+ it "should generate the right query when given a select" do
280
+ @builder.conditions("name = 'John'").select('Title, First Name, Email')
281
+ @builder.to_s.should == "select Title, First Name, Email from music.artists where name = 'John'"
282
+ end
283
+
284
+ it "should generate the right query when given a select as an array" do
285
+ @builder.conditions("name = 'John'").select(['age', 'sex', 'language', 'other'])
286
+ @builder.to_s.should == "select age, sex, language, other from music.artists where name = 'John'"
287
+ end
288
+
289
+ it "should generate the right query when given a sort" do
290
+ @builder.sort('popularity')
291
+ @builder.to_s.should == "select * from music.artists | sort(field='popularity')"
292
+ end
293
+
294
+ it "should generate the right query when given a sort descending" do
295
+ @builder.sort_descending('popularity')
296
+ @builder.to_s.should == "select * from music.artists | sort(field='popularity', descending='true')"
297
+ end
298
+
299
+ it "should generate the right query when given a tail" do
300
+ @builder.tail(5)
301
+ @builder.to_s.should == "select * from music.artists | tail(count=5)"
302
+ end
303
+
304
+ it "should generate the right query when given a truncate" do
305
+ @builder.truncate(5)
306
+ @builder.to_s.should == "select * from music.artists | truncate(count=5)"
307
+ end
308
+
309
+ it "should generate the right query when given a reverse" do
310
+ @builder.reverse
311
+ @builder.to_s.should == "select * from music.artists | reverse()"
312
+ end
313
+
314
+ it "should generate the right query when given a unique" do
315
+ @builder.unique('art')
316
+ @builder.to_s.should == "select * from music.artists | unique(field='art')"
317
+ end
318
+
319
+ it "should generate the right query when given a sanitize" do
320
+ @builder.sanitize('art')
321
+ @builder.to_s.should == "select * from music.artists | sanitize(field='art')"
322
+ end
323
+
324
+ it "should generate the right query when given a sanitize all fields" do
325
+ @builder.sanitize
326
+ @builder.to_s.should == "select * from music.artists | sanitize()"
327
+ end
328
+ end
329
+
330
+ end
@@ -0,0 +1,11 @@
1
+ require File.expand_path('../spec_helper', __FILE__)
2
+
3
+ describe YqlQuery::Source do
4
+ before(:each) do
5
+ @use_case = YqlQuery::Source.new('http://geodata.org/table.xml', 'geodata')
6
+ end
7
+
8
+ it "should be equivalent if both the source and as are equal" do
9
+ @use_case.should == YqlQuery::Source.new('http://geodata.org/table.xml', 'geodata')
10
+ end
11
+ end
@@ -0,0 +1,30 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "yql_query/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "yql-query"
7
+ s.version = YqlQuery::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Steve Agalloco"]
10
+ s.email = ["steve.agalloco@gmail.com"]
11
+ s.homepage = "https://github.com/spagalloco/yql-query"
12
+ s.summary = %q{A YQL Query generator}
13
+ s.description = %q{A YQL Query generator}
14
+
15
+ s.rubyforge_project = "yql-query"
16
+
17
+ s.add_runtime_dependency('hashie', '~> 1.0.0')
18
+
19
+ s.add_development_dependency('bundler', '~> 1.0')
20
+ s.add_development_dependency('rake', '~> 0.8')
21
+ s.add_development_dependency('rspec', '~> 2.5.0')
22
+ s.add_development_dependency('yard', '~> 0.6')
23
+ s.add_development_dependency('maruku', '~> 0.6')
24
+ s.add_development_dependency('simplecov', '~> 0.3')
25
+
26
+ s.files = `git ls-files`.split("\n")
27
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
28
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
29
+ s.require_paths = ["lib"]
30
+ end
metadata ADDED
@@ -0,0 +1,150 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: yql-query
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 1.0.0
6
+ platform: ruby
7
+ authors:
8
+ - Steve Agalloco
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2011-02-22 00:00:00 -05:00
14
+ default_executable:
15
+ dependencies:
16
+ - !ruby/object:Gem::Dependency
17
+ name: hashie
18
+ prerelease: false
19
+ requirement: &id001 !ruby/object:Gem::Requirement
20
+ none: false
21
+ requirements:
22
+ - - ~>
23
+ - !ruby/object:Gem::Version
24
+ version: 1.0.0
25
+ type: :runtime
26
+ version_requirements: *id001
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ prerelease: false
30
+ requirement: &id002 !ruby/object:Gem::Requirement
31
+ none: false
32
+ requirements:
33
+ - - ~>
34
+ - !ruby/object:Gem::Version
35
+ version: "1.0"
36
+ type: :development
37
+ version_requirements: *id002
38
+ - !ruby/object:Gem::Dependency
39
+ name: rake
40
+ prerelease: false
41
+ requirement: &id003 !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ~>
45
+ - !ruby/object:Gem::Version
46
+ version: "0.8"
47
+ type: :development
48
+ version_requirements: *id003
49
+ - !ruby/object:Gem::Dependency
50
+ name: rspec
51
+ prerelease: false
52
+ requirement: &id004 !ruby/object:Gem::Requirement
53
+ none: false
54
+ requirements:
55
+ - - ~>
56
+ - !ruby/object:Gem::Version
57
+ version: 2.5.0
58
+ type: :development
59
+ version_requirements: *id004
60
+ - !ruby/object:Gem::Dependency
61
+ name: yard
62
+ prerelease: false
63
+ requirement: &id005 !ruby/object:Gem::Requirement
64
+ none: false
65
+ requirements:
66
+ - - ~>
67
+ - !ruby/object:Gem::Version
68
+ version: "0.6"
69
+ type: :development
70
+ version_requirements: *id005
71
+ - !ruby/object:Gem::Dependency
72
+ name: maruku
73
+ prerelease: false
74
+ requirement: &id006 !ruby/object:Gem::Requirement
75
+ none: false
76
+ requirements:
77
+ - - ~>
78
+ - !ruby/object:Gem::Version
79
+ version: "0.6"
80
+ type: :development
81
+ version_requirements: *id006
82
+ - !ruby/object:Gem::Dependency
83
+ name: simplecov
84
+ prerelease: false
85
+ requirement: &id007 !ruby/object:Gem::Requirement
86
+ none: false
87
+ requirements:
88
+ - - ~>
89
+ - !ruby/object:Gem::Version
90
+ version: "0.3"
91
+ type: :development
92
+ version_requirements: *id007
93
+ description: A YQL Query generator
94
+ email:
95
+ - steve.agalloco@gmail.com
96
+ executables: []
97
+
98
+ extensions: []
99
+
100
+ extra_rdoc_files: []
101
+
102
+ files:
103
+ - .gitignore
104
+ - .rspec
105
+ - Gemfile
106
+ - License.md
107
+ - Rakefile
108
+ - Readme.md
109
+ - lib/yql-query.rb
110
+ - lib/yql_query.rb
111
+ - lib/yql_query/builder.rb
112
+ - lib/yql_query/query.rb
113
+ - lib/yql_query/source.rb
114
+ - lib/yql_query/version.rb
115
+ - spec/spec_helper.rb
116
+ - spec/yql_query_builder_spec.rb
117
+ - spec/yql_query_source_spec.rb
118
+ - yql-query.gemspec
119
+ has_rdoc: true
120
+ homepage: https://github.com/spagalloco/yql-query
121
+ licenses: []
122
+
123
+ post_install_message:
124
+ rdoc_options: []
125
+
126
+ require_paths:
127
+ - lib
128
+ required_ruby_version: !ruby/object:Gem::Requirement
129
+ none: false
130
+ requirements:
131
+ - - ">="
132
+ - !ruby/object:Gem::Version
133
+ version: "0"
134
+ required_rubygems_version: !ruby/object:Gem::Requirement
135
+ none: false
136
+ requirements:
137
+ - - ">="
138
+ - !ruby/object:Gem::Version
139
+ version: "0"
140
+ requirements: []
141
+
142
+ rubyforge_project: yql-query
143
+ rubygems_version: 1.5.0
144
+ signing_key:
145
+ specification_version: 3
146
+ summary: A YQL Query generator
147
+ test_files:
148
+ - spec/spec_helper.rb
149
+ - spec/yql_query_builder_spec.rb
150
+ - spec/yql_query_source_spec.rb