jason-rails 0.6.8 → 0.7.0
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 +4 -4
- data/CHANGELOG.md +27 -0
- data/Gemfile.lock +1 -1
- data/README.md +2 -12
- data/app/workers/jason/outbound_message_queue_worker.rb +1 -1
- data/client/lib/addRelations.d.ts +1 -0
- data/client/lib/addRelations.js +39 -0
- data/client/lib/createJasonReducers.js +4 -2
- data/client/lib/createOptDis.d.ts +1 -1
- data/client/lib/createOptDis.js +9 -8
- data/client/lib/createServerActionQueue.d.ts +3 -2
- data/client/lib/createServerActionQueue.js +32 -6
- data/client/lib/createServerActionQueue.test.js +61 -6
- data/client/lib/createThenable.d.ts +1 -0
- data/client/lib/createThenable.js +5 -0
- data/client/lib/transportAdapters/actionCableAdapter.js +24 -4
- data/client/lib/transportAdapters/pusherAdapter.js +1 -1
- data/client/lib/useDraft.d.ts +1 -0
- data/client/lib/useDraft.js +13 -0
- data/client/lib/useEager.d.ts +1 -1
- data/client/lib/useEager.js +10 -5
- data/client/lib/useJason.js +0 -3
- data/client/package.json +1 -1
- data/client/src/addRelations.ts +33 -0
- data/client/src/createJasonReducers.ts +4 -2
- data/client/src/createOptDis.ts +10 -8
- data/client/src/createServerActionQueue.test.ts +60 -6
- data/client/src/createServerActionQueue.ts +41 -6
- data/client/src/transportAdapters/actionCableAdapter.ts +24 -5
- data/client/src/transportAdapters/pusherAdapter.ts +1 -2
- data/client/src/useDraft.ts +17 -0
- data/client/src/useEager.ts +9 -6
- data/client/src/useJason.ts +0 -3
- data/lib/jason.rb +2 -0
- data/lib/jason/api_model.rb +0 -4
- data/lib/jason/channel.rb +0 -7
- data/lib/jason/conditions_matcher.rb +88 -0
- data/lib/jason/consistency_checker.rb +61 -0
- data/lib/jason/graph_helper.rb +4 -0
- data/lib/jason/publisher.rb +34 -5
- data/lib/jason/subscription.rb +49 -13
- data/lib/jason/version.rb +1 -1
- metadata +12 -3
- data/client/src/makeEager.ts +0 -46
data/lib/jason.rb
CHANGED
data/lib/jason/api_model.rb
CHANGED
@@ -36,11 +36,7 @@ class Jason::ApiModel
|
|
36
36
|
end
|
37
37
|
|
38
38
|
def permit(params)
|
39
|
-
pp self
|
40
|
-
pp params
|
41
39
|
params = params.require(:payload).permit(allowed_params).tap do |allowed|
|
42
|
-
pp "ALLOWED"
|
43
|
-
pp allowed
|
44
40
|
allowed_object_params.each do |key|
|
45
41
|
allowed[key] = params[:payload][key].to_unsafe_h if params[:payload][key]
|
46
42
|
end
|
data/lib/jason/channel.rb
CHANGED
@@ -12,7 +12,6 @@ class Jason::Channel < ActionCable::Channel::Base
|
|
12
12
|
private
|
13
13
|
|
14
14
|
def handle_message(message)
|
15
|
-
pp message['createSubscription']
|
16
15
|
@subscriptions ||= []
|
17
16
|
|
18
17
|
begin # ActionCable swallows errors in this message - ensure they're output to logs.
|
@@ -38,18 +37,12 @@ class Jason::Channel < ActionCable::Channel::Base
|
|
38
37
|
|
39
38
|
subscriptions.push(subscription)
|
40
39
|
subscription.add_consumer(identifier)
|
41
|
-
subscription.get.each do |payload|
|
42
|
-
pp payload
|
43
|
-
transmit(payload) if payload.present?
|
44
|
-
end
|
45
40
|
end
|
46
41
|
|
47
42
|
def remove_subscription(config)
|
48
43
|
subscription = Jason::Subscription.upsert_by_config(config['model'], conditions: config['conditions'], includes: config['includes'])
|
49
44
|
subscriptions.reject! { |s| s.id == subscription.id }
|
50
45
|
subscription.remove_consumer(identifier)
|
51
|
-
|
52
|
-
# TODO Stop streams
|
53
46
|
end
|
54
47
|
|
55
48
|
def get_payload(config, force_refresh = false)
|
@@ -0,0 +1,88 @@
|
|
1
|
+
class Jason::ConditionsMatcher
|
2
|
+
attr_reader :klass
|
3
|
+
|
4
|
+
def initialize(klass)
|
5
|
+
@klass = klass
|
6
|
+
end
|
7
|
+
|
8
|
+
# key, rules = 'post_id', 123
|
9
|
+
# key, rules = 'post_id', { 'value': [123,C456], 'type': 'between' }
|
10
|
+
# key, rules = 'post_id', { 'value': [123,456], 'type': 'between', 'not': true }
|
11
|
+
# key, rules = 'post_id', { 'value': 123, 'type': 'equals', 'not': true }
|
12
|
+
def test_match(key, rules, previous_changes)
|
13
|
+
return nil if !previous_changes.keys.include?(key)
|
14
|
+
|
15
|
+
if rules.is_a?(Hash)
|
16
|
+
matches = false
|
17
|
+
value = convert_to_datatype(key, rules['value'])
|
18
|
+
|
19
|
+
if rules['type'] == 'equals'
|
20
|
+
matches = previous_changes[key][1] == value
|
21
|
+
elsif rules['type'] == 'between'
|
22
|
+
matches = (value[0]..value[1]).cover?(previous_changes[key][1])
|
23
|
+
else
|
24
|
+
raise "Unrecognized rule type #{rules['type']}"
|
25
|
+
end
|
26
|
+
|
27
|
+
if rules['not']
|
28
|
+
return !matches
|
29
|
+
else
|
30
|
+
return matches
|
31
|
+
end
|
32
|
+
|
33
|
+
elsif rules.is_a?(Array)
|
34
|
+
value = convert_to_datatype(key, rules)
|
35
|
+
return previous_changes[key][1].includes?(value)
|
36
|
+
else
|
37
|
+
value = convert_to_datatype(key, rules)
|
38
|
+
return previous_changes[key][1] == value
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# conditions = { 'post_id' => 123, 'created_at' => { 'type' => 'between', 'value' => ['2020-01-01', '2020-01-02'] } }
|
43
|
+
def apply_conditions(relation, conditions)
|
44
|
+
conditions.each do |key, rules|
|
45
|
+
relation = apply_condition(relation, key, rules)
|
46
|
+
end
|
47
|
+
|
48
|
+
relation
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def apply_condition(relation, key, rules)
|
54
|
+
if rules.is_a?(Hash)
|
55
|
+
value = convert_to_datatype(key, rules['value'])
|
56
|
+
|
57
|
+
if rules['type'] == 'equals'
|
58
|
+
arg = { key => value }
|
59
|
+
elsif rules['type'] == 'between'
|
60
|
+
arg = { key => value[0]..value[1] }
|
61
|
+
else
|
62
|
+
raise "Unrecognized rule type #{rules['type']}"
|
63
|
+
end
|
64
|
+
|
65
|
+
if rules['not']
|
66
|
+
return relation.where.not(arg)
|
67
|
+
else
|
68
|
+
return relation.where(arg)
|
69
|
+
end
|
70
|
+
else
|
71
|
+
value = convert_to_datatype(key, rules)
|
72
|
+
return relation.where({ key => value })
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def convert_to_datatype(key, value)
|
77
|
+
datatype = klass.type_for_attribute(key).type
|
78
|
+
if datatype == :datetime || datatype == :date
|
79
|
+
if value.is_a?(Array)
|
80
|
+
value.map { |v| v&.to_datetime }
|
81
|
+
else
|
82
|
+
value&.to_datetime
|
83
|
+
end
|
84
|
+
else
|
85
|
+
value
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
class Jason::ConsistencyChecker
|
2
|
+
attr_reader :subscription
|
3
|
+
attr_reader :inconsistent
|
4
|
+
|
5
|
+
def self.check_all(fix: false)
|
6
|
+
Jason::Subscription.all.each do |sub|
|
7
|
+
next if sub.consumer_count == 0
|
8
|
+
checker = Jason::ConsistencyChecker.new(sub)
|
9
|
+
result = checker.check
|
10
|
+
if checker.inconsistent?
|
11
|
+
pp sub.config
|
12
|
+
pp result
|
13
|
+
if fix
|
14
|
+
sub.reset!(hard: true)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.fix_all
|
21
|
+
check_all(fix: true)
|
22
|
+
end
|
23
|
+
|
24
|
+
def initialize(subscription)
|
25
|
+
@subscription = subscription
|
26
|
+
@inconsistent = false
|
27
|
+
end
|
28
|
+
|
29
|
+
def inconsistent?
|
30
|
+
inconsistent
|
31
|
+
end
|
32
|
+
|
33
|
+
# Take a subscription, get the current cached payload, and compare it to the data retrieved from the database
|
34
|
+
def check
|
35
|
+
cached_payload = subscription.get
|
36
|
+
edge_set = subscription.load_ids_for_sub_models(subscription.model, nil)
|
37
|
+
|
38
|
+
result = cached_payload.map do |model_name, data|
|
39
|
+
cached_payload_instance_ids = data[:payload].map { |row| row['id'] }
|
40
|
+
|
41
|
+
model_idx = edge_set[:model_names].index(model_name)
|
42
|
+
if model_idx.present?
|
43
|
+
edge_set_instance_ids = edge_set[:instance_ids].map { |row| row[model_idx] }
|
44
|
+
else
|
45
|
+
next
|
46
|
+
end
|
47
|
+
|
48
|
+
missing = edge_set_instance_ids - cached_payload_instance_ids
|
49
|
+
intruding = cached_payload_instance_ids - edge_set_instance_ids
|
50
|
+
|
51
|
+
if missing.present? || intruding.present?
|
52
|
+
@inconsistent = true
|
53
|
+
end
|
54
|
+
|
55
|
+
[model_name, {
|
56
|
+
'missing' => missing,
|
57
|
+
'intruding' => intruding
|
58
|
+
}]
|
59
|
+
end.compact.to_h
|
60
|
+
end
|
61
|
+
end
|
data/lib/jason/graph_helper.rb
CHANGED
@@ -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)
|
data/lib/jason/publisher.rb
CHANGED
@@ -73,13 +73,38 @@ module Jason::Publisher
|
|
73
73
|
)
|
74
74
|
end
|
75
75
|
|
76
|
-
# - An instance is created where it belongs_to an _all_ subscription
|
77
|
-
if previous_changes['id'].present?
|
78
|
-
Jason::Subscription.add_id(self.class.name.underscore, id)
|
79
|
-
end
|
80
|
-
|
81
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
|
+
|
82
105
|
jason_subscriptions.each do |sub_id|
|
106
|
+
next if applied_sub_ids.include?(sub_id)
|
107
|
+
|
83
108
|
Jason::Subscription.new(id: sub_id).update(self.class.name.underscore, id, payload, gidx)
|
84
109
|
end
|
85
110
|
end
|
@@ -94,6 +119,10 @@ module Jason::Publisher
|
|
94
119
|
Jason::Subscription.for_instance(self.class.name.underscore, id)
|
95
120
|
end
|
96
121
|
|
122
|
+
def jason_conditions
|
123
|
+
Jason::Subscription.conditions_for_model(self.class.name.underscore)
|
124
|
+
end
|
125
|
+
|
97
126
|
def jason_cached_value
|
98
127
|
JSON.parse($redis_jason.hget("jason:cache:#{self.class.name.underscore}", id) || '{}')
|
99
128
|
end
|
data/lib/jason/subscription.rb
CHANGED
@@ -60,6 +60,19 @@ class Jason::Subscription
|
|
60
60
|
subs
|
61
61
|
end
|
62
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
|
+
|
63
76
|
def self.for_model(model_name)
|
64
77
|
|
65
78
|
end
|
@@ -166,10 +179,14 @@ class Jason::Subscription
|
|
166
179
|
subscription.apply_id_changeset(id_changeset)
|
167
180
|
subscription.broadcast_id_changeset(id_changeset)
|
168
181
|
end
|
182
|
+
|
183
|
+
#########
|
184
|
+
# ---> Join the community
|
185
|
+
# Subs where changed is parent + parent is an _all_ or _condition_ subscription
|
186
|
+
|
169
187
|
end
|
170
188
|
|
171
189
|
def self.remove_ids(model_name, ids)
|
172
|
-
# td: finish this
|
173
190
|
ids.each do |instance_id|
|
174
191
|
for_instance(model_name, instance_id, false).each do |sub_id|
|
175
192
|
subscription = find_by_id(sub_id)
|
@@ -188,11 +205,6 @@ class Jason::Subscription
|
|
188
205
|
end
|
189
206
|
end
|
190
207
|
|
191
|
-
# Add ID to any _all_ subscriptions
|
192
|
-
def self.add_id(model_name, id)
|
193
|
-
|
194
|
-
end
|
195
|
-
|
196
208
|
def self.all
|
197
209
|
$redis_jason.smembers('jason:subscriptions').map { |id| Jason::Subscription.find_by_id(id) }
|
198
210
|
end
|
@@ -213,6 +225,28 @@ class Jason::Subscription
|
|
213
225
|
end
|
214
226
|
end
|
215
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
|
+
|
216
250
|
def remove_ids(model_name, ids)
|
217
251
|
$redis_jason.srem("jason:subscriptions:#{id}:ids:#{model_name}", ids)
|
218
252
|
ids.each do |instance_id|
|
@@ -252,8 +286,14 @@ class Jason::Subscription
|
|
252
286
|
if conditions.blank?
|
253
287
|
$redis_jason.sadd("jason:models:#{model_name}:all:subscriptions", id)
|
254
288
|
all_models -= [model_name]
|
255
|
-
|
289
|
+
elsif conditions.keys == ['id']
|
256
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)
|
257
297
|
end
|
258
298
|
else
|
259
299
|
raise "Must supply IDs for sub models" if ids.nil?
|
@@ -266,7 +306,7 @@ class Jason::Subscription
|
|
266
306
|
|
267
307
|
# pluck returns only a 1D array if only 1 arg passed
|
268
308
|
if all_models.size == 1
|
269
|
-
instance_ids = [
|
309
|
+
instance_ids = instance_ids.map { |id| [id] }
|
270
310
|
end
|
271
311
|
|
272
312
|
return { model_names: all_models, instance_ids: instance_ids }
|
@@ -275,12 +315,12 @@ class Jason::Subscription
|
|
275
315
|
# 'posts', [post#1, post#2,...]
|
276
316
|
def set_ids_for_sub_models(model_name = model, ids = nil, enforce: false)
|
277
317
|
edge_set = load_ids_for_sub_models(model_name, ids)
|
278
|
-
|
279
318
|
# Build the tree
|
280
319
|
id_changeset = graph_helper.apply_update({
|
281
320
|
add: [edge_set],
|
282
321
|
enforce: enforce
|
283
322
|
})
|
323
|
+
|
284
324
|
apply_id_changeset(id_changeset)
|
285
325
|
end
|
286
326
|
|
@@ -338,10 +378,6 @@ class Jason::Subscription
|
|
338
378
|
def remove_consumer(consumer_id)
|
339
379
|
$redis_jason.srem("jason:subscriptions:#{id}:consumers", consumer_id)
|
340
380
|
$redis_jason.hdel("jason:consumers", consumer_id)
|
341
|
-
|
342
|
-
if consumer_count == 0
|
343
|
-
clear_all_ids
|
344
|
-
end
|
345
381
|
end
|
346
382
|
|
347
383
|
def consumer_count
|
data/lib/jason/version.rb
CHANGED
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.
|
4
|
+
version: 0.7.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: 2021-
|
11
|
+
date: 2021-04-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -152,6 +152,8 @@ files:
|
|
152
152
|
- client/lib/JasonProvider.js
|
153
153
|
- client/lib/actionFactory.d.ts
|
154
154
|
- client/lib/actionFactory.js
|
155
|
+
- client/lib/addRelations.d.ts
|
156
|
+
- client/lib/addRelations.js
|
155
157
|
- client/lib/createActions.d.ts
|
156
158
|
- client/lib/createActions.js
|
157
159
|
- client/lib/createJasonReducers.d.ts
|
@@ -164,6 +166,8 @@ files:
|
|
164
166
|
- client/lib/createServerActionQueue.js
|
165
167
|
- client/lib/createServerActionQueue.test.d.ts
|
166
168
|
- client/lib/createServerActionQueue.test.js
|
169
|
+
- client/lib/createThenable.d.ts
|
170
|
+
- client/lib/createThenable.js
|
167
171
|
- client/lib/createTransportAdapter.d.ts
|
168
172
|
- client/lib/createTransportAdapter.js
|
169
173
|
- client/lib/deepCamelizeKeys.d.ts
|
@@ -184,6 +188,8 @@ files:
|
|
184
188
|
- client/lib/transportAdapters/pusherAdapter.js
|
185
189
|
- client/lib/useAct.d.ts
|
186
190
|
- client/lib/useAct.js
|
191
|
+
- client/lib/useDraft.d.ts
|
192
|
+
- client/lib/useDraft.js
|
187
193
|
- client/lib/useEager.d.ts
|
188
194
|
- client/lib/useEager.js
|
189
195
|
- client/lib/useJason.d.ts
|
@@ -196,6 +202,7 @@ files:
|
|
196
202
|
- client/src/JasonContext.ts
|
197
203
|
- client/src/JasonProvider.tsx
|
198
204
|
- client/src/actionFactory.ts
|
205
|
+
- client/src/addRelations.ts
|
199
206
|
- client/src/createActions.ts
|
200
207
|
- client/src/createJasonReducers.ts
|
201
208
|
- client/src/createOptDis.ts
|
@@ -206,12 +213,12 @@ files:
|
|
206
213
|
- client/src/deepCamelizeKeys.test.ts
|
207
214
|
- client/src/deepCamelizeKeys.ts
|
208
215
|
- client/src/index.ts
|
209
|
-
- client/src/makeEager.ts
|
210
216
|
- client/src/pruneIdsMiddleware.ts
|
211
217
|
- client/src/restClient.ts
|
212
218
|
- client/src/transportAdapters/actionCableAdapter.ts
|
213
219
|
- client/src/transportAdapters/pusherAdapter.ts
|
214
220
|
- client/src/useAct.ts
|
221
|
+
- client/src/useDraft.ts
|
215
222
|
- client/src/useEager.ts
|
216
223
|
- client/src/useJason.test.ts
|
217
224
|
- client/src/useJason.ts
|
@@ -224,6 +231,8 @@ files:
|
|
224
231
|
- lib/jason/api_model.rb
|
225
232
|
- lib/jason/broadcaster.rb
|
226
233
|
- lib/jason/channel.rb
|
234
|
+
- lib/jason/conditions_matcher.rb
|
235
|
+
- lib/jason/consistency_checker.rb
|
227
236
|
- lib/jason/engine.rb
|
228
237
|
- lib/jason/graph_helper.rb
|
229
238
|
- lib/jason/includes_helper.rb
|