jason-rails 0.6.6 → 0.7.2

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.
Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +41 -0
  3. data/Gemfile.lock +11 -4
  4. data/README.md +9 -15
  5. data/app/controllers/jason/{api_controller.rb → jason_controller.rb} +27 -5
  6. data/app/controllers/jason/{api/pusher_controller.rb → pusher_controller.rb} +1 -1
  7. data/app/workers/jason/outbound_message_queue_worker.rb +21 -0
  8. data/client/lib/JasonProvider.d.ts +2 -1
  9. data/client/lib/JasonProvider.js +2 -2
  10. data/client/lib/addRelations.d.ts +1 -0
  11. data/client/lib/addRelations.js +39 -0
  12. data/client/lib/createJasonReducers.js +4 -2
  13. data/client/lib/createOptDis.d.ts +1 -1
  14. data/client/lib/createOptDis.js +9 -8
  15. data/client/lib/createServerActionQueue.d.ts +3 -2
  16. data/client/lib/createServerActionQueue.js +32 -6
  17. data/client/lib/createServerActionQueue.test.js +61 -6
  18. data/client/lib/createThenable.d.ts +1 -0
  19. data/client/lib/createThenable.js +5 -0
  20. data/client/lib/index.d.ts +7 -1
  21. data/client/lib/index.js +3 -1
  22. data/client/lib/transportAdapters/actionCableAdapter.js +24 -4
  23. data/client/lib/transportAdapters/pusherAdapter.js +1 -1
  24. data/client/lib/useDraft.d.ts +1 -0
  25. data/client/lib/useDraft.js +13 -0
  26. data/client/lib/useEager.d.ts +1 -1
  27. data/client/lib/useEager.js +10 -5
  28. data/client/lib/useJason.d.ts +2 -1
  29. data/client/lib/useJason.js +4 -6
  30. data/client/package.json +1 -1
  31. data/client/src/JasonProvider.tsx +2 -2
  32. data/client/src/addRelations.ts +33 -0
  33. data/client/src/createJasonReducers.ts +4 -2
  34. data/client/src/createOptDis.ts +10 -8
  35. data/client/src/createServerActionQueue.test.ts +60 -6
  36. data/client/src/createServerActionQueue.ts +41 -6
  37. data/client/src/index.ts +2 -0
  38. data/client/src/transportAdapters/actionCableAdapter.ts +24 -5
  39. data/client/src/transportAdapters/pusherAdapter.ts +1 -2
  40. data/client/src/useDraft.ts +17 -0
  41. data/client/src/useEager.ts +9 -6
  42. data/client/src/useJason.ts +3 -6
  43. data/config/routes.rb +6 -6
  44. data/jason-rails.gemspec +1 -0
  45. data/lib/jason.rb +6 -1
  46. data/lib/jason/api_model.rb +0 -4
  47. data/lib/jason/broadcaster.rb +2 -1
  48. data/lib/jason/channel.rb +0 -7
  49. data/lib/jason/conditions_matcher.rb +88 -0
  50. data/lib/jason/consistency_checker.rb +65 -0
  51. data/lib/jason/graph_helper.rb +4 -0
  52. data/lib/jason/publisher.rb +42 -38
  53. data/lib/jason/subscription.rb +63 -18
  54. data/lib/jason/version.rb +1 -1
  55. metadata +29 -7
  56. data/client/src/makeEager.ts +0 -46
  57. data/lib/jason/publisher_old.rb +0 -112
  58. data/lib/jason/subscription_old.rb +0 -171
@@ -26,6 +26,10 @@ class Jason::GraphHelper
26
26
  $redis_jason.srem("jason:subscriptions:#{id}:graph", edges)
27
27
  end
28
28
 
29
+ def apply_add_node_at_root(node)
30
+ diff_edges_from_graph(add_edges: ["root/#{node}"])
31
+ end
32
+
29
33
  def apply_remove_node(node)
30
34
  edges = $redis_jason.smembers("jason:subscriptions:#{id}:graph")
31
35
  edges = find_edges_with_node(edges, node)
@@ -5,6 +5,7 @@ module Jason::Publisher
5
5
  def self.cache_all
6
6
  Rails.application.eager_load!
7
7
  ActiveRecord::Base.descendants.each do |klass|
8
+ $redis_jason.del("jason:cache:#{klass.name.underscore}")
8
9
  klass.cache_all if klass.respond_to?(:cache_all)
9
10
  end
10
11
  end
@@ -15,7 +16,7 @@ module Jason::Publisher
15
16
 
16
17
  # Exists
17
18
  if self.persisted? && (scope.blank? || self.class.unscoped.send(scope).exists?(self.id))
18
- payload = self.reload.as_json(as_json_config)
19
+ payload = self.as_json(as_json_config)
19
20
  gidx = Jason::LuaGenerator.new.cache_json(self.class.name.underscore, self.id, payload)
20
21
  return [payload, gidx]
21
22
  # Has been destroyed
@@ -42,7 +43,9 @@ module Jason::Publisher
42
43
  # - TODO: The value of an instance changes so that it enters/leaves a subscription
43
44
 
44
45
  # TODO: Optimize this, by caching associations rather than checking each time instance is saved
45
- jason_assocs = self.class.reflect_on_all_associations(:belongs_to).select { |assoc| assoc.klass.respond_to?(:has_jason?) }
46
+ jason_assocs = self.class.reflect_on_all_associations(:belongs_to)
47
+ .reject { |assoc| assoc.polymorphic? } # Can't get the class name of a polymorphic association, by
48
+ .select { |assoc| assoc.klass.respond_to?(:has_jason?) }
46
49
  jason_assocs.each do |assoc|
47
50
  if previous_changes[assoc.foreign_key].present?
48
51
  Jason::Subscription.update_ids(
@@ -70,13 +73,38 @@ module Jason::Publisher
70
73
  )
71
74
  end
72
75
 
73
- # - An instance is created where it belongs_to an _all_ subscription
74
- if previous_changes['id'].present?
75
- Jason::Subscription.add_id(self.class.name.underscore, id)
76
- end
77
-
78
76
  if persisted?
77
+ applied_sub_ids = []
78
+
79
+ jason_conditions.each do |row|
80
+ matches = row['conditions'].map do |key, rules|
81
+ Jason::ConditionsMatcher.new(self.class).test_match(key, rules, previous_changes)
82
+ end
83
+ next if matches.all? { |m| m.nil? } # None of the keys were in previous changes - therefore this condition does not apply
84
+ in_sub = matches.all? { |m| m }
85
+
86
+ if in_sub
87
+ row['subscription_ids'].each do |sub_id|
88
+ Jason::Subscription.find_by_id(sub_id).add_id(self.class.name.underscore, self.id)
89
+ applied_sub_ids.push(sub_id)
90
+ end
91
+ else
92
+ row['subscription_ids'].each do |sub_id|
93
+ jason_subscriptions.each do |already_sub_id|
94
+ # If this sub ID already has this instance, remove it
95
+ if already_sub_id == sub_id
96
+ sub = Jason::Subscription.find_by_id(already_sub_id)
97
+ sub.remove_id(self.class.name.underscore, self.id)
98
+ applied_sub_ids.push(already_sub_id)
99
+ end
100
+ end
101
+ end
102
+ end
103
+ end
104
+
79
105
  jason_subscriptions.each do |sub_id|
106
+ next if applied_sub_ids.include?(sub_id)
107
+
80
108
  Jason::Subscription.new(id: sub_id).update(self.class.name.underscore, id, payload, gidx)
81
109
  end
82
110
  end
@@ -91,13 +119,17 @@ module Jason::Publisher
91
119
  Jason::Subscription.for_instance(self.class.name.underscore, id)
92
120
  end
93
121
 
122
+ def jason_conditions
123
+ Jason::Subscription.conditions_for_model(self.class.name.underscore)
124
+ end
125
+
94
126
  def jason_cached_value
95
127
  JSON.parse($redis_jason.hget("jason:cache:#{self.class.name.underscore}", id) || '{}')
96
128
  end
97
129
 
98
130
  class_methods do
99
131
  def cache_all
100
- all.each(&:cache_json)
132
+ all.find_each(&:cache_json)
101
133
  end
102
134
 
103
135
  def has_jason?
@@ -115,36 +147,8 @@ module Jason::Publisher
115
147
  self.after_initialize -> {
116
148
  @api_model = Jason::ApiModel.new(self.class.name.underscore)
117
149
  }
118
- self.after_commit :publish_json_if_changed
119
- end
120
-
121
- def find_or_create_by_id(params)
122
- object = find_by(id: params[:id])
123
-
124
- if object
125
- object.update(params)
126
- elsif params[:hidden]
127
- return false ## If an object is passed with hidden = true but didn't already exist, it's safe to never create it
128
- else
129
- object = create!(params)
130
- end
131
-
132
- object
133
- end
134
-
135
- def find_or_create_by_id!(params)
136
- object = find_by(id: params[:id])
137
-
138
- if object
139
- object.update!(params)
140
- elsif params[:hidden]
141
- ## 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.
142
- return false ## If an object is passed with hidden = true but didn't already exist, it's safe to never create it
143
- else
144
- object = create!(params)
145
- end
146
-
147
- object
150
+ self.after_commit :force_publish_json, on: [:create, :destroy]
151
+ self.after_commit :publish_json_if_changed, on: [:update]
148
152
  end
149
153
  end
150
154
 
@@ -48,15 +48,31 @@ class Jason::Subscription
48
48
  end
49
49
  end
50
50
 
51
+ def self.all_for_model(model_name)
52
+ $redis_jason.smembers("jason:models:#{model_name}:all:subscriptions")
53
+ end
54
+
51
55
  def self.for_instance(model_name, id, include_all = true)
52
56
  subs = $redis_jason.smembers("jason:models:#{model_name}:#{id}:subscriptions")
53
57
  if include_all
54
- subs += $redis_jason.smembers("jason:models:#{model_name}:all:subscriptions")
58
+ subs += all_for_model(model_name)
55
59
  end
56
-
57
60
  subs
58
61
  end
59
62
 
63
+ # returns [
64
+ # { condition: { post_id: 123 }, subscription_ids: [] }
65
+ # ]
66
+ def self.conditions_for_model(model_name)
67
+ rows = $redis_jason.smembers("jason:models:#{model_name}:conditions").map do |row|
68
+ JSON.parse(row)
69
+ end
70
+ conditions = rows.group_by { |row| row['conditions'] }
71
+ conditions.map do |conditions, rows|
72
+ { 'conditions' => conditions, 'subscription_ids' => rows.map { |row| row['subscription_id'] } }
73
+ end
74
+ end
75
+
60
76
  def self.for_model(model_name)
61
77
 
62
78
  end
@@ -163,10 +179,14 @@ class Jason::Subscription
163
179
  subscription.apply_id_changeset(id_changeset)
164
180
  subscription.broadcast_id_changeset(id_changeset)
165
181
  end
182
+
183
+ #########
184
+ # ---> Join the community
185
+ # Subs where changed is parent + parent is an _all_ or _condition_ subscription
186
+
166
187
  end
167
188
 
168
189
  def self.remove_ids(model_name, ids)
169
- # td: finish this
170
190
  ids.each do |instance_id|
171
191
  for_instance(model_name, instance_id, false).each do |sub_id|
172
192
  subscription = find_by_id(sub_id)
@@ -176,11 +196,13 @@ class Jason::Subscription
176
196
  subscription.broadcast_id_changeset(id_changeset)
177
197
  end
178
198
  end
179
- end
180
-
181
- # Add ID to any _all_ subscriptions
182
- def self.add_id(model_name, id)
183
199
 
200
+ all_for_model(model_name).each do |sub_id|
201
+ subscription = find_by_id(sub_id)
202
+ ids.each do |id|
203
+ subscription.destroy(model_name, id)
204
+ end
205
+ end
184
206
  end
185
207
 
186
208
  def self.all
@@ -203,6 +225,28 @@ class Jason::Subscription
203
225
  end
204
226
  end
205
227
 
228
+ def remove_id(model_name, id)
229
+ id_changeset = graph_helper.apply_remove_node("#{model_name}:#{id}")
230
+ apply_id_changeset(id_changeset)
231
+ broadcast_id_changeset(id_changeset)
232
+ end
233
+
234
+ def add_id(model_name, id)
235
+ id_changeset = graph_helper.apply_update({
236
+ add: [
237
+ {
238
+ model_names: [model_name],
239
+ instance_ids: [[id]]
240
+ },
241
+ # Add IDs of child models
242
+ load_ids_for_sub_models(model_name, id)
243
+ ]
244
+ })
245
+
246
+ apply_id_changeset(id_changeset)
247
+ broadcast_id_changeset(id_changeset)
248
+ end
249
+
206
250
  def remove_ids(model_name, ids)
207
251
  $redis_jason.srem("jason:subscriptions:#{id}:ids:#{model_name}", ids)
208
252
  ids.each do |instance_id|
@@ -238,13 +282,18 @@ class Jason::Subscription
238
282
  all_models = includes_helper.all_models(model_name)
239
283
 
240
284
  relation = model_name.classify.constantize.all.eager_load(includes_tree)
241
-
242
285
  if model_name == model
243
286
  if conditions.blank?
244
287
  $redis_jason.sadd("jason:models:#{model_name}:all:subscriptions", id)
245
288
  all_models -= [model_name]
246
- else
289
+ elsif conditions.keys == ['id']
247
290
  relation = relation.where(conditions)
291
+ else
292
+ $redis_jason.sadd("jason:models:#{model_name}:conditions", {
293
+ 'conditions' => conditions,
294
+ 'subscription_id' => self.id
295
+ }.to_json)
296
+ relation = Jason::ConditionsMatcher.new(relation.klass).apply_conditions(relation, conditions)
248
297
  end
249
298
  else
250
299
  raise "Must supply IDs for sub models" if ids.nil?
@@ -257,7 +306,7 @@ class Jason::Subscription
257
306
 
258
307
  # pluck returns only a 1D array if only 1 arg passed
259
308
  if all_models.size == 1
260
- instance_ids = [instance_ids]
309
+ instance_ids = instance_ids.map { |id| [id] }
261
310
  end
262
311
 
263
312
  return { model_names: all_models, instance_ids: instance_ids }
@@ -266,12 +315,12 @@ class Jason::Subscription
266
315
  # 'posts', [post#1, post#2,...]
267
316
  def set_ids_for_sub_models(model_name = model, ids = nil, enforce: false)
268
317
  edge_set = load_ids_for_sub_models(model_name, ids)
269
-
270
318
  # Build the tree
271
319
  id_changeset = graph_helper.apply_update({
272
320
  add: [edge_set],
273
321
  enforce: enforce
274
322
  })
323
+
275
324
  apply_id_changeset(id_changeset)
276
325
  end
277
326
 
@@ -287,6 +336,7 @@ class Jason::Subscription
287
336
  end
288
337
  $redis_jason.del("jason:subscriptions:#{id}:ids:#{model_name}")
289
338
  end
339
+ $redis_jason.del("jason:subscriptions:#{id}:graph")
290
340
  end
291
341
 
292
342
  def ids(model_name = model)
@@ -328,10 +378,6 @@ class Jason::Subscription
328
378
  def remove_consumer(consumer_id)
329
379
  $redis_jason.srem("jason:subscriptions:#{id}:consumers", consumer_id)
330
380
  $redis_jason.hdel("jason:consumers", consumer_id)
331
-
332
- if consumer_count == 0
333
- clear_all_ids
334
- end
335
381
  end
336
382
 
337
383
  def consumer_count
@@ -344,8 +390,8 @@ class Jason::Subscription
344
390
 
345
391
  def user_can_access?(user)
346
392
  # td: implement the authorization logic here
347
- return true if Jason.authorization_service.blank?
348
- Jason.authorization_service.call(user, model, conditions, includes_helper.all_models - [model])
393
+ return true if Jason.subscription_authorization_service.blank?
394
+ Jason.subscription_authorization_service.call(user, model, conditions, includes_helper.all_models - [model])
349
395
  end
350
396
 
351
397
  def get
@@ -381,7 +427,6 @@ class Jason::Subscription
381
427
  # Remove subscription state
382
428
  if hard
383
429
  clear_all_ids
384
- $redis_jason.del("jason:subscriptions:#{id}:graph")
385
430
  end
386
431
 
387
432
  set_ids_for_sub_models(enforce: true)
data/lib/jason/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Jason
2
- VERSION = "0.6.6"
2
+ VERSION = "0.7.2"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jason-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.6
4
+ version: 0.7.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - James Rees
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-02-19 00:00:00.000000000 Z
11
+ date: 2021-04-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -108,6 +108,20 @@ dependencies:
108
108
  - - ">="
109
109
  - !ruby/object:Gem::Version
110
110
  version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: sidekiq
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
111
125
  description:
112
126
  email:
113
127
  - jarees@gmail.com
@@ -126,8 +140,9 @@ files:
126
140
  - LICENSE.txt
127
141
  - README.md
128
142
  - Rakefile
129
- - app/controllers/jason/api/pusher_controller.rb
130
- - app/controllers/jason/api_controller.rb
143
+ - app/controllers/jason/jason_controller.rb
144
+ - app/controllers/jason/pusher_controller.rb
145
+ - app/workers/jason/outbound_message_queue_worker.rb
131
146
  - bin/console
132
147
  - bin/setup
133
148
  - client/babel.config.js
@@ -137,6 +152,8 @@ files:
137
152
  - client/lib/JasonProvider.js
138
153
  - client/lib/actionFactory.d.ts
139
154
  - client/lib/actionFactory.js
155
+ - client/lib/addRelations.d.ts
156
+ - client/lib/addRelations.js
140
157
  - client/lib/createActions.d.ts
141
158
  - client/lib/createActions.js
142
159
  - client/lib/createJasonReducers.d.ts
@@ -149,6 +166,8 @@ files:
149
166
  - client/lib/createServerActionQueue.js
150
167
  - client/lib/createServerActionQueue.test.d.ts
151
168
  - client/lib/createServerActionQueue.test.js
169
+ - client/lib/createThenable.d.ts
170
+ - client/lib/createThenable.js
152
171
  - client/lib/createTransportAdapter.d.ts
153
172
  - client/lib/createTransportAdapter.js
154
173
  - client/lib/deepCamelizeKeys.d.ts
@@ -169,6 +188,8 @@ files:
169
188
  - client/lib/transportAdapters/pusherAdapter.js
170
189
  - client/lib/useAct.d.ts
171
190
  - client/lib/useAct.js
191
+ - client/lib/useDraft.d.ts
192
+ - client/lib/useDraft.js
172
193
  - client/lib/useEager.d.ts
173
194
  - client/lib/useEager.js
174
195
  - client/lib/useJason.d.ts
@@ -181,6 +202,7 @@ files:
181
202
  - client/src/JasonContext.ts
182
203
  - client/src/JasonProvider.tsx
183
204
  - client/src/actionFactory.ts
205
+ - client/src/addRelations.ts
184
206
  - client/src/createActions.ts
185
207
  - client/src/createJasonReducers.ts
186
208
  - client/src/createOptDis.ts
@@ -191,12 +213,12 @@ files:
191
213
  - client/src/deepCamelizeKeys.test.ts
192
214
  - client/src/deepCamelizeKeys.ts
193
215
  - client/src/index.ts
194
- - client/src/makeEager.ts
195
216
  - client/src/pruneIdsMiddleware.ts
196
217
  - client/src/restClient.ts
197
218
  - client/src/transportAdapters/actionCableAdapter.ts
198
219
  - client/src/transportAdapters/pusherAdapter.ts
199
220
  - client/src/useAct.ts
221
+ - client/src/useDraft.ts
200
222
  - client/src/useEager.ts
201
223
  - client/src/useJason.test.ts
202
224
  - client/src/useJason.ts
@@ -209,14 +231,14 @@ files:
209
231
  - lib/jason/api_model.rb
210
232
  - lib/jason/broadcaster.rb
211
233
  - lib/jason/channel.rb
234
+ - lib/jason/conditions_matcher.rb
235
+ - lib/jason/consistency_checker.rb
212
236
  - lib/jason/engine.rb
213
237
  - lib/jason/graph_helper.rb
214
238
  - lib/jason/includes_helper.rb
215
239
  - lib/jason/lua_generator.rb
216
240
  - lib/jason/publisher.rb
217
- - lib/jason/publisher_old.rb
218
241
  - lib/jason/subscription.rb
219
- - lib/jason/subscription_old.rb
220
242
  - lib/jason/version.rb
221
243
  homepage: https://github.com/jamesr2323/jason
222
244
  licenses:
@@ -1,46 +0,0 @@
1
- import pluralize from 'pluralize'
2
- import _ from 'lodash'
3
- import { useSelector } from 'react-redux'
4
-
5
- export default function (schema) {
6
- function addRelations(s, objects, objectType, relations) {
7
- // first find out relation name
8
- if (_.isArray(relations)) {
9
- relations.forEach(relation => {
10
- objects = addRelations(s, objects, objectType, relation)
11
- })
12
- } else if (typeof(relations) === 'object') {
13
- const relation = Object.keys(relations)[0]
14
- const subRelations = relations[relation]
15
-
16
- objects = addRelations(s, objects, objectType, relation)
17
- objects[relation] = addRelations(s, objects[relation], pluralize(relation), subRelations)
18
- // #
19
- } else if (typeof(relations) === 'string') {
20
- const relation = relations
21
- if (_.isArray(objects)) {
22
- objects = objects.map(obj => addRelations(s, obj, objectType, relation))
23
- } else {
24
- const relatedObjects = _.values(s[pluralize(relation)].entities)
25
-
26
- if(pluralize.isSingular(relation)) {
27
- objects = { ...objects, [relation]: _.find(relatedObjects, { id: objects[relation + 'Id'] }) }
28
- } else {
29
- objects = { ...objects, [relation]: relatedObjects.filter(e => e[pluralize.singular(objectType) + 'Id'] === objects.id) }
30
- }
31
- }
32
- }
33
-
34
- return objects
35
- }
36
-
37
- function useEager(entity, id = null, relations = []) {
38
- if (id) {
39
- return useSelector(s => addRelations(s, { ...s[entity].entities[String(id)] }, entity, relations), _.isEqual)
40
- } else {
41
- return useSelector(s => addRelations(s, _.values(s[entity].entities), entity, relations), _.isEqual)
42
- }
43
- }
44
-
45
- return useEager
46
- }