jason-rails 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +34 -0
  3. data/README.md +6 -9
  4. data/app/assets/config/jason_engine_manifest.js +1 -0
  5. data/app/assets/images/jason/engine/.keep +0 -0
  6. data/app/assets/stylesheets/jason/engine/application.css +15 -0
  7. data/app/controllers/jason/api_controller.rb +36 -0
  8. data/app/helpers/jason/engine/application_helper.rb +6 -0
  9. data/app/jobs/jason/engine/application_job.rb +6 -0
  10. data/app/mailers/jason/engine/application_mailer.rb +8 -0
  11. data/app/models/jason/engine/application_record.rb +7 -0
  12. data/app/views/layouts/jason/engine/application.html.erb +15 -0
  13. data/client/babel.config.js +13 -0
  14. data/client/lib/JasonProvider.d.ts +5 -4
  15. data/client/lib/JasonProvider.js +30 -3
  16. data/client/lib/actionFactory.js +1 -1
  17. data/client/lib/createActions.d.ts +1 -1
  18. data/client/lib/createActions.js +2 -27
  19. data/client/lib/createJasonReducers.js +1 -0
  20. data/client/lib/createOptDis.d.ts +1 -0
  21. data/client/lib/createOptDis.js +45 -0
  22. data/client/lib/createPayloadHandler.d.ts +1 -1
  23. data/client/lib/createPayloadHandler.js +23 -6
  24. data/client/lib/deepCamelizeKeys.d.ts +1 -0
  25. data/client/lib/deepCamelizeKeys.js +23 -0
  26. data/client/lib/deepCamelizeKeys.test.d.ts +1 -0
  27. data/client/lib/deepCamelizeKeys.test.js +106 -0
  28. data/client/lib/index.d.ts +4 -4
  29. data/client/package.json +17 -4
  30. data/client/src/JasonProvider.tsx +33 -5
  31. data/client/src/actionFactory.ts +1 -1
  32. data/client/src/createActions.ts +2 -33
  33. data/client/src/createJasonReducers.ts +1 -0
  34. data/client/src/createOptDis.ts +47 -0
  35. data/client/src/createPayloadHandler.ts +26 -4
  36. data/client/src/deepCamelizeKeys.test.ts +113 -0
  37. data/client/src/deepCamelizeKeys.ts +17 -0
  38. data/client/yarn.lock +4539 -81
  39. data/config/routes.rb +4 -0
  40. data/jason-rails.gemspec +5 -0
  41. data/lib/jason.rb +7 -1
  42. data/lib/jason/api_model.rb +16 -0
  43. data/lib/jason/channel.rb +2 -2
  44. data/lib/jason/engine.rb +5 -0
  45. data/lib/jason/publisher.rb +38 -6
  46. data/lib/jason/subscription.rb +21 -24
  47. data/lib/jason/version.rb +1 -1
  48. metadata +81 -3
@@ -0,0 +1,4 @@
1
+ Jason::Engine.routes.draw do
2
+ get '/api/schema', to: 'api#schema'
3
+ post '/api/action', to: 'api#action'
4
+ end
@@ -22,4 +22,9 @@ Gem::Specification.new do |spec|
22
22
  end
23
23
  spec.executables = []
24
24
  spec.require_paths = ["lib"]
25
+
26
+ spec.add_dependency "rails", ">= 5"
27
+ spec.add_dependency "connection_pool", ">= 2.2.3"
28
+ spec.add_dependency "redis", ">= 4"
29
+ spec.add_dependency "jsondiff"
25
30
  end
@@ -1,10 +1,16 @@
1
+ require 'connection_pool'
2
+ require 'redis'
3
+ require 'jsondiff'
4
+
1
5
  require "jason/version"
2
6
  require 'jason/api_model'
3
7
  require 'jason/channel'
4
8
  require 'jason/publisher'
5
9
  require 'jason/subscription'
10
+ require 'jason/engine'
6
11
 
7
12
  module Jason
8
13
  class Error < StandardError; end
9
- # Your code goes here...
14
+
15
+ $redis_jason = ::ConnectionPool::Wrapper.new(size: 5, timeout: 3) { ::Redis.new(url: ENV['REDIS_URL']) }
10
16
  end
@@ -15,6 +15,10 @@ class Jason::ApiModel
15
15
  model.allowed_params || []
16
16
  end
17
17
 
18
+ def allowed_object_params
19
+ model.allowed_object_params || []
20
+ end
21
+
18
22
  def include_models
19
23
  model.include_models || []
20
24
  end
@@ -35,6 +39,18 @@ class Jason::ApiModel
35
39
  model.scope
36
40
  end
37
41
 
42
+ def permit(params)
43
+ pp self
44
+ pp params
45
+ params = params.require(:payload).permit(allowed_params).tap do |allowed|
46
+ pp "ALLOWED"
47
+ pp allowed
48
+ allowed_object_params.each do |key|
49
+ allowed[key] = params[:payload][key].to_unsafe_h if params[:payload][key]
50
+ end
51
+ end
52
+ end
53
+
38
54
  def as_json_config
39
55
  include_configs = include_models.map do |assoc|
40
56
  reflection = name.classify.constantize.reflect_on_association(assoc.to_sym)
@@ -24,8 +24,8 @@ class Jason::Channel < ActionCable::Channel::Base
24
24
  # stream_from s.channel
25
25
  # end
26
26
  elsif (data = message['getPayload'])
27
- config = data.config
28
- model = data.model
27
+ config = data['config']
28
+ model = data['model']
29
29
  Jason::Subscription.new(config: config).get(model.to_s.underscore)
30
30
  end
31
31
  rescue => e
@@ -0,0 +1,5 @@
1
+ module Jason
2
+ class Engine < ::Rails::Engine
3
+ isolate_namespace Jason
4
+ end
5
+ end
@@ -7,17 +7,16 @@ module Jason::Publisher
7
7
 
8
8
  if self.persisted? && (scope.blank? || self.class.unscoped.send(scope).exists?(self.id))
9
9
  payload = self.reload.as_json(as_json_config)
10
- $redis.hset("jason:#{self.class.name.underscore}:cache", self.id, payload.to_json)
10
+ $redis_jason.hset("jason:#{self.class.name.underscore}:cache", self.id, payload.to_json)
11
11
  else
12
- $redis.hdel("jason:#{self.class.name.underscore}:cache", self.id)
12
+ $redis_jason.hdel("jason:#{self.class.name.underscore}:cache", self.id)
13
13
  end
14
14
  end
15
15
 
16
16
  def publish_json
17
17
  cache_json
18
18
  return if skip_publish_json
19
- subscriptions = $redis.hgetall("jason:#{self.class.name.underscore}:subscriptions")
20
- subscriptions.each do |id, config_json|
19
+ self.class.jason_subscriptions.each do |id, config_json|
21
20
  config = JSON.parse(config_json)
22
21
 
23
22
  if (config['conditions'] || {}).all? { |field, value| self.send(field) == value }
@@ -33,7 +32,11 @@ module Jason::Publisher
33
32
 
34
33
  class_methods do
35
34
  def subscriptions
36
- $redis.hgetall("jason:#{self.name.underscore}:subscriptions")
35
+ $redis_jason.hgetall("jason:#{self.name.underscore}:subscriptions")
36
+ end
37
+
38
+ def jason_subscriptions
39
+ $redis_jason.hgetall("jason:#{self.name.underscore}:subscriptions")
37
40
  end
38
41
 
39
42
  def publish_all(instances)
@@ -45,7 +48,7 @@ module Jason::Publisher
45
48
  end
46
49
 
47
50
  def flush_cache
48
- $redis.del("jason:#{self.name.underscore}:cache")
51
+ $redis_jason.del("jason:#{self.name.underscore}:cache")
49
52
  end
50
53
 
51
54
  def setup_json
@@ -69,6 +72,35 @@ module Jason::Publisher
69
72
  }
70
73
  end
71
74
  end
75
+
76
+ def find_or_create_by_id(params)
77
+ object = find_by(id: params[:id])
78
+
79
+ if object
80
+ object.update(params)
81
+ elsif params[:hidden]
82
+ return false ## If an object is passed with hidden = true but didn't already exist, it's safe to never create it
83
+ else
84
+ object = create!(params)
85
+ end
86
+
87
+ object
88
+ end
89
+
90
+ def find_or_create_by_id!(params)
91
+ object = find_by(id: params[:id])
92
+
93
+ if object
94
+ object.update!(params)
95
+ elsif params[:hidden]
96
+ ## TODO: We're diverging from semantics of the Rails bang! methods here, which would normally either raise or return an object. Find a way to make this better.
97
+ return false ## If an object is passed with hidden = true but didn't already exist, it's safe to never create it
98
+ else
99
+ object = create!(params)
100
+ end
101
+
102
+ object
103
+ end
72
104
  end
73
105
 
74
106
  included do
@@ -4,7 +4,7 @@ class Jason::Subscription
4
4
  def initialize(id: nil, config: nil)
5
5
  if id
6
6
  @id = id
7
- raw_config = $redis.hgetall("jason:subscriptions:#{id}").map { |k,v| [k, JSON.parse(v)] }.to_h.with_indifferent_access
7
+ raw_config = $redis_jason.hgetall("jason:subscriptions:#{id}").map { |k,v| [k, JSON.parse(v)] }.to_h.with_indifferent_access
8
8
  set_config(raw_config)
9
9
  else
10
10
  @id = Digest::MD5.hexdigest(config.to_json)
@@ -18,30 +18,28 @@ class Jason::Subscription
18
18
 
19
19
  def configure(raw_config)
20
20
  set_config(raw_config)
21
- $redis.hmset("jason:subscriptions:#{id}", *config.map { |k,v| [k, v.to_json]}.flatten)
21
+ $redis_jason.hmset("jason:subscriptions:#{id}", *config.map { |k,v| [k, v.to_json]}.flatten)
22
22
  end
23
23
 
24
24
  def destroy
25
25
  config.each do |model, value|
26
- $redis.srem("jason:#{model.to_s.underscore}:subscriptions", id)
26
+ $redis_jason.srem("jason:#{model.to_s.underscore}:subscriptions", id)
27
27
  end
28
- $redis.del("jason:subscriptions:#{id}")
28
+ $redis_jason.del("jason:subscriptions:#{id}")
29
29
  end
30
30
 
31
31
  def add_consumer(consumer_id)
32
32
  before_consumer_count = consumer_count
33
- $redis.sadd("jason:subscriptions:#{id}:consumers", consumer_id)
34
- $redis.hset("jason:consumers", consumer_id, Time.now.utc)
33
+ $redis_jason.sadd("jason:subscriptions:#{id}:consumers", consumer_id)
34
+ $redis_jason.hset("jason:consumers", consumer_id, Time.now.utc)
35
35
 
36
- if before_consumer_count == 0
37
- add_subscriptions
38
- publish_all
39
- end
36
+ add_subscriptions
37
+ publish_all
40
38
  end
41
39
 
42
40
  def remove_consumer(consumer_id)
43
- $redis.srem("jason:subscriptions:#{id}:consumers", consumer_id)
44
- $redis.hdel("jason:consumers", consumer_id)
41
+ $redis_jason.srem("jason:subscriptions:#{id}:consumers", consumer_id)
42
+ $redis_jason.hdel("jason:consumers", consumer_id)
45
43
 
46
44
  if consumer_count == 0
47
45
  remove_subscriptions
@@ -49,7 +47,7 @@ class Jason::Subscription
49
47
  end
50
48
 
51
49
  def consumer_count
52
- $redis.scard("jason:subscriptions:#{id}:consumers")
50
+ $redis_jason.scard("jason:subscriptions:#{id}:consumers")
53
51
  end
54
52
 
55
53
  def channel
@@ -67,14 +65,14 @@ class Jason::Subscription
67
65
 
68
66
  def add_subscriptions
69
67
  config.each do |model, value|
70
- $redis.hset("jason:#{model.to_s.underscore}:subscriptions", id, value.to_json)
68
+ $redis_jason.hset("jason:#{model.to_s.underscore}:subscriptions", id, value.to_json)
71
69
  update(model)
72
70
  end
73
71
  end
74
72
 
75
73
  def remove_subscriptions
76
74
  config.each do |model, _|
77
- $redis.hdel("jason:#{model.to_s.underscore}:subscriptions", id)
75
+ $redis_jason.hdel("jason:#{model.to_s.underscore}:subscriptions", id)
78
76
  end
79
77
  end
80
78
 
@@ -86,8 +84,8 @@ class Jason::Subscription
86
84
  end
87
85
 
88
86
  def get(model)
89
- value = JSON.parse($redis.get("#{channel}:#{model}:value") || '{}')
90
- idx = $redis.get("#{channel}:#{model}:idx").to_i
87
+ value = JSON.parse($redis_jason.get("#{channel}:#{model}:value") || '[]')
88
+ idx = $redis_jason.get("#{channel}:#{model}:idx").to_i
91
89
 
92
90
  {
93
91
  type: 'payload',
@@ -113,7 +111,7 @@ class Jason::Subscription
113
111
  def get_throttle
114
112
  if !$throttle_rate || !$throttle_timeout || Time.now.utc > $throttle_timeout
115
113
  $throttle_timeout = Time.now.utc + 5.seconds
116
- $throttle_rate = (Sidekiq.redis { |r| r.get 'global_throttle_rate' } || 0).to_i
114
+ $throttle_rate = ($redis_jason.get('global_throttle_rate') || 0).to_i
117
115
  else
118
116
  $throttle_rate
119
117
  end
@@ -124,15 +122,15 @@ class Jason::Subscription
124
122
  start_time = Time.now.utc
125
123
  conditions = config[model]['conditions']
126
124
 
127
- value = $redis.hgetall("jason:#{model}:cache")
125
+ value = $redis_jason.hgetall("jason:#{model}:cache")
128
126
  .values.map { |v| JSON.parse(v) }
129
127
  .select { |v| (conditions || {}).all? { |field, value| v[field] == value } }
130
128
  .sort_by { |v| v['id'] }
131
129
 
132
130
  # lfsa = last finished, started at
133
131
  # If another job that started after this one, finished before this one, skip sending this state update
134
- if Time.parse(Sidekiq.redis { |r| r.get("jason:#{channel}:lfsa") || '1970-01-01 00:00:00 UTC' } ) < start_time
135
- Sidekiq.redis { |r| r.set("jason:#{channel}:lfsa", start_time) }
132
+ if Time.parse($redis_jason.get("jason:#{channel}:lfsa") || '1970-01-01 00:00:00 UTC') < start_time
133
+ $redis_jason.set("jason:#{channel}:lfsa", start_time)
136
134
  else
137
135
  return
138
136
  end
@@ -149,12 +147,11 @@ class Jason::Subscription
149
147
  end
150
148
  LUA
151
149
 
152
- result = $redis.eval cmd, [], ["#{channel}:#{model}", value.to_json]
150
+ result = $redis_jason.eval cmd, [], ["#{channel}:#{model}", value.to_json]
153
151
  return if result.blank?
154
152
 
155
153
  idx = result[0]
156
- old_value = JSON.parse(result[1] || '{}')
157
-
154
+ old_value = JSON.parse(result[1] || '[]')
158
155
  diff = get_diff(old_value, value)
159
156
 
160
157
  end_time = Time.now.utc
@@ -1,3 +1,3 @@
1
1
  module Jason
2
- VERSION = "0.3.0"
2
+ VERSION = "0.4.0"
3
3
  end
metadata CHANGED
@@ -1,15 +1,71 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jason-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - James Rees
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-12-04 00:00:00.000000000 Z
12
- dependencies: []
11
+ date: 2020-12-22 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '5'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '5'
27
+ - !ruby/object:Gem::Dependency
28
+ name: connection_pool
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 2.2.3
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: 2.2.3
41
+ - !ruby/object:Gem::Dependency
42
+ name: redis
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '4'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '4'
55
+ - !ruby/object:Gem::Dependency
56
+ name: jsondiff
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
13
69
  description:
14
70
  email:
15
71
  - jarees@gmail.com
@@ -22,11 +78,22 @@ files:
22
78
  - ".travis.yml"
23
79
  - CODE_OF_CONDUCT.md
24
80
  - Gemfile
81
+ - Gemfile.lock
25
82
  - LICENSE.txt
26
83
  - README.md
27
84
  - Rakefile
85
+ - app/assets/config/jason_engine_manifest.js
86
+ - app/assets/images/jason/engine/.keep
87
+ - app/assets/stylesheets/jason/engine/application.css
88
+ - app/controllers/jason/api_controller.rb
89
+ - app/helpers/jason/engine/application_helper.rb
90
+ - app/jobs/jason/engine/application_job.rb
91
+ - app/mailers/jason/engine/application_mailer.rb
92
+ - app/models/jason/engine/application_record.rb
93
+ - app/views/layouts/jason/engine/application.html.erb
28
94
  - bin/console
29
95
  - bin/setup
96
+ - client/babel.config.js
30
97
  - client/lib/JasonContext.d.ts
31
98
  - client/lib/JasonContext.js
32
99
  - client/lib/JasonProvider.d.ts
@@ -37,8 +104,14 @@ files:
37
104
  - client/lib/createActions.js
38
105
  - client/lib/createJasonReducers.d.ts
39
106
  - client/lib/createJasonReducers.js
107
+ - client/lib/createOptDis.d.ts
108
+ - client/lib/createOptDis.js
40
109
  - client/lib/createPayloadHandler.d.ts
41
110
  - client/lib/createPayloadHandler.js
111
+ - client/lib/deepCamelizeKeys.d.ts
112
+ - client/lib/deepCamelizeKeys.js
113
+ - client/lib/deepCamelizeKeys.test.d.ts
114
+ - client/lib/deepCamelizeKeys.test.js
42
115
  - client/lib/index.d.ts
43
116
  - client/lib/index.js
44
117
  - client/lib/makeEager.d.ts
@@ -53,17 +126,22 @@ files:
53
126
  - client/src/actionFactory.ts
54
127
  - client/src/createActions.ts
55
128
  - client/src/createJasonReducers.ts
129
+ - client/src/createOptDis.ts
56
130
  - client/src/createPayloadHandler.ts
131
+ - client/src/deepCamelizeKeys.test.ts
132
+ - client/src/deepCamelizeKeys.ts
57
133
  - client/src/index.ts
58
134
  - client/src/makeEager.ts
59
135
  - client/src/useAct.ts
60
136
  - client/src/useSub.ts
61
137
  - client/tsconfig.json
62
138
  - client/yarn.lock
139
+ - config/routes.rb
63
140
  - jason-rails.gemspec
64
141
  - lib/jason.rb
65
142
  - lib/jason/api_model.rb
66
143
  - lib/jason/channel.rb
144
+ - lib/jason/engine.rb
67
145
  - lib/jason/publisher.rb
68
146
  - lib/jason/subscription.rb
69
147
  - lib/jason/version.rb