yql 0.0.1
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/History.txt +4 -0
- data/Manifest.txt +7 -0
- data/README.rdoc +105 -0
- data/lib/yql.rb +12 -0
- data/lib/yql/client.rb +61 -0
- data/lib/yql/error.rb +19 -0
- data/lib/yql/query_builder.rb +186 -0
- metadata +69 -0
data/History.txt
ADDED
data/Manifest.txt
ADDED
data/README.rdoc
ADDED
@@ -0,0 +1,105 @@
|
|
1
|
+
==DESCRIPTION
|
2
|
+
|
3
|
+
A basic Ruby Wrapper for interacting programatically with YQL API.
|
4
|
+
|
5
|
+
|
6
|
+
==TODO
|
7
|
+
|
8
|
+
1. Add Unit Tests
|
9
|
+
2. Add oauth
|
10
|
+
3. Add table creation
|
11
|
+
4. Add update / insert / delete operations
|
12
|
+
|
13
|
+
==INSTALLATION
|
14
|
+
|
15
|
+
sudo gem source --add http://rubygems.org
|
16
|
+
|
17
|
+
sudo gem install yql
|
18
|
+
|
19
|
+
|
20
|
+
==USAGE
|
21
|
+
|
22
|
+
require 'rubygems'
|
23
|
+
|
24
|
+
require 'yql'
|
25
|
+
|
26
|
+
===Building Query
|
27
|
+
|
28
|
+
|
29
|
+
====Finders
|
30
|
+
|
31
|
+
yql = Yql::Client.new
|
32
|
+
|
33
|
+
query = Yql::QueryBuilder.new 'yelp.review.search'
|
34
|
+
|
35
|
+
query.to_s #=> "select * from yelp.review.search"
|
36
|
+
|
37
|
+
query.find #=> "select * from yelp.review.search limit 1"
|
38
|
+
|
39
|
+
query.limit = 4
|
40
|
+
|
41
|
+
query.to_s #=> "select * from yelp.review.search limit 4"
|
42
|
+
|
43
|
+
query.find_all #=> "select * from yelp.review.search"
|
44
|
+
|
45
|
+
|
46
|
+
====Conditions
|
47
|
+
|
48
|
+
query.conditions = "term like '%pizza%'"
|
49
|
+
|
50
|
+
query.to_s #=> "select * from yelp.review.search where term='%pizza%'"
|
51
|
+
|
52
|
+
query.conditions = {:term => 'pizza'}
|
53
|
+
|
54
|
+
query.to_s #=> "select * from yelp.review.search where term = 'pizza'"
|
55
|
+
|
56
|
+
query.conditions = {:term => 'pizza', :location => 'london', 'ywsid' => '6L0Lc-yn1OKMkCKeXLD4lg'}
|
57
|
+
|
58
|
+
query.to_s #=> "select * from yelp.review.search where term='pizza' and location='london' and ywsid= '6L0Lc-yn1OKMkCKeXLD4lg'"
|
59
|
+
|
60
|
+
query.select = 'user_photo_url, state'
|
61
|
+
|
62
|
+
yql.query = query
|
63
|
+
response = yql.get
|
64
|
+
|
65
|
+
yql.format = 'json'
|
66
|
+
response = yql.get #=> Yql::Response object
|
67
|
+
|
68
|
+
|
69
|
+
===Piped Filters
|
70
|
+
|
71
|
+
query.unique = 'name'
|
72
|
+
|
73
|
+
query.to_s #=> "select title, Rating, LastReviewIntro from yelp.review.search where ywsid='6L0Lc-yn1OKMkCKeXLD4lg' and term='pizza' and location='london' | unique(field='name')"
|
74
|
+
|
75
|
+
query.tail = 4
|
76
|
+
|
77
|
+
query.to_s #=> "select title, Rating, LastReviewIntro from yelp.review.search where ywsid='6L0Lc-yn1OKMkCKeXLD4lg' and term='pizza' and location='london' | unique(field='name') | tail(count=4)"
|
78
|
+
|
79
|
+
query.reorder_pipe_command :from => 1, :to => 0
|
80
|
+
|
81
|
+
query.to_s #=> "select title, Rating, LastReviewIntro from yelp.review.search where ywsid='6L0Lc-yn1OKMkCKeXLD4lg' and term='pizza' and location='london' | tail(count=4) | unique(field='name')"
|
82
|
+
|
83
|
+
yql.format = 'json'
|
84
|
+
response = yql.get #=> Yql::Response object
|
85
|
+
|
86
|
+
|
87
|
+
====Pagination
|
88
|
+
|
89
|
+
query.per_page = 10
|
90
|
+
query.current_page = 1
|
91
|
+
|
92
|
+
yql.query = query
|
93
|
+
response = yql.get #=> Yql::Response object
|
94
|
+
|
95
|
+
|
96
|
+
===Describe and show tables
|
97
|
+
|
98
|
+
query = Yql::QueryBuilder.describe_table('yelp.review.search')
|
99
|
+
|
100
|
+
query = Yql::QueryBuilder.show_tables
|
101
|
+
|
102
|
+
yql.query = query
|
103
|
+
response = yql.get #=> Yql::Response object
|
104
|
+
|
105
|
+
response.show
|
data/lib/yql.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
$:.unshift(File.dirname(__FILE__)) unless
|
2
|
+
$:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
|
3
|
+
|
4
|
+
require 'rubygems'
|
5
|
+
require 'CGI'
|
6
|
+
require 'net/http'
|
7
|
+
require 'net/https'
|
8
|
+
require 'rexml/document'
|
9
|
+
require 'yql/error.rb'
|
10
|
+
require 'yql/client.rb'
|
11
|
+
require 'yql/query_builder.rb'
|
12
|
+
require 'yql/response.rb'
|
data/lib/yql/client.rb
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
module Yql
|
2
|
+
|
3
|
+
class Client
|
4
|
+
|
5
|
+
BASE_URL = 'query.yahooapis.com'
|
6
|
+
VERSION = 'v1'
|
7
|
+
URL_SUFFIX = 'public/yql'
|
8
|
+
YQL_ENV = 'http://datatables.org/alltables.env'
|
9
|
+
|
10
|
+
attr_accessor :query, :diagnostics, :format
|
11
|
+
|
12
|
+
def initialize(args={})
|
13
|
+
@diagnostics = args[:diagnostics] #true or false
|
14
|
+
@version = args[:version]
|
15
|
+
@query = args[:query]
|
16
|
+
@format = args[:format] || 'xml'
|
17
|
+
end
|
18
|
+
|
19
|
+
def query
|
20
|
+
@query.kind_of?(Yql::QueryBuilder) ? @query.to_s : @query
|
21
|
+
end
|
22
|
+
|
23
|
+
def version
|
24
|
+
@version ||= VERSION
|
25
|
+
end
|
26
|
+
|
27
|
+
def full_url
|
28
|
+
"#{version}/#{URL_SUFFIX}"
|
29
|
+
end
|
30
|
+
|
31
|
+
def get
|
32
|
+
if query.nil?
|
33
|
+
raise Yql::IncompleteRequestParameter, "Query not specified"
|
34
|
+
end
|
35
|
+
http = Net::HTTP.new(BASE_URL, Net::HTTP.https_default_port)
|
36
|
+
http.use_ssl = true
|
37
|
+
path = "/#{version}/#{URL_SUFFIX}"
|
38
|
+
Yql::Response.new(http.post(path, parameters), format)
|
39
|
+
end
|
40
|
+
|
41
|
+
def parameters
|
42
|
+
url_parameters = "q=#{CGI.escape(query)}&env=#{YQL_ENV}"
|
43
|
+
url_parameters = add_format(url_parameters)
|
44
|
+
add_diagnostics(url_parameters)
|
45
|
+
end
|
46
|
+
|
47
|
+
def add_format(existing_parameters)
|
48
|
+
return unless existing_parameters
|
49
|
+
return existing_parameters unless format
|
50
|
+
return existing_parameters + "&format=#{format}"
|
51
|
+
end
|
52
|
+
|
53
|
+
def add_diagnostics(existing_parameters)
|
54
|
+
return unless existing_parameters
|
55
|
+
return existing_parameters unless diagnostics
|
56
|
+
return existing_parameters + "&diagnostics=true"
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
data/lib/yql/error.rb
ADDED
@@ -0,0 +1,186 @@
|
|
1
|
+
module Yql
|
2
|
+
|
3
|
+
class QueryBuilder
|
4
|
+
|
5
|
+
attr_accessor :table, :conditions, :limit, :truncate, :sanitize_field, :select,
|
6
|
+
:sort_field, :current_pipe_command_types, :sort_descending,
|
7
|
+
:per_page, :current_page
|
8
|
+
|
9
|
+
def initialize(table, args = {})
|
10
|
+
@select = args[:select]
|
11
|
+
@table = table
|
12
|
+
@use_statement = args[:use]
|
13
|
+
@conditions = args[:conditions]
|
14
|
+
@limit = args[:limit]
|
15
|
+
@tail = args[:tail]
|
16
|
+
@reverse = args[:reverse]
|
17
|
+
@unique = args[:unique]
|
18
|
+
@sanitize = args[:sanitize]
|
19
|
+
@sort_descending = args[:sort_descending]
|
20
|
+
@sanitize_field = args[:sanitize_field]
|
21
|
+
@sort_field = args[:sort_field]
|
22
|
+
@current_pipe_command_types = []
|
23
|
+
@per_page = args[:per_page]
|
24
|
+
end
|
25
|
+
|
26
|
+
def find
|
27
|
+
self.limit = 1
|
28
|
+
"#{construct_query}"
|
29
|
+
end
|
30
|
+
|
31
|
+
def find_all
|
32
|
+
self.limit = nil
|
33
|
+
construct_query
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.show_tables
|
37
|
+
"show tables;"
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.describe_table(table)
|
41
|
+
"desc #{table};"
|
42
|
+
end
|
43
|
+
|
44
|
+
def describe_table
|
45
|
+
Yql::QueryBuilder.describle_table(table)
|
46
|
+
end
|
47
|
+
|
48
|
+
def to_s
|
49
|
+
construct_query
|
50
|
+
end
|
51
|
+
|
52
|
+
def limit
|
53
|
+
return unless @limit
|
54
|
+
"limit #{@limit}"
|
55
|
+
end
|
56
|
+
|
57
|
+
# Conditions can either be provided as hash or plane string
|
58
|
+
def conditions
|
59
|
+
if @conditions.kind_of?(String)
|
60
|
+
cond = @conditions
|
61
|
+
elsif @conditions.kind_of?(Hash)
|
62
|
+
cond = @conditions.collect do |k,v|
|
63
|
+
val = v.kind_of?(String) ? "'#{v}'" : v
|
64
|
+
"#{k.to_s}=#{val}"
|
65
|
+
end
|
66
|
+
cond = cond.join(' and ')
|
67
|
+
else
|
68
|
+
return
|
69
|
+
end
|
70
|
+
return "where #{cond}"
|
71
|
+
end
|
72
|
+
|
73
|
+
%w{sort tail truncate reverse unique sanitize}.each do |method|
|
74
|
+
self.send(:define_method, "#{method}=") do |param|
|
75
|
+
instance_variable_set("@#{method}", param)
|
76
|
+
current_pipe_command_types << method unless current_pipe_command_types.include?(method)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
# Cption can be piped
|
81
|
+
# Sorts the result set according to the specified field (column) in the result set.
|
82
|
+
def sort
|
83
|
+
return unless @sort_field
|
84
|
+
return "sort(field='#{@sort_field}')" unless @sort_descending
|
85
|
+
return "sort(field='#{@sort_field}', descending='true')"
|
86
|
+
end
|
87
|
+
|
88
|
+
# Cption can be piped
|
89
|
+
# Gets the last count items
|
90
|
+
def tail
|
91
|
+
return unless @tail
|
92
|
+
"tail(count=#{@tail})"
|
93
|
+
end
|
94
|
+
|
95
|
+
# Cption can be piped
|
96
|
+
# Gets the first count items (rows)
|
97
|
+
def truncate
|
98
|
+
return unless @truncate
|
99
|
+
"truncate(count=#{@truncate})"
|
100
|
+
end
|
101
|
+
|
102
|
+
# Cption can be piped
|
103
|
+
# Reverses the order of the rows
|
104
|
+
def reverse
|
105
|
+
return unless @reverse
|
106
|
+
"reverse()"
|
107
|
+
end
|
108
|
+
|
109
|
+
# Cption can be piped
|
110
|
+
# Removes items (rows) with duplicate values in the specified field (column)
|
111
|
+
def unique
|
112
|
+
return unless @unique
|
113
|
+
"unique(field='#{@unique}')"
|
114
|
+
end
|
115
|
+
|
116
|
+
# Cption can be piped
|
117
|
+
# Sanitizes the output for HTML-safe rendering. To sanitize all returned fields, omit the field parameter.
|
118
|
+
def sanitize
|
119
|
+
return unless @sanitize
|
120
|
+
return "sanitize()" unless @sanitize_field
|
121
|
+
"sanitize(field='#{@sanitize_field}')"
|
122
|
+
end
|
123
|
+
|
124
|
+
# Its always advisable to order the pipe when there are more than one
|
125
|
+
# pipe commands available else unexpected results might get returned
|
126
|
+
# reorder_pipe_command {:from => 1, :to => 0}
|
127
|
+
# the values in the hash are the element numbers
|
128
|
+
#
|
129
|
+
def reorder_pipe_command(args)
|
130
|
+
return if current_pipe_command_types.empty?
|
131
|
+
if args[:from].nil? or args[:to].nil?
|
132
|
+
raise Yql::Error, "Not able to move pipe commands. Wrong element numbers. Please try again"
|
133
|
+
end
|
134
|
+
args.values.each do |element|
|
135
|
+
if element > current_pipe_command_types.size-1
|
136
|
+
raise Yql::Error, "Not able to move pipe commands. Wrong element numbers. Please try again"
|
137
|
+
end
|
138
|
+
end
|
139
|
+
element_to_be_inserted_at = args[:from] < args[:to] ? args[:to]+1 : args[:to]
|
140
|
+
element_to_be_removed = args[:from] < args[:to] ? args[:from] : args[:from]+1
|
141
|
+
current_pipe_command_types.insert(element_to_be_inserted_at, current_pipe_command_types.at(args[:from]))
|
142
|
+
current_pipe_command_types.delete_at(element_to_be_removed)
|
143
|
+
end
|
144
|
+
|
145
|
+
|
146
|
+
# Remove a command that will be piped to the yql query
|
147
|
+
def remove_pipe_command(command)
|
148
|
+
current_pipe_command_types.delete(command)
|
149
|
+
end
|
150
|
+
|
151
|
+
private
|
152
|
+
|
153
|
+
def pipe_commands
|
154
|
+
return if current_pipe_command_types.empty?
|
155
|
+
'| ' + current_pipe_command_types.map{|c| self.send(c)}.join(' | ')
|
156
|
+
end
|
157
|
+
|
158
|
+
def build_select_query
|
159
|
+
[select_statement, conditions, limit, pipe_commands].compact.join(' ')
|
160
|
+
end
|
161
|
+
|
162
|
+
def construct_query
|
163
|
+
return build_select_query unless @use
|
164
|
+
return [@use, build_select_query].join('; ')
|
165
|
+
end
|
166
|
+
|
167
|
+
def select_statement
|
168
|
+
select = "select #{column_select} from #{table}"
|
169
|
+
return select unless per_page
|
170
|
+
with_pagination(select)
|
171
|
+
end
|
172
|
+
|
173
|
+
def with_pagination(select)
|
174
|
+
self.current_page ||= 1
|
175
|
+
offset = (current_page - 1) * per_page
|
176
|
+
last_record = current_page * per_page
|
177
|
+
"#{select}(#{offset},#{last_record})"
|
178
|
+
end
|
179
|
+
|
180
|
+
def column_select
|
181
|
+
@select ? @select : '*'
|
182
|
+
end
|
183
|
+
|
184
|
+
end
|
185
|
+
|
186
|
+
end
|
metadata
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: yql
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
version: 0.0.1
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Nasir Jamal
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2010-06-20 00:00:00 +01:00
|
18
|
+
default_executable:
|
19
|
+
dependencies: []
|
20
|
+
|
21
|
+
description: Yql is a ruby wrapper for Yahoo Query Language.
|
22
|
+
email: nas35_in@yahoo.com
|
23
|
+
executables: []
|
24
|
+
|
25
|
+
extensions: []
|
26
|
+
|
27
|
+
extra_rdoc_files:
|
28
|
+
- README.rdoc
|
29
|
+
files:
|
30
|
+
- History.txt
|
31
|
+
- Manifest.txt
|
32
|
+
- README.rdoc
|
33
|
+
- lib/yql.rb
|
34
|
+
- lib/yql/client.rb
|
35
|
+
- lib/yql/error.rb
|
36
|
+
- lib/yql/query_builder.rb
|
37
|
+
has_rdoc: true
|
38
|
+
homepage: http://github.com/nas/yql
|
39
|
+
licenses: []
|
40
|
+
|
41
|
+
post_install_message:
|
42
|
+
rdoc_options:
|
43
|
+
- --charset=UTF-8
|
44
|
+
require_paths:
|
45
|
+
- lib
|
46
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
47
|
+
requirements:
|
48
|
+
- - ">="
|
49
|
+
- !ruby/object:Gem::Version
|
50
|
+
segments:
|
51
|
+
- 1
|
52
|
+
- 8
|
53
|
+
version: "1.8"
|
54
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
55
|
+
requirements:
|
56
|
+
- - ">="
|
57
|
+
- !ruby/object:Gem::Version
|
58
|
+
segments:
|
59
|
+
- 0
|
60
|
+
version: "0"
|
61
|
+
requirements: []
|
62
|
+
|
63
|
+
rubyforge_project:
|
64
|
+
rubygems_version: 1.3.6
|
65
|
+
signing_key:
|
66
|
+
specification_version: 3
|
67
|
+
summary: Yql is a ruby wrapper for Yahoo Query Language.
|
68
|
+
test_files: []
|
69
|
+
|