yql-query 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.
@@ -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