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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +41 -0
- data/Gemfile.lock +11 -4
- data/README.md +9 -15
- data/app/controllers/jason/{api_controller.rb → jason_controller.rb} +27 -5
- data/app/controllers/jason/{api/pusher_controller.rb → pusher_controller.rb} +1 -1
- data/app/workers/jason/outbound_message_queue_worker.rb +21 -0
- data/client/lib/JasonProvider.d.ts +2 -1
- data/client/lib/JasonProvider.js +2 -2
- 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/index.d.ts +7 -1
- data/client/lib/index.js +3 -1
- 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.d.ts +2 -1
- data/client/lib/useJason.js +4 -6
- data/client/package.json +1 -1
- data/client/src/JasonProvider.tsx +2 -2
- 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/index.ts +2 -0
- 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 +3 -6
- data/config/routes.rb +6 -6
- data/jason-rails.gemspec +1 -0
- data/lib/jason.rb +6 -1
- data/lib/jason/api_model.rb +0 -4
- data/lib/jason/broadcaster.rb +2 -1
- data/lib/jason/channel.rb +0 -7
- data/lib/jason/conditions_matcher.rb +88 -0
- data/lib/jason/consistency_checker.rb +65 -0
- data/lib/jason/graph_helper.rb +4 -0
- data/lib/jason/publisher.rb +42 -38
- data/lib/jason/subscription.rb +63 -18
- data/lib/jason/version.rb +1 -1
- metadata +29 -7
- data/client/src/makeEager.ts +0 -46
- data/lib/jason/publisher_old.rb +0 -112
- data/lib/jason/subscription_old.rb +0 -171
@@ -1,31 +1,65 @@
|
|
1
1
|
// A FIFO queue with deduping of actions whose effect will be cancelled by later actions
|
2
|
-
|
2
|
+
import { v4 as uuidv4 } from 'uuid'
|
3
3
|
import _ from 'lodash'
|
4
4
|
|
5
|
+
class Deferred {
|
6
|
+
promise: Promise<any>;
|
7
|
+
resolve: any;
|
8
|
+
reject: any;
|
9
|
+
|
10
|
+
constructor() {
|
11
|
+
this.promise = new Promise((resolve, reject)=> {
|
12
|
+
this.reject = reject
|
13
|
+
this.resolve = resolve
|
14
|
+
})
|
15
|
+
}
|
16
|
+
}
|
17
|
+
|
5
18
|
export default function createServerActionQueue() {
|
6
19
|
const queue: any[] = []
|
20
|
+
const deferreds = {}
|
21
|
+
|
7
22
|
let inFlight = false
|
8
23
|
|
9
|
-
function addItem(
|
24
|
+
function addItem(action) {
|
10
25
|
// Check if there are any items ahead in the queue that this item would effectively overwrite.
|
11
26
|
// In that case we can remove them
|
12
27
|
// If this is an upsert && item ID is the same && current item attributes are a superset of the earlier item attributes
|
13
|
-
const { type, payload } =
|
28
|
+
const { type, payload } = action
|
29
|
+
const id = uuidv4()
|
30
|
+
const dfd = new Deferred()
|
31
|
+
deferreds[id] = [dfd]
|
32
|
+
|
33
|
+
const item = { id, action }
|
34
|
+
|
14
35
|
if (type.split('/')[1] !== 'upsert') {
|
15
36
|
queue.push(item)
|
16
|
-
return
|
37
|
+
return dfd.promise
|
17
38
|
}
|
18
39
|
|
19
40
|
_.remove(queue, item => {
|
20
|
-
const { type: itemType, payload: itemPayload } = item
|
41
|
+
const { type: itemType, payload: itemPayload } = item.action
|
21
42
|
if (type !== itemType) return false
|
22
43
|
if (itemPayload.id !== payload.id) return false
|
23
44
|
|
24
45
|
// Check that all keys of itemPayload are in payload.
|
46
|
+
deferreds[id].push(...deferreds[item.id])
|
25
47
|
return _.difference(_.keys(itemPayload),_.keys(payload)).length === 0
|
26
48
|
})
|
27
49
|
|
28
50
|
queue.push(item)
|
51
|
+
return dfd.promise
|
52
|
+
}
|
53
|
+
|
54
|
+
function itemProcessed(id, data?: any) {
|
55
|
+
inFlight = false
|
56
|
+
deferreds[id].forEach(dfd => dfd.resolve(data))
|
57
|
+
}
|
58
|
+
|
59
|
+
function itemFailed(id, error?: any) {
|
60
|
+
queue.length = 0
|
61
|
+
deferreds[id].forEach(dfd => dfd.reject(error))
|
62
|
+
inFlight = false
|
29
63
|
}
|
30
64
|
|
31
65
|
return {
|
@@ -40,7 +74,8 @@ export default function createServerActionQueue() {
|
|
40
74
|
}
|
41
75
|
return false
|
42
76
|
},
|
43
|
-
itemProcessed
|
77
|
+
itemProcessed,
|
78
|
+
itemFailed,
|
44
79
|
fullySynced: () => queue.length === 0 && !inFlight,
|
45
80
|
getData: () => ({ queue, inFlight })
|
46
81
|
}
|
data/client/src/index.ts
CHANGED
@@ -1,8 +1,10 @@
|
|
1
|
+
import _JasonContext from './JasonContext'
|
1
2
|
import _JasonProvider from './JasonProvider'
|
2
3
|
import _useAct from './useAct'
|
3
4
|
import _useSub from './useSub'
|
4
5
|
import _useEager from './useEager'
|
5
6
|
|
7
|
+
export const JasonContext = _JasonContext
|
6
8
|
export const JasonProvider = _JasonProvider
|
7
9
|
export const useAct = _useAct
|
8
10
|
export const useSub = _useSub
|
@@ -1,6 +1,11 @@
|
|
1
1
|
import { createConsumer } from "@rails/actioncable"
|
2
|
+
import restClient from '../restClient'
|
3
|
+
import { v4 as uuidv4 } from 'uuid'
|
4
|
+
import _ from 'lodash'
|
2
5
|
|
3
6
|
export default function actionCableAdapter(jasonConfig, handlePayload, dispatch, onConnected) {
|
7
|
+
const consumerId = uuidv4()
|
8
|
+
|
4
9
|
const consumer = createConsumer()
|
5
10
|
const subscription = (consumer.subscriptions.create({
|
6
11
|
channel: 'Jason::Channel'
|
@@ -22,16 +27,30 @@ export default function actionCableAdapter(jasonConfig, handlePayload, dispatch,
|
|
22
27
|
}
|
23
28
|
}));
|
24
29
|
|
25
|
-
function getPayload(config, options) {
|
26
|
-
subscription.send({ getPayload: config, ...options })
|
27
|
-
}
|
28
|
-
|
29
30
|
function createSubscription(config) {
|
30
31
|
subscription.send({ createSubscription: config })
|
31
32
|
}
|
32
33
|
|
33
34
|
function removeSubscription(config) {
|
34
|
-
|
35
|
+
restClient.post('/jason/api/remove_subscription', { config, consumerId })
|
36
|
+
.catch(e => console.error(e))
|
37
|
+
}
|
38
|
+
|
39
|
+
function getPayload(config, options) {
|
40
|
+
restClient.post('/jason/api/get_payload', {
|
41
|
+
config,
|
42
|
+
options
|
43
|
+
})
|
44
|
+
.then(({ data }) => {
|
45
|
+
_.map(data, (payload, modelName) => {
|
46
|
+
handlePayload(payload)
|
47
|
+
})
|
48
|
+
})
|
49
|
+
.catch(e => console.error(e))
|
50
|
+
}
|
51
|
+
|
52
|
+
function fullChannelName(channelName) {
|
53
|
+
return channelName
|
35
54
|
}
|
36
55
|
|
37
56
|
return { getPayload, createSubscription, removeSubscription }
|
@@ -1,11 +1,10 @@
|
|
1
1
|
import Pusher from 'pusher-js'
|
2
|
-
import { createConsumer } from "@rails/actioncable"
|
3
2
|
import restClient from '../restClient'
|
4
3
|
import { v4 as uuidv4 } from 'uuid'
|
5
4
|
import _ from 'lodash'
|
6
5
|
|
7
6
|
export default function pusherAdapter(jasonConfig, handlePayload, dispatch) {
|
8
|
-
|
7
|
+
const consumerId = uuidv4()
|
9
8
|
|
10
9
|
const { pusherKey, pusherRegion, pusherChannelPrefix } = jasonConfig
|
11
10
|
const pusher = new Pusher(pusherKey, {
|
@@ -0,0 +1,17 @@
|
|
1
|
+
import _ from 'lodash'
|
2
|
+
import { useSelector } from 'react-redux'
|
3
|
+
import addRelations from './addRelations'
|
4
|
+
|
5
|
+
/* Can be called as
|
6
|
+
useDraft() => draft object for making updates
|
7
|
+
useDraft('entity', id) => returns [draft, object]
|
8
|
+
useDraft('entity', id, relations) => returns [draft, objectWithEmbeddedRelations]
|
9
|
+
*/
|
10
|
+
|
11
|
+
export default function useDraft(entity, id, relations = []) {
|
12
|
+
// const entityDraft =`${entity}Draft`
|
13
|
+
// const object = { ...s[entityDraft].entities[String(id)] }
|
14
|
+
|
15
|
+
// return useSelector(s => addRelations(s, object, entity, relations, 'Draft'), _.isEqual)
|
16
|
+
}
|
17
|
+
|
data/client/src/useEager.ts
CHANGED
@@ -1,9 +1,12 @@
|
|
1
|
-
import
|
2
|
-
import {
|
1
|
+
import _ from 'lodash'
|
2
|
+
import { useSelector } from 'react-redux'
|
3
|
+
import addRelations from './addRelations'
|
3
4
|
|
4
|
-
export default function useEager(entity, id =
|
5
|
-
|
6
|
-
|
7
|
-
|
5
|
+
export default function useEager(entity: string, id = '', relations = [] as any) {
|
6
|
+
if (id) {
|
7
|
+
return useSelector(s => addRelations(s, { ...s[entity].entities[String(id)] }, entity, relations), _.isEqual)
|
8
|
+
} else {
|
9
|
+
return useSelector(s => addRelations(s, _.values(s[entity].entities), entity, relations), _.isEqual)
|
10
|
+
}
|
8
11
|
}
|
9
12
|
|
data/client/src/useJason.ts
CHANGED
@@ -9,13 +9,12 @@ import createTransportAdapater from './createTransportAdapter'
|
|
9
9
|
|
10
10
|
import { createEntityAdapter, createSlice, createReducer, configureStore } from '@reduxjs/toolkit'
|
11
11
|
|
12
|
-
import makeEager from './makeEager'
|
13
12
|
import { camelizeKeys } from 'humps'
|
14
13
|
import md5 from 'blueimp-md5'
|
15
14
|
import _ from 'lodash'
|
16
15
|
import React, { useState, useEffect } from 'react'
|
17
16
|
|
18
|
-
export default function useJason({ reducers, middleware = [], extraActions }: { reducers?: any, middleware?: any[], extraActions?: any }) {
|
17
|
+
export default function useJason({ reducers, middleware = [], enhancers = [], extraActions }: { reducers?: any, middleware?: any[], enhancers?: any[], extraActions?: any }) {
|
19
18
|
const [store, setStore] = useState(null as any)
|
20
19
|
const [value, setValue] = useState(null as any)
|
21
20
|
|
@@ -36,12 +35,11 @@ export default function useJason({ reducers, middleware = [], extraActions }: {
|
|
36
35
|
|
37
36
|
console.debug({ allReducers })
|
38
37
|
|
39
|
-
const store = configureStore({ reducer: allReducers, middleware: [...middleware, pruneIdsMiddleware(schema)] })
|
38
|
+
const store = configureStore({ reducer: allReducers, middleware: [...middleware, pruneIdsMiddleware(schema)], enhancers })
|
40
39
|
const dispatch = store.dispatch
|
41
40
|
|
42
41
|
const optDis = createOptDis(schema, dispatch, restClient, serverActionQueue)
|
43
42
|
const actions = createActions(schema, store, restClient, optDis, extraActions)
|
44
|
-
const eager = makeEager(schema)
|
45
43
|
|
46
44
|
let payloadHandlers = {}
|
47
45
|
let configs = {}
|
@@ -90,7 +88,7 @@ export default function useJason({ reducers, middleware = [], extraActions }: {
|
|
90
88
|
function removeSubscription(config) {
|
91
89
|
transportAdapter.removeSubscription(config)
|
92
90
|
const md5Hash = md5(JSON.stringify(config))
|
93
|
-
payloadHandlers[md5Hash]
|
91
|
+
payloadHandlers[md5Hash]?.tearDown() // Race condition where component mounts then unmounts quickly
|
94
92
|
delete payloadHandlers[md5Hash]
|
95
93
|
delete configs[md5Hash]
|
96
94
|
delete subOptions[md5Hash]
|
@@ -99,7 +97,6 @@ export default function useJason({ reducers, middleware = [], extraActions }: {
|
|
99
97
|
setValue({
|
100
98
|
actions: actions,
|
101
99
|
subscribe: createSubscription,
|
102
|
-
eager,
|
103
100
|
handlePayload
|
104
101
|
})
|
105
102
|
setStore(store)
|
data/config/routes.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
Jason::Engine.routes.draw do
|
2
|
-
get '/api/config', to: '
|
3
|
-
post '/api/action', to: '
|
4
|
-
post '/api/create_subscription', to: '
|
5
|
-
post '/api/remove_subscription', to: '
|
6
|
-
post '/api/get_payload', to: '
|
7
|
-
post '/api/pusher/auth', to: '
|
2
|
+
get '/api/config', to: 'jason#configuration'
|
3
|
+
post '/api/action', to: 'jason#action'
|
4
|
+
post '/api/create_subscription', to: 'jason#create_subscription'
|
5
|
+
post '/api/remove_subscription', to: 'jason#remove_subscription'
|
6
|
+
post '/api/get_payload', to: 'jason#get_payload'
|
7
|
+
post '/api/pusher/auth', to: 'pusher#auth'
|
8
8
|
end
|
data/jason-rails.gemspec
CHANGED
data/lib/jason.rb
CHANGED
@@ -12,6 +12,8 @@ require 'jason/engine'
|
|
12
12
|
require 'jason/lua_generator'
|
13
13
|
require 'jason/includes_helper'
|
14
14
|
require 'jason/graph_helper'
|
15
|
+
require 'jason/conditions_matcher'
|
16
|
+
require 'jason/consistency_checker'
|
15
17
|
|
16
18
|
module Jason
|
17
19
|
class Error < StandardError; end
|
@@ -23,12 +25,15 @@ module Jason
|
|
23
25
|
self.mattr_accessor :pusher_key
|
24
26
|
self.mattr_accessor :pusher_region
|
25
27
|
self.mattr_accessor :pusher_channel_prefix
|
26
|
-
self.mattr_accessor :
|
28
|
+
self.mattr_accessor :subscription_authorization_service
|
29
|
+
self.mattr_accessor :update_authorization_service
|
30
|
+
self.mattr_accessor :sidekiq_queue
|
27
31
|
|
28
32
|
self.schema = {}
|
29
33
|
self.transport_service = :action_cable
|
30
34
|
self.pusher_region = 'eu'
|
31
35
|
self.pusher_channel_prefix = 'jason'
|
36
|
+
self.sidekiq_queue = 'default'
|
32
37
|
|
33
38
|
def self.init
|
34
39
|
# Don't run in AR migration / generator etc.
|
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/broadcaster.rb
CHANGED
@@ -13,7 +13,8 @@ class Jason::Broadcaster
|
|
13
13
|
if Jason.transport_service == :action_cable
|
14
14
|
ActionCable.server.broadcast(channel, message)
|
15
15
|
elsif Jason.transport_service == :pusher
|
16
|
-
|
16
|
+
$redis_jason.rpush("jason:outbound_message_queue", { channel: pusher_channel_name, name: 'changed', data: message }.to_json)
|
17
|
+
Jason::OutboundMessageQueueWorker.perform_async
|
17
18
|
end
|
18
19
|
end
|
19
20
|
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,65 @@
|
|
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 wipe_all_subs
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
def initialize(subscription)
|
29
|
+
@subscription = subscription
|
30
|
+
@inconsistent = false
|
31
|
+
end
|
32
|
+
|
33
|
+
def inconsistent?
|
34
|
+
inconsistent
|
35
|
+
end
|
36
|
+
|
37
|
+
# Take a subscription, get the current cached payload, and compare it to the data retrieved from the database
|
38
|
+
def check
|
39
|
+
cached_payload = subscription.get
|
40
|
+
edge_set = subscription.load_ids_for_sub_models(subscription.model, nil)
|
41
|
+
|
42
|
+
result = cached_payload.map do |model_name, data|
|
43
|
+
cached_payload_instance_ids = data[:payload].map { |row| row['id'] }
|
44
|
+
|
45
|
+
model_idx = edge_set[:model_names].index(model_name)
|
46
|
+
if model_idx.present?
|
47
|
+
edge_set_instance_ids = edge_set[:instance_ids].map { |row| row[model_idx] }
|
48
|
+
else
|
49
|
+
next
|
50
|
+
end
|
51
|
+
|
52
|
+
missing = edge_set_instance_ids - cached_payload_instance_ids
|
53
|
+
intruding = cached_payload_instance_ids - edge_set_instance_ids
|
54
|
+
|
55
|
+
if missing.present? || intruding.present?
|
56
|
+
@inconsistent = true
|
57
|
+
end
|
58
|
+
|
59
|
+
[model_name, {
|
60
|
+
'missing' => missing,
|
61
|
+
'intruding' => intruding
|
62
|
+
}]
|
63
|
+
end.compact.to_h
|
64
|
+
end
|
65
|
+
end
|