parse-stack 1.6.1 → 1.6.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e6f2fcd731c3e5c535c2fcd5b6ad7de0411ee3b8
4
- data.tar.gz: d43b5c15e4ca7ff3528d53c09d9f333ea5cca2cd
3
+ metadata.gz: 8fe3974386a315a6858707bdfe4c70ad41d9757e
4
+ data.tar.gz: ae7f69099d57799341027a1f1776529be848740b
5
5
  SHA512:
6
- metadata.gz: 7521b1712daddb91201f06062a327443f65467c4098441b68e06de9a53b862c5e2fe36d5f66abb68d974aae098b5a9218315e9de0ab494b47032ad02a81c0a94
7
- data.tar.gz: 75e194bbed8d4aebbb8c1ab2fd08f1d4b6c1b1c58191df19bcaf356bfceac761c40874321049e2a83b622b02b68cdf1b167652cac9f796c3f2a1a59aca062297
6
+ metadata.gz: 943d2a2607014404c125680ad77b75b95edb46fa310bb4185e7945eb090003a09abb1c3165e2b229ba0691293386d25249b34ba0d2ebe68b80ee47210362c914
7
+ data.tar.gz: 00a8dcfb89c494f21d2763bc7fb6305b65b80e51bfd701e9d73293c9e86902db1faa3a92557b782d6c52b98b6bd5c59522f3c29cc9cb8cd03ba3e577d63c26b4
data/Changes.md CHANGED
@@ -1,5 +1,14 @@
1
1
  ## Parse-Stack Changelog
2
2
 
3
+ ### 1.6.4
4
+ - Fixes #20: All temporary headers values are strings.
5
+ - Reduced cache storage consumption by only storing response body and headers.
6
+ - Increased maximum cache content length size to 1.25 MB.
7
+ - You may pass a redis url to the :cache option of setup.
8
+ - Fixes issue with invalid struct size of Faraday::Env with old caching keys.
9
+ - Added server_info and health check APIs for Parse-Server +2.2.25.
10
+ - Updated test to validate against MT6.
11
+
3
12
  ### 1.6.1
4
13
  - NEW: Batch requests are now parallelized.
5
14
  - `skip` in queries no longer capped to 10,000.
data/Gemfile CHANGED
@@ -3,10 +3,10 @@ source 'https://rubygems.org'
3
3
  # Specify your gem's dependencies in parse-stack.gemspec
4
4
  gemspec
5
5
 
6
- gem 'dotenv'
7
- gem 'rake'
8
-
9
6
  group :test, :development do
7
+ gem 'dotenv'
8
+ gem 'redis'
9
+ gem 'rake'
10
10
  gem 'byebug'
11
11
  gem 'minitest'
12
12
  gem 'pry'
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- parse-stack (1.6.1)
4
+ parse-stack (1.6.4)
5
5
  active_model_serializers (>= 0.9, < 1)
6
6
  activemodel (>= 4.2.1, < 6)
7
7
  activesupport (>= 4.2.1, < 6)
@@ -59,12 +59,12 @@ GEM
59
59
  nokogiri (>= 1.5.9)
60
60
  method_source (0.8.2)
61
61
  mini_portile2 (2.1.0)
62
- minitest (5.9.1)
63
- moneta (0.8.0)
62
+ minitest (5.10.1)
63
+ moneta (0.8.1)
64
64
  multipart-post (2.0.0)
65
65
  nokogiri (1.6.8.1)
66
66
  mini_portile2 (~> 2.1.0)
67
- parallel (1.9.0)
67
+ parallel (1.10.0)
68
68
  pry (0.10.4)
69
69
  coderay (~> 1.1.0)
70
70
  method_source (~> 0.8.1)
@@ -82,7 +82,8 @@ GEM
82
82
  nokogiri (~> 1.6.0)
83
83
  rails-html-sanitizer (1.0.3)
84
84
  loofah (~> 2.0)
85
- rake (11.3.0)
85
+ rake (12.0.0)
86
+ redis (3.3.2)
86
87
  slop (3.6.0)
87
88
  thread_safe (0.3.5)
88
89
  tzinfo (1.2.2)
@@ -100,6 +101,7 @@ DEPENDENCIES
100
101
  pry-nav
101
102
  pry-stack_explorer
102
103
  rake
104
+ redis
103
105
 
104
106
  BUNDLED WITH
105
- 1.13.3
107
+ 1.13.6
data/README.md CHANGED
@@ -1,6 +1,8 @@
1
1
  <img src='https://raw.githubusercontent.com/modernistik/parse-stack/master/.github/parse-ruby-sdk.png?raw=true' width='500' alt='Ruby Parse SDK'/>
2
2
 
3
- Parse-Stack is the [Parse Server](https://github.com/ParsePlatform/parse-server) SDK and ORM framework for [Ruby](https://www.ruby-lang.org/en/). It provides a client adapter, a query engine, an object relational mapper (ORM) and a Cloud Code Webhooks rack application.
3
+ # Parse-Stack - The Parse Ruby Client SDK
4
+
5
+ Parse-Stack is the [Parse Server](https://github.com/ParsePlatform/parse-server) SDK, REST Client and ORM framework for [Ruby](https://www.ruby-lang.org/en/). It provides a client adapter, a query engine, an object relational mapper (ORM) and a Cloud Code Webhooks rack application.
4
6
 
5
7
  Below is a [quick start guide](https://github.com/modernistik/parse-stack#overview), but you can also check out the full [API Reference](http://www.rubydoc.info/github/modernistik/parse-stack) for more detailed information about our Parse Server SDK.
6
8
 
@@ -34,11 +36,83 @@ Parse-Stack comes with support for Rails by adding additional rake tasks and gen
34
36
 
35
37
  For a more details on the rails integration see [Parse-Stack Rails Example](https://github.com/modernistik/parse-stack-rails-example).
36
38
 
37
- # Parse-Stack - The Parse Server Ruby SDK
39
+ ## Overview
40
+ Parse-Stack is a full stack framework that utilizes several ideas behind [DataMapper](http://datamapper.org/docs/find.html) and [ActiveModel](https://github.com/rails/rails/tree/master/activemodel) to manage and maintain larger scale ruby applications and tools that utilize the [Parse Server Platform](https://github.com/ParsePlatform/parse-server). If you are familiar with these technologies, the framework should feel familiar to you.
41
+
42
+ ```ruby
43
+
44
+ require 'parse/stack'
45
+
46
+ Parse.setup server_url: 'https://localhost:1337/parse',
47
+ app_id: APP_ID,
48
+ api_key: REST_API_KEY,
49
+ master_key: YOUR_MASTER_KEY # optional
50
+
51
+ # Automatically build models based on your Parse application schemas.
52
+ Parse.auto_generate_models!
53
+
54
+ # or define custom Subclasses (Highly Recommended)
55
+ class Song < Parse::Object
56
+ property :name
57
+ property :play, :integer
58
+ property :audio_file, :file
59
+ property :tags, :array
60
+ property :released, :date
61
+ belongs_to :artist
62
+ # `like` is a Parse Relation to User class
63
+ has_many :likes, as: :user, through: :relation
64
+ end
65
+
66
+ class Artist < Parse::Object
67
+ property :name
68
+ property :genres, :array
69
+ has_many :fans, as: :user
70
+ has_one :manager, as: :user
71
+
72
+ scope :recent, ->(x) { query(:created_at.after => x) }
73
+ end
74
+
75
+ # updates schemas for your Parse app based on your models (non-destructive)
76
+ Parse.auto_upgrade!
77
+
78
+ # login
79
+ user = Parse::User.login(username, passwd)
80
+
81
+ artist = Artist.new(name: "Frank Sinatra", genres: ["swing", "jazz"])
82
+ artist.fans << user
83
+ artist.save
84
+
85
+ # Query
86
+ artist = Artist.first(:name.like => /Sinatra/, :genres.in => ['swing'])
87
+
88
+ # more examples
89
+ song = Song.new name: "Fly Me to the Moon"
90
+ song.artist = artist
91
+ # Parse files - upload a file and attach to object
92
+ song.audio_file = Parse::File.create("http://path_to.mp3")
93
+
94
+ # relations - find a User matching username and add it to relation.
95
+ song.likes.add Parse::User.first(username: "persaud")
96
+
97
+ # saves both attributes and relations
98
+ song.save
99
+
100
+ # find songs
101
+ songs = Song.all(artist: artist, :plays.gt => 100, :released.on_or_after => 30.days.ago)
102
+
103
+ songs.each { |s| s.tags.add "awesome" }
104
+ # batch saves
105
+ songs.save
106
+
107
+ # Call Cloud Code functions
108
+ result = Parse.call_function :myFunctionName, {param: value}
109
+
110
+ ```
111
+ ## Table of Contents
112
+
38
113
  <!-- START doctoc generated TOC please keep comment here to allow auto update -->
39
114
  <!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
40
115
 
41
-
42
116
  - [Overview](#overview)
43
117
  - [Architecture](#architecture)
44
118
  - [Parse::Client](#parseclient)
@@ -113,7 +187,7 @@ For a more details on the rails integration see [Parse-Stack Rails Example](http
113
187
  - [:skip](#skip)
114
188
  - [:cache](#cache)
115
189
  - [:use_master_key](#use_master_key)
116
- - [:session_token](#session_token)
190
+ - [:session](#session)
117
191
  - [:where](#where)
118
192
  - [Query Constraints](#query-constraints)
119
193
  - [Equals](#equals)
@@ -155,79 +229,6 @@ For a more details on the rails integration see [Parse-Stack Rails Example](http
155
229
 
156
230
  <!-- END doctoc generated TOC please keep comment here to allow auto update -->
157
231
 
158
- ## Overview
159
- Parse-Stack is a full stack framework that utilizes several ideas behind [DataMapper](http://datamapper.org/docs/find.html) and [ActiveModel](https://github.com/rails/rails/tree/master/activemodel) to manage and maintain larger scale ruby applications and tools that utilize the [Parse Server Platform](https://github.com/ParsePlatform/parse-server). If you are familiar with these technologies, the framework should feel familiar to you.
160
-
161
- ```ruby
162
-
163
- require 'parse/stack'
164
-
165
- Parse.setup server_url: 'https://localhost:1337/parse',
166
- app_id: APP_ID,
167
- api_key: REST_API_KEY,
168
- master_key: YOUR_MASTER_KEY # optional
169
-
170
- # Automatically build models based on your Parse application schemas.
171
- Parse.auto_generate_models!
172
-
173
- # or define custom Subclasses (Highly Recommended)
174
- class Song < Parse::Object
175
- property :name
176
- property :play, :integer
177
- property :audio_file, :file
178
- property :tags, :array
179
- property :released, :date
180
- belongs_to :artist
181
- # `like` is a Parse Relation to User class
182
- has_many :likes, as: :user, through: :relation
183
- end
184
-
185
- class Artist < Parse::Object
186
- property :name
187
- property :genres, :array
188
- has_many :fans, as: :user
189
- has_one :manager, as: :user
190
-
191
- scope :recent, ->(x) { query(:created_at.after => x) }
192
- end
193
-
194
- # updates schemas for your Parse app based on your models (non-destructive)
195
- Parse.auto_upgrade!
196
-
197
- # login
198
- user = Parse::User.login(username, passwd)
199
-
200
- artist = Artist.new(name: "Frank Sinatra", genres: ["swing", "jazz"])
201
- artist.fans << user
202
- artist.save
203
-
204
- # Query
205
- artist = Artist.first(:name.like => /Sinatra/, :genres.in => ['swing'])
206
-
207
- # more examples
208
- song = Song.new name: "Fly Me to the Moon"
209
- song.artist = artist
210
- # Parse files - upload a file and attach to object
211
- song.audio_file = Parse::File.create("http://path_to.mp3")
212
-
213
- # relations - find a User matching username and add it to relation.
214
- song.likes.add Parse::User.first(username: "persaud")
215
-
216
- # saves both attributes and relations
217
- song.save
218
-
219
- # find songs
220
- songs = Song.all(artist: artist, :plays.gt => 100, :released.on_or_after => 30.days.ago)
221
-
222
- songs.each { |s| s.tags.add "awesome" }
223
- # batch saves
224
- songs.save
225
-
226
- # Call Cloud Code functions
227
- result = Parse.call_function :myFunctionName, {param: value}
228
-
229
- ```
230
-
231
232
  ## Architecture
232
233
  The architecture of `Parse::Stack` is broken into four main components.
233
234
 
@@ -316,6 +317,18 @@ The connection adapter. By default it uses the `Faraday.default_adapter` which i
316
317
  #### `:cache`
317
318
  A caching adapter of type `Moneta::Transformer`. Caching queries and object fetches can help improve the performance of your application, even if it is for a few seconds. Only successful `GET` object fetches and queries (non-empty) will be cached. You may set the default expiration time with the `expires` option. See related: [Moneta](https://github.com/minad/moneta). At any point in time you may clear the cache by calling the `clear_cache!` method on the client connection.
318
319
 
320
+ ```ruby
321
+ store = Moneta.new :Redis, url: 'redis://localhost:6379'
322
+ # use a Redis cache store with an automatic expire of 10 seconds.
323
+ Parse.setup(cache: store, expires: 10, ...)
324
+ ```
325
+
326
+ As a shortcut, if you are planning on using REDIS and have configured the use of `redis` in your `Gemfile`, you can just pass the redis connection string directly to the cache option.
327
+
328
+ ```ruby
329
+ Parse.setup(cache: 'redis://localhost:6379', ...)
330
+ ```
331
+
319
332
  #### `:expires`
320
333
  Sets the default cache expiration time (in seconds) for successful non-empty `GET` requests when using the caching middleware. The default value is 3 seconds. If `:expires` is set to 0, caching will be disabled. You can always clear the current state of the cache using the `clear_cache!` method on your `Parse::Client` instance.
321
334
 
@@ -1652,13 +1665,15 @@ A true/false value. If you provided a master key as part of `Parse.setup()`, it
1652
1665
  Song.all limit: 3, use_master_key: false
1653
1666
  ```
1654
1667
 
1655
- #### :session_token
1656
- A Parse session token string. If you would like to perform a query as a particular user, you may pass their session token in the query. This will make sure that the query is performed on behalf (and with the privileges) of that user which will cause record ACLs to be enforced. If a session token is provided, caching will be disabled for this request.
1668
+ #### :session
1669
+ This will make sure that the query is performed on behalf (and with the privileges) of an authenticated user which will cause record ACLs to be enforced. If a session token is provided, caching will be disabled for this request. You may pass a string representing the session token, an authenticated `Parse::User` instance or a `Parse::Session` instance.
1657
1670
 
1658
1671
  ```ruby
1659
1672
  # disable sending the master key in the request if configured
1660
1673
  # and perform this request as a Parse user represented by this token
1661
- Song.all limit: 3, session_token: "<session_token>"
1674
+ Song.all limit: 3, session: "<session_token>"
1675
+ Song.all limit: 3, session: user # a logged-in Parse::User
1676
+ Song.all limit: 3, session: session # Parse::Session
1662
1677
  ```
1663
1678
 
1664
1679
  #### :where
data/bin/console CHANGED
@@ -6,7 +6,7 @@ require 'dotenv'
6
6
  require 'byebug'
7
7
  Dotenv.load
8
8
 
9
- Parse.setup
9
+ Parse.setup # cache: 'redis://localhost:6379'
10
10
 
11
11
  puts "[ParseServerURL] #{Parse.client.server_url}"
12
12
  puts "[ParseAppID] #{Parse.client.app_id}"
@@ -13,7 +13,7 @@ module Parse
13
13
 
14
14
  # @!visibility private
15
15
  SERVER_INFO_PATH = 'serverInfo'
16
-
16
+ SERVER_HEALTH_PATH = 'health'
17
17
  # Fetch and cache information about the Parse server configuration. This
18
18
  # hash contains information specifically to the configuration of the running
19
19
  # parse server.
@@ -25,6 +25,13 @@ module Parse
25
25
  response.result.with_indifferent_access
26
26
  end
27
27
 
28
+ # Fetches the status of the server based on the health check.
29
+ # @return [Boolean] whether the server is 'OK'.
30
+ def server_health
31
+ response = request :get, SERVER_HEALTH_PATH
32
+ response.success?
33
+ end
34
+
28
35
  # Force fetches the server information.
29
36
  # @return [Hash] a hash containing server configuration if available.
30
37
  def server_info!
data/lib/parse/client.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  require 'faraday'
2
2
  require 'faraday_middleware'
3
3
  require 'active_support'
4
+ require 'moneta'
4
5
  require 'active_model_serializers'
5
6
  require 'active_support/inflector'
6
7
  require 'active_support/core_ext/object'
@@ -267,6 +268,16 @@ module Parse
267
268
  end
268
269
 
269
270
  if opts[:cache].present? && opts[:expires].to_i > 0
271
+ # advanced: provide a REDIS url, we'll configure a Moneta Redis store.
272
+ if opts[:cache].is_a?(String) && opts[:cache].starts_with?("redis://")
273
+ begin
274
+ opts[:cache] = Moneta.new(:Redis, url: opts[:cache])
275
+ rescue LoadError
276
+ puts "[Parse::Middleware::Caching] Did you forget to load the redis gem (Gemfile)?"
277
+ raise
278
+ end
279
+ end
280
+
270
281
  unless opts[:cache].is_a?(Moneta::Transformer)
271
282
  raise ArgumentError, "Parse::Client option :cache needs to be a type of Moneta::Transformer store."
272
283
  end
@@ -379,7 +390,7 @@ module Parse
379
390
  headers[Parse::Middleware::Caching::CACHE_CONTROL] = "no-cache"
380
391
  elsif opts[:cache].is_a?(Numeric)
381
392
  # specify the cache duration of this request
382
- headers[Parse::Middleware::Caching::CACHE_EXPIRES_DURATION] = opts[:cache].to_i
393
+ headers[Parse::Middleware::Caching::CACHE_EXPIRES_DURATION] = opts[:cache].to_s
383
394
  end
384
395
 
385
396
  if opts[:use_master_key] == false
@@ -130,12 +130,29 @@ module Parse
130
130
 
131
131
  begin
132
132
  if method == :get && @cache_key.present? && @store.key?(@cache_key)
133
- puts("[Parse::Cache::Hit] >> #{url}") if self.class.logging.present?
133
+ puts("[Parse::Cache] Hit >> #{url}") if self.class.logging.present?
134
134
  response = Faraday::Response.new
135
- res_env = @store[@cache_key] # previous cached response
136
- body = res_env.respond_to?(:body) ? res_env.body : nil
137
- if body.present?
138
- response.finish({status: 200, response_headers: { CACHE_RESPONSE_HEADER => true }, body: body })
135
+ begin
136
+ cache_data = @store[@cache_key] # previous cached response
137
+ rescue => e
138
+ puts "[Parse::Cache] Error: #{e}"
139
+ cache_data = nil
140
+ end
141
+
142
+ # check if the store was from a legacy parse-stack cache value which
143
+ # is stored as Faraday::Env. T\he new system stores less content in a simple hash
144
+ # for improved interoperability and access time.
145
+ if cache_data.is_a?(Faraday::Env)
146
+ body = cache_data.respond_to?(:body) ? cache_data.body : nil
147
+ response_headers = cache_data.response_headers || {}
148
+ elsif cache_data.is_a?(Hash)
149
+ body = cache_data[:body]
150
+ response_headers = cache_data[:headers] || {}
151
+ end
152
+
153
+ if cache_data.present? && body.present?
154
+ response_headers[CACHE_RESPONSE_HEADER] = 'true'
155
+ response.finish({status: 200, response_headers: response_headers, body: body })
139
156
  return response
140
157
  else
141
158
  @store.delete @cache_key
@@ -148,7 +165,7 @@ module Parse
148
165
  @store.delete "mk:#{url.to_s}" # master key cache-key
149
166
  @store.delete @cache_key # final key
150
167
  end
151
- rescue Errno::EINVAL, Redis::CannotConnectError, Redis::TimeoutError => e
168
+ rescue ::TypeError, Errno::EINVAL, Redis::CannotConnectError, Redis::TimeoutError => e
152
169
  # if the cache store fails to connect, catch the exception but proceed
153
170
  # with the regular request, but turn off caching for this request. It is possible
154
171
  # that the cache connection resumes at a later point, so this is temporary.
@@ -161,9 +178,11 @@ module Parse
161
178
  # is between 20 bytes and 1MB. Otherwise they could be errors, successes and empty result sets.
162
179
 
163
180
  if @enabled && method == :get && CACHEABLE_HTTP_CODES.include?(response_env.status) &&
164
- response_env.present? && response_env.response_headers[CONTENT_LENGTH_KEY].to_i.between?(20,1_000_000)
181
+ response_env.body.present? && response_env.response_headers[CONTENT_LENGTH_KEY].to_i.between?(20,1_250_000)
165
182
  begin
166
- @store.store(@cache_key, response_env, expires: @expires) # ||= response_env.body
183
+ @store.store(@cache_key,
184
+ { headers: response_env.response_headers, body: response_env.body },
185
+ expires: @expires)
167
186
  rescue => e
168
187
  puts "[Parse::Cache] Store Error: #{e}"
169
188
  end
@@ -73,7 +73,8 @@ module Parse
73
73
  @batch_response = false # by default, not a batch response
74
74
  @result = nil
75
75
  # If a string is used for initializing, treat it as JSON
76
- res = JSON.parse(res) if res.is_a?(String)
76
+ # check for string to not be 'OK' since that is the health check API response
77
+ res = JSON.parse(res) if res.is_a?(String) && res != "OK".freeze
77
78
  # If it is a hash (or parsed JSON), then parse the result.
78
79
  parse_result!(res) if res.is_a?(Hash)
79
80
  # if the result is an Array, then most likely it is a set of responses
data/lib/parse/query.rb CHANGED
@@ -132,9 +132,15 @@ module Parse
132
132
  # Set the session token to send with this API request. A session token is tied to
133
133
  # a logged in {Parse::User}. When sending a session_token in the request,
134
134
  # this performs the query on behalf of the user (with their allowed priviledges).
135
+ # Using the short hand (inline) form, you can also pass an authenticated {Parse::User} instance
136
+ # or a {Parse::Session} instance.
135
137
  # @example
136
138
  # # perform this query as user represented by session_token
137
- # query = Parse::Query.new("_User", :name => "Bob", :session_token => "r:XyX123...")
139
+
140
+ # query = Parse::Query.new("_User", :name => "Bob")
141
+ # query.session_token = "r:XyX123..."
142
+ # # or inline
143
+ # query = Parse::Query.new("_User", :name => "Bob", :session => "r:XyX123...")
138
144
  # @note Using a session_token automatically disables sending the master key in the request.
139
145
  # @return [String] the session token to send with this API request.
140
146
  attr_accessor :table, :client, :key, :cache, :use_master_key, :session_token
@@ -6,6 +6,6 @@ module Parse
6
6
  # The Parse Server SDK for Ruby
7
7
  module Stack
8
8
  # The current version.
9
- VERSION = "1.6.1"
9
+ VERSION = "1.6.4"
10
10
  end
11
11
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: parse-stack
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.6.1
4
+ version: 1.6.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Anthony Persaud
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2016-12-01 00:00:00.000000000 Z
11
+ date: 2016-12-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activemodel
@@ -274,7 +274,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
274
274
  version: '0'
275
275
  requirements: []
276
276
  rubyforge_project:
277
- rubygems_version: 2.5.1
277
+ rubygems_version: 2.6.6
278
278
  signing_key:
279
279
  specification_version: 4
280
280
  summary: Parse-Server Ruby Client and Relational Mapper