jason-rails 0.6.8 → 0.7.5
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 +34 -0
- data/Gemfile.lock +5 -3
- data/README.md +20 -14
- data/app/controllers/jason/jason_controller.rb +26 -4
- data/app/workers/jason/outbound_message_queue_worker.rb +1 -1
- data/client/lib/JasonProvider.d.ts +3 -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/createTransportAdapter.d.ts +1 -1
- data/client/lib/createTransportAdapter.js +2 -2
- data/client/lib/index.d.ts +8 -1
- data/client/lib/index.js +3 -1
- data/client/lib/transportAdapters/actionCableAdapter.d.ts +1 -1
- data/client/lib/transportAdapters/actionCableAdapter.js +27 -6
- 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 +3 -1
- data/client/lib/useJason.js +4 -7
- 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/createTransportAdapter.ts +2 -2
- data/client/src/index.ts +2 -0
- data/client/src/transportAdapters/actionCableAdapter.ts +28 -7
- 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 +10 -7
- data/lib/jason.rb +9 -2
- 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 +65 -0
- data/lib/jason/graph_helper.rb +4 -0
- data/lib/jason/publisher.rb +36 -36
- data/lib/jason/subscription.rb +51 -15
- data/lib/jason/version.rb +1 -1
- metadata +12 -5
- 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
|
}
|
@@ -1,10 +1,10 @@
|
|
1
1
|
import actionCableAdapter from './transportAdapters/actionCableAdapter'
|
2
2
|
import pusherAdapter from './transportAdapters/pusherAdapter'
|
3
3
|
|
4
|
-
export default function createTransportAdapter(jasonConfig, handlePayload, dispatch, onConnect) {
|
4
|
+
export default function createTransportAdapter(jasonConfig, handlePayload, dispatch, onConnect, transportOptions) {
|
5
5
|
const { transportService } = jasonConfig
|
6
6
|
if (transportService === 'action_cable') {
|
7
|
-
return actionCableAdapter(jasonConfig, handlePayload, dispatch, onConnect)
|
7
|
+
return actionCableAdapter(jasonConfig, handlePayload, dispatch, onConnect, transportOptions)
|
8
8
|
} else if (transportService === 'pusher') {
|
9
9
|
return pusherAdapter(jasonConfig, handlePayload, dispatch)
|
10
10
|
} else {
|
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,7 +1,14 @@
|
|
1
1
|
import { createConsumer } from "@rails/actioncable"
|
2
|
+
import restClient from '../restClient'
|
3
|
+
import { v4 as uuidv4 } from 'uuid'
|
4
|
+
import _ from 'lodash'
|
5
|
+
|
6
|
+
export default function actionCableAdapter(jasonConfig, handlePayload, dispatch, onConnected, transportOptions) {
|
7
|
+
const consumerId = uuidv4()
|
8
|
+
|
9
|
+
const { cableUrl } = transportOptions
|
10
|
+
const consumer = cableUrl ? createConsumer(cableUrl) : createConsumer()
|
2
11
|
|
3
|
-
export default function actionCableAdapter(jasonConfig, handlePayload, dispatch, onConnected) {
|
4
|
-
const consumer = createConsumer()
|
5
12
|
const subscription = (consumer.subscriptions.create({
|
6
13
|
channel: 'Jason::Channel'
|
7
14
|
}, {
|
@@ -22,16 +29,30 @@ export default function actionCableAdapter(jasonConfig, handlePayload, dispatch,
|
|
22
29
|
}
|
23
30
|
}));
|
24
31
|
|
25
|
-
function getPayload(config, options) {
|
26
|
-
subscription.send({ getPayload: config, ...options })
|
27
|
-
}
|
28
|
-
|
29
32
|
function createSubscription(config) {
|
30
33
|
subscription.send({ createSubscription: config })
|
31
34
|
}
|
32
35
|
|
33
36
|
function removeSubscription(config) {
|
34
|
-
|
37
|
+
restClient.post('/jason/api/remove_subscription', { config, consumerId })
|
38
|
+
.catch(e => console.error(e))
|
39
|
+
}
|
40
|
+
|
41
|
+
function getPayload(config, options) {
|
42
|
+
restClient.post('/jason/api/get_payload', {
|
43
|
+
config,
|
44
|
+
options
|
45
|
+
})
|
46
|
+
.then(({ data }) => {
|
47
|
+
_.map(data, (payload, modelName) => {
|
48
|
+
handlePayload(payload)
|
49
|
+
})
|
50
|
+
})
|
51
|
+
.catch(e => console.error(e))
|
52
|
+
}
|
53
|
+
|
54
|
+
function fullChannelName(channelName) {
|
55
|
+
return channelName
|
35
56
|
}
|
36
57
|
|
37
58
|
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 = [], transportOptions = {}, extraActions }: { reducers?: any, middleware?: any[], enhancers?: any[], extraActions?: any, transportOptions?: 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 = {}
|
@@ -50,7 +48,7 @@ export default function useJason({ reducers, middleware = [], extraActions }: {
|
|
50
48
|
function handlePayload(payload) {
|
51
49
|
const { md5Hash } = payload
|
52
50
|
|
53
|
-
const { handlePayload } = payloadHandlers[md5Hash]
|
51
|
+
const { handlePayload } = payloadHandlers[md5Hash] || {}
|
54
52
|
if (handlePayload) {
|
55
53
|
handlePayload(payload)
|
56
54
|
} else {
|
@@ -58,7 +56,13 @@ export default function useJason({ reducers, middleware = [], extraActions }: {
|
|
58
56
|
}
|
59
57
|
}
|
60
58
|
|
61
|
-
const transportAdapter = createTransportAdapater(
|
59
|
+
const transportAdapter = createTransportAdapater(
|
60
|
+
jasonConfig,
|
61
|
+
handlePayload,
|
62
|
+
dispatch,
|
63
|
+
() => _.keys(configs).forEach(md5Hash => createSubscription(configs[md5Hash], subOptions[md5Hash])),
|
64
|
+
transportOptions
|
65
|
+
)
|
62
66
|
|
63
67
|
function createSubscription(config, options = {}) {
|
64
68
|
// We need the hash to be consistent in Ruby / Javascript
|
@@ -99,7 +103,6 @@ export default function useJason({ reducers, middleware = [], extraActions }: {
|
|
99
103
|
setValue({
|
100
104
|
actions: actions,
|
101
105
|
subscribe: createSubscription,
|
102
|
-
eager,
|
103
106
|
handlePayload
|
104
107
|
})
|
105
108
|
setStore(store)
|
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,7 +25,8 @@ 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
|
27
30
|
self.mattr_accessor :sidekiq_queue
|
28
31
|
|
29
32
|
self.schema = {}
|
@@ -48,7 +51,11 @@ module Jason
|
|
48
51
|
puts "Old config was #{previous_schema[model]}"
|
49
52
|
puts "New config is #{config}"
|
50
53
|
puts "Rebuilding cache for #{model}"
|
51
|
-
|
54
|
+
|
55
|
+
# This is necessary to ensure all Rails methods have been added to model before we attempt to cache.
|
56
|
+
Rails.configuration.after_initialize do
|
57
|
+
model.classify.constantize.cache_all
|
58
|
+
end
|
52
59
|
puts "Done"
|
53
60
|
end
|
54
61
|
end
|
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,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
|