steem_api 1.1.5 → 1.1.6

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 60041edca796504270f02e4317f7931f96881bf31e46669f3e28b183392caf97
4
- data.tar.gz: 50eb29b87407ed3da0d9e3ec8f31ca4eb665e98d8d1842eee4ef11723b8b6aaa
3
+ metadata.gz: ce1065f519a5f966513079a25f8eccb3c032fcd9d93c113e8d1653f14b036251
4
+ data.tar.gz: 2d36809af781240caa13df1ff49233ba0017f479b156d9f0c82a4b7b9f64dca3
5
5
  SHA512:
6
- metadata.gz: 1492198c88ef64ea3e9f105339729be53e073a41c8b5c8b9d0fd9e4330570120d929795df529aff746ee316f9347d08411a7ee141222f4b433a74d480c7569ce
7
- data.tar.gz: a9931f0dc925f795b71136d2585fb33447662d7756f1468e6935a3e1a25d146fe49fb99462d56eb89ef5e1d4da180c0da8f7b89ec8e4a4b52220eb3784de1d91
6
+ metadata.gz: cd08d84e0f148b96703166f141a790be12efd1e2046a3f91d28cba48e1fba9b3e4b6b8a3e86670cbb0155fc384631cc3198badd998235f75eca9cf3ea4b90b72
7
+ data.tar.gz: 3e9b12eef96d2ec8d4793bf727f8250f946c7d731dae3c895b1ea6238e3c4e638e2c9faf007bff08d4c7e33d1036eab214116647ecf10633771a071e2a641114
@@ -8,9 +8,13 @@ require "steem_api/models/account"
8
8
  require "steem_api/models/block"
9
9
  require "steem_api/models/comment"
10
10
  require "steem_api/models/connection"
11
+ require "steem_api/models/community"
12
+ require "steem_api/models/community_subscriber"
13
+ require "steem_api/models/community_role"
11
14
  require "steem_api/models/dynamic_global_properties"
12
15
  require "steem_api/models/follower"
13
16
  require "steem_api/models/reblog"
17
+ require "steem_api/models/tag"
14
18
  require "steem_api/models/token"
15
19
  require "steem_api/models/transaction"
16
20
  require "steem_api/models/witness"
@@ -12,6 +12,23 @@ module SteemApi
12
12
 
13
13
  belongs_to :witness, foreign_key: :name, primary_key: :name
14
14
 
15
+ has_many :roles, foreign_key: :account, class_name: 'SteemApi::CommunityRole', primary_key: :name
16
+ has_many :guest_roles, -> { guests }, foreign_key: :account, class_name: 'SteemApi::CommunityRole', primary_key: :name
17
+ has_many :member_roles, -> { members }, foreign_key: :account, class_name: 'SteemApi::CommunityRole', primary_key: :name
18
+ has_many :mod_roles, -> { mods }, foreign_key: :account, class_name: 'SteemApi::CommunityRole', primary_key: :name
19
+ has_many :admin_roles, -> { admins }, foreign_key: :account, class_name: 'SteemApi::CommunityRole', primary_key: :name
20
+ has_many :muted_roles, -> { muted }, foreign_key: :account, class_name: 'SteemApi::CommunityRole', primary_key: :name
21
+
22
+ has_many :communities, through: :roles, source: :community_record
23
+ has_many :guest_communities, through: :guest_roles, source: :community_record
24
+ has_many :member_communities, through: :member_roles, source: :community_record
25
+ has_many :mod_communities, through: :mod_roles, source: :community_record
26
+ has_many :admin_communities, through: :admin_roles, source: :community_record
27
+ has_many :muted_communities, through: :muted_roles, source: :community_record
28
+
29
+ has_many :subscriptions, foreign_key: :subscriber, class_name: 'SteemApi::CommunitySubscriber', primary_key: :name
30
+ has_many :subscribed_communities, through: :subscriptions, source: :community_record
31
+
15
32
  scope :before, lambda { |before, field = 'created'| where("#{field} < ?", before) }
16
33
  scope :after, lambda { |after, field = 'created'| where("#{field} > ?", after) }
17
34
  scope :today, -> { after(1.day.ago) }
@@ -19,6 +36,10 @@ module SteemApi
19
36
 
20
37
  scope :mined, lambda { |mined = true| where(mined: mined) }
21
38
 
39
+ def all_communities
40
+ SteemApi::Community.where('name IN(?) OR name IN(?)', roles.select(:community), subscriptions.select(:community))
41
+ end
42
+
22
43
  def witness?
23
44
  !!witness
24
45
  end
@@ -3,6 +3,21 @@ module SteemApi
3
3
 
4
4
  self.table_name = :Comments
5
5
 
6
+ has_many :tags, foreign_key: 'comment_ID'
7
+
8
+ belongs_to :author_record, foreign_key: :author, class_name: 'SteemApi::Account', primary_key: :name
9
+ belongs_to :community_record, foreign_key: :category, class_name: 'SteemApi::Community', primary_key: :name
10
+
11
+ scope :depth, lambda { |depth| where(depth: depth) }
12
+
13
+ scope :community, lambda { |community|
14
+ case community
15
+ when String then where(category: community)
16
+ else
17
+ where(category: community.name)
18
+ end
19
+ }
20
+
6
21
  scope :before, lambda { |before, field = 'created'| where("#{field} < ?", before) }
7
22
  scope :after, lambda { |after, field = 'created'| where("#{field} > ?", after) }
8
23
  scope :today, -> { after(1.day.ago) }
@@ -18,8 +33,17 @@ module SteemApi
18
33
  normalized_json.where("JSON_VALUE(json_metadata, '$.app') LIKE ?", "%/#{version}")
19
34
  }
20
35
 
21
- scope :tagged, lambda { |tag|
22
- normalized_json.where("? IN (SELECT value FROM OPENJSON(json_metadata,'$.tags'))", tag)
36
+ scope :community, lambda {|community| joins(:community_record).where(category: community)}
37
+ scope :author, lambda {|author| joins(:author_record).where(author: author)}
38
+
39
+ scope :tagged, lambda { |tag, options = {exclude_category: false}|
40
+ exclude_category = !!options[:exclude_category]
41
+
42
+ if exclude_category
43
+ where(id: SteemSQL::Tag.where(tag: tag).select(:comment_ID))
44
+ else
45
+ where("ID IN(?) OR category = ?", SteemSQL::Tag.where(tag: tag).select(:comment_ID), tag)
46
+ end
23
47
  }
24
48
 
25
49
  scope :decorate_metadata, -> {
@@ -42,18 +66,25 @@ module SteemApi
42
66
  where("JSON_VALUE(beneficiaries, '$.account') IN(?)", [account].flatten)
43
67
  }
44
68
 
45
- def self.find_by_author(user)
46
- self.where(author: user)
69
+ def self.find_by_author(author)
70
+ where(author: author).first
47
71
  end
48
72
 
49
- def self.find_by_parent(user)
50
- self.where(parent_author: user)
73
+ def self.find_by_parent(parent_author)
74
+ where(parent_author: parent_author).first
75
+ end
76
+
77
+ def self.find_by_author_and_permlink(author, permlink)
78
+ where(author: author, permlink: permlink).first
51
79
  end
52
80
 
53
81
  def beneficiaries
54
82
  JSON[self[:beneficiaries]]
55
83
  end
56
84
 
85
+ def tag_names
86
+ tags.pluck(:tag)
87
+ end
57
88
  end
58
89
  end
59
90
 
@@ -0,0 +1,78 @@
1
+ module SteemApi
2
+ class Community < SteemApi::SqlBase
3
+
4
+ self.table_name = :Communities
5
+
6
+ has_many :roles, foreign_key: :community, class_name: 'SteemApi::CommunityRole', primary_key: :name
7
+ has_many :guest_roles, -> { guests }, foreign_key: :community, class_name: 'SteemApi::CommunityRole', primary_key: :name
8
+ has_many :member_roles, -> { members }, foreign_key: :community, class_name: 'SteemApi::CommunityRole', primary_key: :name
9
+ has_many :mod_roles, -> { mods }, foreign_key: :community, class_name: 'SteemApi::CommunityRole', primary_key: :name
10
+ has_many :admin_roles, -> { admins }, foreign_key: :community, class_name: 'SteemApi::CommunityRole', primary_key: :name
11
+ has_many :muted_roles, -> { muted }, foreign_key: :community, class_name: 'SteemApi::CommunityRole', primary_key: :name
12
+
13
+ has_many :role_accounts, through: :roles, source: :account_record
14
+ has_many :guests, through: :guest_roles, source: :account_record
15
+ has_many :members, through: :member_roles, source: :account_record
16
+ has_many :mods, through: :mod_roles, source: :account_record
17
+ has_many :admins, through: :admin_roles, source: :account_record
18
+ has_many :muted, through: :muted_roles, source: :account_record
19
+
20
+ has_many :subscribers, foreign_key: :community, class_name: 'SteemApi::CommunitySubscriber', primary_key: :name
21
+ has_many :subscriber_accounts, through: :subscribers, source: :account_record
22
+
23
+ has_many :comments, foreign_key: :category, class_name: 'SteemApi::Comment', primary_key: :name
24
+ has_many :authors, -> { distinct }, through: :comments, source: :author_record
25
+ has_many :tags, -> { distinct }, through: :comments, source: :tags
26
+
27
+ scope :mode, lambda { |type| where(type: type) }
28
+ scope :topics, -> { mode 1 }
29
+ scope :journals, -> { mode 2 }
30
+ scope :councils, -> { mode 3 }
31
+
32
+ scope :language, lambda { |language| where(language: language) }
33
+ scope :nsfw, lambda { |nsfw = true| where(nsfw: nsfw) }
34
+
35
+ scope :tagged, lambda { |tag|
36
+ comments = SteemSQL::Comment.where("category LIKE 'hive-%'")
37
+ comments = comments.joins(:community_record)
38
+ comments = comments.tagged(tag, exclude_category: true)
39
+
40
+ where(name: comments.select(:category))
41
+ }
42
+
43
+ scope :query, lambda { |query, options = {include_roles: false}|
44
+ query_clause = []
45
+
46
+ query_clause << "LOWER([Communities].[name]) LIKE ?"
47
+ query_clause << "LOWER([Communities].[title]) LIKE ?"
48
+ query_clause << "LOWER([Communities].[about]) LIKE ?"
49
+ query_clause << "LOWER([Communities].[description]) LIKE ?"
50
+
51
+ if !!options.fetch(:include_roles, false)
52
+ query_clause << "[Communities].[name] IN ( SELECT [CommunitiesRoles].[community] FROM [CommunitiesRoles] WHERE [CommunitiesRoles].[account] LIKE ?)"
53
+ query_clause << "[Communities].[name] IN ( SELECT [CommunitiesRoles].[community] FROM [CommunitiesRoles] WHERE LOWER([CommunitiesRoles].[title]) LIKE ?)"
54
+ end
55
+
56
+ query = ["%#{query.downcase}%"] * query_clause.size
57
+ where(query_clause.join(' OR '), *query)
58
+ }
59
+
60
+ def tag_names
61
+ tags.pluck(:tag)
62
+ end
63
+ end
64
+ end
65
+
66
+ # Structure
67
+ #
68
+ # SteemApi::Community(
69
+ # name varchar,
70
+ # type varchar,
71
+ # title varchar,
72
+ # about varchar,
73
+ # description varchar,
74
+ # flag_text varchar,
75
+ # language varchar,
76
+ # nsfw boolean,
77
+ # TS timestamp,
78
+ # )
@@ -0,0 +1,37 @@
1
+ module SteemApi
2
+ class CommunityRole < SteemApi::SqlBase
3
+
4
+ self.table_name = :CommunitiesRoles
5
+
6
+ belongs_to :community_record, foreign_key: :community, class_name: 'SteemApi::Community', primary_key: :name
7
+ belongs_to :account_record, foreign_key: :account, class_name: 'SteemApi::Account', primary_key: :name
8
+
9
+ scope :account, lambda { |account| where(account: account) }
10
+
11
+ scope :mode, lambda { |mode| where(role: mode) }
12
+ scope :guests, -> { mode 'guest' }
13
+ scope :members, -> { mode 'member' }
14
+ scope :mods, -> { mode 'mod' }
15
+ scope :admins, -> { mode 'admin' }
16
+ scope :muted, -> { mode 'muted' }
17
+
18
+ scope :community, lambda {|community| where(community: community)}
19
+ scope :account, lambda {|account| where(account: account)}
20
+
21
+ scope :query, lambda { |query, options = {include_roles: false}|
22
+ where("community IN(?) OR account LIKE ? OR LOWER(title) LIKE ?",
23
+ Community.query(query, options).select(:name),
24
+ "%#{query}%",
25
+ "%#{query.downcase}%")
26
+ }
27
+ end
28
+ end
29
+
30
+ # Structure
31
+ #
32
+ # SteemApi::CommunityRole(
33
+ # community varchar,
34
+ # account varchar,
35
+ # role varchar,
36
+ # title varchar
37
+ # )
@@ -0,0 +1,23 @@
1
+ module SteemApi
2
+ class CommunitySubscriber < SteemApi::SqlBase
3
+
4
+ self.table_name = :CommunitiesSubscribers
5
+
6
+ belongs_to :community_record, foreign_key: :community, class_name: 'SteemApi::Community', primary_key: :name
7
+ belongs_to :account_record, foreign_key: :subscriber, class_name: 'SteemApi::Account', primary_key: :name
8
+
9
+ scope :community, lambda {|community| where(community: community)}
10
+ scope :subscriber, lambda {|subscriber| where(subscriber: subscriber)}
11
+
12
+ scope :query, lambda { |query, options = {include_roles: false}|
13
+ where(community: Community.query(query, options).select(:name))
14
+ }
15
+ end
16
+ end
17
+
18
+ # Structure
19
+ #
20
+ # SteemApi::CommunitySubscriber(
21
+ # community varchar,
22
+ # subscriber varchar
23
+ # )
@@ -0,0 +1,15 @@
1
+ module SteemApi
2
+ class Tag < SteemApi::SqlBase
3
+
4
+ self.table_name = :Tags
5
+
6
+ belongs_to :comment, foreign_key: 'comment_ID', class_name: 'SteemApi::Comment'
7
+ end
8
+ end
9
+
10
+ # Structure
11
+ #
12
+ # SteemApi::Tag(
13
+ # comment_ID integer,
14
+ # tag varchar
15
+ # )
@@ -3,7 +3,13 @@ module SteemApi
3
3
  class Custom < SteemApi::SqlBase
4
4
 
5
5
  self.table_name = :TxCustoms
6
-
6
+
7
+ scope :any_required_auths, lambda { |required_auth|
8
+ where("? IN(JSON_VALUE(required_auths, '$'))", required_auth)
9
+ }
10
+ scope :any_required_posting_auths, lambda { |required_posting_auth|
11
+ where("? IN(JSON_VALUE(required_posting_auths, '$'))", required_posting_auth)
12
+ }
7
13
  end
8
14
  end
9
15
  end
@@ -3,25 +3,25 @@ module SteemApi
3
3
  class Custom::Community < SteemApi::Tx::Custom
4
4
  default_scope { where(tid: :community) }
5
5
 
6
- scope :normalized_json, -> { where("ISJSON(json_metadata) > 0") }
7
- scope :op, lambda { |op| normalized_json.where("JSON_VALUE(json_metadata, '$[0]') = ?", op) }
8
- scope :community, lambda { |community| normalized_json.where("JSON_VALUE(json_metadata, '$[1].community') = ?", community) }
9
- scope :role, lambda { |role| normalized_json.where("JSON_VALUE(json_metadata, '$[1].role') = ?", role) }
10
- scope :language, lambda { |language| normalized_json.where("JSON_VALUE(json_metadata, '$[1].language') = ?", language) }
11
- scope :nsfw, lambda { |nsfw = true| normalized_json.where("JSON_VALUE(json_metadata, '$[1].is_nsfw') = ?", nsfw) }
6
+ scope :normalized_json, -> { where("ISJSON([TxCustoms].[json_metadata]) > 0") }
7
+ scope :op, lambda { |op| normalized_json.where("JSON_VALUE([TxCustoms].[json_metadata], '$[0]') = ?", op) }
8
+ scope :community, lambda { |community| normalized_json.where("JSON_VALUE([TxCustoms].[json_metadata], '$[1].community') = ?", community) }
9
+ scope :role, lambda { |role| normalized_json.where("JSON_VALUE([TxCustoms].[json_metadata], '$[1].role') = ?", role) }
10
+ scope :language, lambda { |language| normalized_json.where("JSON_VALUE([TxCustoms].[json_metadata], '$[1].language') = ?", language) }
11
+ scope :nsfw, lambda { |nsfw = true| normalized_json.where("JSON_VALUE([TxCustoms].[json_metadata], '$[1].is_nsfw') = ?", nsfw) }
12
12
  scope :account, lambda { |account|
13
13
  account = [account].flatten
14
- normalized_json.where("required_auth IN(?) OR required_posting_auth IN(?) OR JSON_VALUE(json_metadata, '$[1].account') IN(?)", account, account, account)
14
+ normalized_json.where("required_auth IN(?) OR required_posting_auth IN(?) OR JSON_VALUE([TxCustoms].[json_metadata], '$[1].account') IN(?)", account, account, account)
15
15
  }
16
16
  scope :permlink, lambda { |permlink|
17
- normalized_json.where("JSON_VALUE(json_metadata, '$[1].permlink') = ?", permlink)
17
+ normalized_json.where("JSON_VALUE([TxCustoms].[json_metadata], '$[1].permlink') = ?", permlink)
18
18
  }
19
19
  scope :slug, lambda { |slug|
20
- normalized_json.where("JSON_VALUE(json_metadata, '$[1].account') = ? AND JSON_VALUE(json_metadata, '$[1].permlink') = ?", *slug.split('/'))
20
+ normalized_json.where("JSON_VALUE([TxCustoms].[json_metadata], '$[1].account') = ? AND JSON_VALUE([TxCustoms].[json_metadata], '$[1].permlink') = ?", *slug.split('/'))
21
21
  }
22
22
 
23
23
  def self.ops
24
- distinct.normalized_json.pluck(Arel.sql "JSON_VALUE(json_metadata, '$[0]') AS ops")
24
+ distinct.normalized_json.pluck(Arel.sql "JSON_VALUE([TxCustoms].[json_metadata], '$[0]') AS ops")
25
25
  end
26
26
 
27
27
  def payload
@@ -1,3 +1,3 @@
1
1
  module SteemApi
2
- VERSION = '1.1.5'
2
+ VERSION = '1.1.6'
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: steem_api
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.5
4
+ version: 1.1.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Chaney (netuoso)
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2019-12-07 00:00:00.000000000 Z
12
+ date: 2020-02-27 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
@@ -35,42 +35,42 @@ dependencies:
35
35
  name: rake
36
36
  requirement: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - "~>"
39
- - !ruby/object:Gem::Version
40
- version: '12.1'
41
38
  - - ">="
42
39
  - !ruby/object:Gem::Version
43
40
  version: 12.1.0
41
+ - - "~>"
42
+ - !ruby/object:Gem::Version
43
+ version: '12.1'
44
44
  type: :development
45
45
  prerelease: false
46
46
  version_requirements: !ruby/object:Gem::Requirement
47
47
  requirements:
48
- - - "~>"
49
- - !ruby/object:Gem::Version
50
- version: '12.1'
51
48
  - - ">="
52
49
  - !ruby/object:Gem::Version
53
50
  version: 12.1.0
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '12.1'
54
54
  - !ruby/object:Gem::Dependency
55
55
  name: minitest-proveit
56
56
  requirement: !ruby/object:Gem::Requirement
57
57
  requirements:
58
- - - "~>"
59
- - !ruby/object:Gem::Version
60
- version: '1.0'
61
58
  - - ">="
62
59
  - !ruby/object:Gem::Version
63
60
  version: 1.0.0
61
+ - - "~>"
62
+ - !ruby/object:Gem::Version
63
+ version: '1.0'
64
64
  type: :development
65
65
  prerelease: false
66
66
  version_requirements: !ruby/object:Gem::Requirement
67
67
  requirements:
68
- - - "~>"
69
- - !ruby/object:Gem::Version
70
- version: '1.0'
71
68
  - - ">="
72
69
  - !ruby/object:Gem::Version
73
70
  version: 1.0.0
71
+ - - "~>"
72
+ - !ruby/object:Gem::Version
73
+ version: '1.0'
74
74
  - !ruby/object:Gem::Dependency
75
75
  name: minitest
76
76
  requirement: !ruby/object:Gem::Requirement
@@ -175,22 +175,22 @@ dependencies:
175
175
  name: irb
176
176
  requirement: !ruby/object:Gem::Requirement
177
177
  requirements:
178
- - - "~>"
179
- - !ruby/object:Gem::Version
180
- version: '1.0'
181
178
  - - ">="
182
179
  - !ruby/object:Gem::Version
183
180
  version: 1.0.0
181
+ - - "~>"
182
+ - !ruby/object:Gem::Version
183
+ version: '1.0'
184
184
  type: :development
185
185
  prerelease: false
186
186
  version_requirements: !ruby/object:Gem::Requirement
187
187
  requirements:
188
- - - "~>"
189
- - !ruby/object:Gem::Version
190
- version: '1.0'
191
188
  - - ">="
192
189
  - !ruby/object:Gem::Version
193
190
  version: 1.0.0
191
+ - - "~>"
192
+ - !ruby/object:Gem::Version
193
+ version: '1.0'
194
194
  - !ruby/object:Gem::Dependency
195
195
  name: nokogiri
196
196
  requirement: !ruby/object:Gem::Requirement
@@ -297,22 +297,22 @@ dependencies:
297
297
  name: awesome_print
298
298
  requirement: !ruby/object:Gem::Requirement
299
299
  requirements:
300
- - - "~>"
301
- - !ruby/object:Gem::Version
302
- version: '1.7'
303
300
  - - ">="
304
301
  - !ruby/object:Gem::Version
305
302
  version: 1.7.0
303
+ - - "~>"
304
+ - !ruby/object:Gem::Version
305
+ version: '1.7'
306
306
  type: :runtime
307
307
  prerelease: false
308
308
  version_requirements: !ruby/object:Gem::Requirement
309
309
  requirements:
310
- - - "~>"
311
- - !ruby/object:Gem::Version
312
- version: '1.7'
313
310
  - - ">="
314
311
  - !ruby/object:Gem::Version
315
312
  version: 1.7.0
313
+ - - "~>"
314
+ - !ruby/object:Gem::Version
315
+ version: '1.7'
316
316
  description: Rails compatible gem that provides full DB connection and models to SteemSQL.com
317
317
  email:
318
318
  - andrewc@pobox.com
@@ -333,11 +333,15 @@ files:
333
333
  - lib/steem_api/models/account.rb
334
334
  - lib/steem_api/models/block.rb
335
335
  - lib/steem_api/models/comment.rb
336
+ - lib/steem_api/models/community.rb
337
+ - lib/steem_api/models/community_role.rb
338
+ - lib/steem_api/models/community_subscriber.rb
336
339
  - lib/steem_api/models/connection.rb
337
340
  - lib/steem_api/models/dynamic_global_properties.rb
338
341
  - lib/steem_api/models/follower.rb
339
342
  - lib/steem_api/models/reblog.rb
340
343
  - lib/steem_api/models/sql_base.rb
344
+ - lib/steem_api/models/tag.rb
341
345
  - lib/steem_api/models/token.rb
342
346
  - lib/steem_api/models/transaction.rb
343
347
  - lib/steem_api/models/tx/account_create.rb
@@ -407,7 +411,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
407
411
  version: '0'
408
412
  requirements: []
409
413
  rubyforge_project:
410
- rubygems_version: 2.7.7
414
+ rubygems_version: 2.7.10
411
415
  signing_key:
412
416
  specification_version: 4
413
417
  summary: Ruby/Rails wrapper for SteemSQL.com