jason-rails 0.3.0 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +4 -1
- data/.ruby-version +1 -0
- data/Gemfile.lock +184 -0
- data/README.md +118 -10
- data/app/controllers/jason/api/pusher_controller.rb +15 -0
- data/app/controllers/jason/api_controller.rb +78 -0
- data/client/babel.config.js +13 -0
- data/client/lib/JasonContext.d.ts +6 -1
- data/client/lib/JasonProvider.d.ts +6 -5
- data/client/lib/JasonProvider.js +5 -97
- data/client/lib/actionFactory.js +1 -1
- data/client/lib/createActions.d.ts +1 -1
- data/client/lib/createActions.js +2 -27
- data/client/lib/createJasonReducers.js +49 -3
- data/client/lib/createOptDis.d.ts +1 -0
- data/client/lib/createOptDis.js +43 -0
- data/client/lib/createPayloadHandler.d.ts +9 -1
- data/client/lib/createPayloadHandler.js +52 -43
- data/client/lib/createServerActionQueue.d.ts +10 -0
- data/client/lib/createServerActionQueue.js +48 -0
- data/client/lib/createServerActionQueue.test.d.ts +1 -0
- data/client/lib/createServerActionQueue.test.js +37 -0
- data/client/lib/createTransportAdapter.d.ts +5 -0
- data/client/lib/createTransportAdapter.js +20 -0
- data/client/lib/deepCamelizeKeys.d.ts +1 -0
- data/client/lib/deepCamelizeKeys.js +23 -0
- data/client/lib/deepCamelizeKeys.test.d.ts +1 -0
- data/client/lib/deepCamelizeKeys.test.js +106 -0
- data/client/lib/index.d.ts +6 -5
- data/client/lib/pruneIdsMiddleware.d.ts +2 -0
- data/client/lib/pruneIdsMiddleware.js +24 -0
- data/client/lib/restClient.d.ts +2 -0
- data/client/lib/restClient.js +17 -0
- data/client/lib/transportAdapters/actionCableAdapter.d.ts +5 -0
- data/client/lib/transportAdapters/actionCableAdapter.js +35 -0
- data/client/lib/transportAdapters/pusherAdapter.d.ts +5 -0
- data/client/lib/transportAdapters/pusherAdapter.js +68 -0
- data/client/lib/useJason.d.ts +5 -0
- data/client/lib/useJason.js +94 -0
- data/client/lib/useJason.test.d.ts +1 -0
- data/client/lib/useJason.test.js +85 -0
- data/client/lib/useSub.d.ts +1 -1
- data/client/lib/useSub.js +6 -3
- data/client/package.json +19 -4
- data/client/src/JasonProvider.tsx +6 -96
- data/client/src/actionFactory.ts +1 -1
- data/client/src/createActions.ts +2 -33
- data/client/src/createJasonReducers.ts +57 -3
- data/client/src/createOptDis.ts +45 -0
- data/client/src/createPayloadHandler.ts +58 -47
- data/client/src/createServerActionQueue.test.ts +42 -0
- data/client/src/createServerActionQueue.ts +47 -0
- data/client/src/createTransportAdapter.ts +13 -0
- data/client/src/deepCamelizeKeys.test.ts +113 -0
- data/client/src/deepCamelizeKeys.ts +17 -0
- data/client/src/pruneIdsMiddleware.ts +24 -0
- data/client/src/restClient.ts +14 -0
- data/client/src/transportAdapters/actionCableAdapter.ts +38 -0
- data/client/src/transportAdapters/pusherAdapter.ts +72 -0
- data/client/src/useJason.test.ts +87 -0
- data/client/src/useJason.ts +110 -0
- data/client/src/useSub.ts +6 -3
- data/client/yarn.lock +4607 -81
- data/config/routes.rb +8 -0
- data/jason-rails.gemspec +9 -0
- data/lib/jason.rb +40 -1
- data/lib/jason/api_model.rb +15 -9
- data/lib/jason/broadcaster.rb +19 -0
- data/lib/jason/channel.rb +50 -21
- data/lib/jason/engine.rb +5 -0
- data/lib/jason/graph_helper.rb +165 -0
- data/lib/jason/includes_helper.rb +108 -0
- data/lib/jason/lua_generator.rb +71 -0
- data/lib/jason/publisher.rb +103 -30
- data/lib/jason/publisher_old.rb +112 -0
- data/lib/jason/subscription.rb +352 -101
- data/lib/jason/subscription_old.rb +171 -0
- data/lib/jason/version.rb +1 -1
- metadata +151 -4
@@ -1,7 +1,8 @@
|
|
1
|
+
import React from 'react';
|
1
2
|
declare const JasonProvider: ({ reducers, middleware, extraActions, children }: {
|
2
|
-
reducers
|
3
|
-
middleware
|
4
|
-
extraActions
|
5
|
-
children
|
6
|
-
}) =>
|
3
|
+
reducers?: any;
|
4
|
+
middleware?: any;
|
5
|
+
extraActions?: any;
|
6
|
+
children?: React.FC<{}> | undefined;
|
7
|
+
}) => JSX.Element;
|
7
8
|
export default JasonProvider;
|
data/client/lib/JasonProvider.js
CHANGED
@@ -1,107 +1,15 @@
|
|
1
1
|
"use strict";
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
3
|
-
if (k2 === undefined) k2 = k;
|
4
|
-
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
|
5
|
-
}) : (function(o, m, k, k2) {
|
6
|
-
if (k2 === undefined) k2 = k;
|
7
|
-
o[k2] = m[k];
|
8
|
-
}));
|
9
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
10
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
11
|
-
}) : function(o, v) {
|
12
|
-
o["default"] = v;
|
13
|
-
});
|
14
|
-
var __importStar = (this && this.__importStar) || function (mod) {
|
15
|
-
if (mod && mod.__esModule) return mod;
|
16
|
-
var result = {};
|
17
|
-
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
18
|
-
__setModuleDefault(result, mod);
|
19
|
-
return result;
|
20
|
-
};
|
21
2
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
22
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
23
4
|
};
|
24
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
25
|
-
const
|
26
|
-
const
|
27
|
-
const JasonContext_1 = __importDefault(require("./JasonContext"));
|
28
|
-
const axios_1 = __importDefault(require("axios"));
|
29
|
-
const axios_case_converter_1 = __importDefault(require("axios-case-converter"));
|
6
|
+
const react_1 = __importDefault(require("react"));
|
7
|
+
const useJason_1 = __importDefault(require("./useJason"));
|
30
8
|
const react_redux_1 = require("react-redux");
|
31
|
-
const
|
32
|
-
const createJasonReducers_1 = __importDefault(require("./createJasonReducers"));
|
33
|
-
const createPayloadHandler_1 = __importDefault(require("./createPayloadHandler"));
|
34
|
-
const makeEager_1 = __importDefault(require("./makeEager"));
|
35
|
-
const humps_1 = require("humps");
|
36
|
-
const blueimp_md5_1 = __importDefault(require("blueimp-md5"));
|
37
|
-
const lodash_1 = __importDefault(require("lodash"));
|
38
|
-
const react_1 = __importStar(require("react"));
|
9
|
+
const JasonContext_1 = __importDefault(require("./JasonContext"));
|
39
10
|
const JasonProvider = ({ reducers, middleware, extraActions, children }) => {
|
40
|
-
const [store,
|
41
|
-
|
42
|
-
const [connected, setConnected] = react_1.useState(false);
|
43
|
-
const csrfToken = document.querySelector("meta[name=csrf-token]").content;
|
44
|
-
axios_1.default.defaults.headers.common['X-CSRF-Token'] = csrfToken;
|
45
|
-
const restClient = axios_case_converter_1.default(axios_1.default.create());
|
46
|
-
react_1.useEffect(() => {
|
47
|
-
restClient.get('/jason/api/schema')
|
48
|
-
.then(({ data: snakey_schema }) => {
|
49
|
-
const schema = humps_1.camelizeKeys(snakey_schema);
|
50
|
-
const consumer = actioncable_1.createConsumer();
|
51
|
-
const allReducers = Object.assign(Object.assign({}, reducers), createJasonReducers_1.default(schema));
|
52
|
-
console.log({ schema, allReducers });
|
53
|
-
const store = toolkit_1.configureStore({ reducer: allReducers, middleware });
|
54
|
-
let payloadHandlers = {};
|
55
|
-
function handlePayload(payload) {
|
56
|
-
const { model, md5Hash } = payload;
|
57
|
-
console.log({ md5Hash, fn: `${model}:${md5Hash}`, payloadHandlers, model: lodash_1.default.camelCase(model), payload });
|
58
|
-
const handler = payloadHandlers[`${lodash_1.default.camelCase(model)}:${md5Hash}`];
|
59
|
-
if (handler) {
|
60
|
-
handler(Object.assign(Object.assign({}, payload), { model: lodash_1.default.camelCase(model) }));
|
61
|
-
}
|
62
|
-
}
|
63
|
-
const subscription = (consumer.subscriptions.create({
|
64
|
-
channel: 'Jason::Channel'
|
65
|
-
}, {
|
66
|
-
connected: () => {
|
67
|
-
setConnected(true);
|
68
|
-
},
|
69
|
-
received: payload => {
|
70
|
-
console.log("Payload received", payload);
|
71
|
-
handlePayload(payload);
|
72
|
-
},
|
73
|
-
disconnected: () => console.warn('Disconnected from ActionCable')
|
74
|
-
}));
|
75
|
-
console.log('sending message');
|
76
|
-
subscription.send({ message: 'test' });
|
77
|
-
function createSubscription(config) {
|
78
|
-
const md5Hash = blueimp_md5_1.default(JSON.stringify(config));
|
79
|
-
console.log('Subscribe with', config, md5Hash);
|
80
|
-
lodash_1.default.map(config, (v, model) => {
|
81
|
-
payloadHandlers[`${model}:${md5Hash}`] = createPayloadHandler_1.default(store.dispatch, subscription, model, schema[model]);
|
82
|
-
});
|
83
|
-
subscription.send({ createSubscription: config });
|
84
|
-
return () => removeSubscription(config);
|
85
|
-
}
|
86
|
-
function removeSubscription(config) {
|
87
|
-
subscription.send({ removeSubscription: config });
|
88
|
-
const md5Hash = blueimp_md5_1.default(JSON.stringify(config));
|
89
|
-
lodash_1.default.map(config, (v, model) => {
|
90
|
-
delete payloadHandlers[`${model}:${md5Hash}`];
|
91
|
-
});
|
92
|
-
}
|
93
|
-
const actions = createActions_1.default(schema, store, restClient, extraActions);
|
94
|
-
const eager = makeEager_1.default(schema);
|
95
|
-
console.log({ actions });
|
96
|
-
setValue({
|
97
|
-
actions: actions,
|
98
|
-
subscribe: (config) => createSubscription(config),
|
99
|
-
eager
|
100
|
-
});
|
101
|
-
setStore(store);
|
102
|
-
});
|
103
|
-
}, []);
|
104
|
-
if (!(store && value && connected))
|
11
|
+
const [store, value] = useJason_1.default({ reducers, middleware, extraActions });
|
12
|
+
if (!(store && value))
|
105
13
|
return react_1.default.createElement("div", null); // Wait for async fetch of schema to complete
|
106
14
|
return react_1.default.createElement(react_redux_1.Provider, { store: store },
|
107
15
|
react_1.default.createElement(JasonContext_1.default.Provider, { value: value }, children));
|
data/client/lib/actionFactory.js
CHANGED
@@ -23,7 +23,7 @@ exports.default = (dis, store, entity, { extraActions = {}, hasPriority = false
|
|
23
23
|
function remove(id) {
|
24
24
|
return dis({ type: `${pluralize_1.default(entity)}/remove`, payload: id });
|
25
25
|
}
|
26
|
-
const extraActionsResolved = lodash_1.default.mapValues(extraActions, v => v(dis, store, entity));
|
26
|
+
const extraActionsResolved = extraActions ? lodash_1.default.mapValues(extraActions, v => v(dis, store, entity)) : {};
|
27
27
|
if (hasPriority) {
|
28
28
|
return Object.assign({ add, upsert, setAll, remove, movePriority }, extraActionsResolved);
|
29
29
|
}
|
@@ -1,2 +1,2 @@
|
|
1
|
-
declare function createActions(schema: any, store: any, restClient: any, extraActions: any): any;
|
1
|
+
declare function createActions(schema: any, store: any, restClient: any, optDis: any, extraActions: any): any;
|
2
2
|
export default createActions;
|
data/client/lib/createActions.js
CHANGED
@@ -6,32 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
const actionFactory_1 = __importDefault(require("./actionFactory"));
|
7
7
|
const pluralize_1 = __importDefault(require("pluralize"));
|
8
8
|
const lodash_1 = __importDefault(require("lodash"));
|
9
|
-
|
10
|
-
function enrich(type, payload) {
|
11
|
-
if (type.split('/')[1] === 'upsert' && !(type.split('/')[0] === 'session')) {
|
12
|
-
if (!payload.id) {
|
13
|
-
return Object.assign(Object.assign({}, payload), { id: uuid_1.v4() });
|
14
|
-
}
|
15
|
-
}
|
16
|
-
return payload;
|
17
|
-
}
|
18
|
-
function makeOptDis(schema, dispatch, restClient) {
|
19
|
-
const plurals = lodash_1.default.keys(schema).map(k => pluralize_1.default(k));
|
20
|
-
return function (action) {
|
21
|
-
const { type, payload } = action;
|
22
|
-
const data = enrich(type, payload);
|
23
|
-
dispatch(action);
|
24
|
-
if (plurals.indexOf(type.split('/')[0]) > -1) {
|
25
|
-
return restClient.post('/jason/api/action', { type, payload: data })
|
26
|
-
.catch(e => {
|
27
|
-
dispatch({ type: 'upsertLocalUi', data: { error: JSON.stringify(e) } });
|
28
|
-
});
|
29
|
-
}
|
30
|
-
};
|
31
|
-
}
|
32
|
-
function createActions(schema, store, restClient, extraActions) {
|
33
|
-
const dis = store.dispatch;
|
34
|
-
const optDis = makeOptDis(schema, dis, restClient);
|
9
|
+
function createActions(schema, store, restClient, optDis, extraActions) {
|
35
10
|
const actions = lodash_1.default.fromPairs(lodash_1.default.map(schema, (config, model) => {
|
36
11
|
if (config.priorityScope) {
|
37
12
|
return [pluralize_1.default(model), actionFactory_1.default(optDis, store, model, { hasPriority: true })];
|
@@ -40,7 +15,7 @@ function createActions(schema, store, restClient, extraActions) {
|
|
40
15
|
return [pluralize_1.default(model), actionFactory_1.default(optDis, store, model)];
|
41
16
|
}
|
42
17
|
}));
|
43
|
-
const extraActionsResolved = extraActions(optDis, store, restClient);
|
18
|
+
const extraActionsResolved = extraActions ? extraActions(optDis, store, restClient, actions) : {};
|
44
19
|
return lodash_1.default.merge(actions, extraActionsResolved);
|
45
20
|
}
|
46
21
|
exports.default = createActions;
|
@@ -6,8 +6,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
const toolkit_1 = require("@reduxjs/toolkit");
|
7
7
|
const pluralize_1 = __importDefault(require("pluralize"));
|
8
8
|
const lodash_1 = __importDefault(require("lodash"));
|
9
|
-
function generateSlices(
|
10
|
-
const sliceNames =
|
9
|
+
function generateSlices(models) {
|
10
|
+
const sliceNames = models.map(k => pluralize_1.default(k));
|
11
11
|
const adapter = toolkit_1.createEntityAdapter();
|
12
12
|
return lodash_1.default.fromPairs(lodash_1.default.map(sliceNames, name => {
|
13
13
|
return [name, toolkit_1.createSlice({
|
@@ -19,6 +19,7 @@ function generateSlices(schema) {
|
|
19
19
|
add: adapter.addOne,
|
20
20
|
setAll: adapter.setAll,
|
21
21
|
remove: adapter.removeOne,
|
22
|
+
removeMany: adapter.removeMany,
|
22
23
|
movePriority: (s, { payload: { id, priority, parentFilter } }) => {
|
23
24
|
// Get IDs and insert our item at the new index
|
24
25
|
var affectedIds = lodash_1.default.orderBy(lodash_1.default.filter(lodash_1.default.values(s.entities), parentFilter).filter(e => e.id !== id), 'priority').map(e => e.id);
|
@@ -30,7 +31,52 @@ function generateSlices(schema) {
|
|
30
31
|
}).reducer];
|
31
32
|
}));
|
32
33
|
}
|
34
|
+
function generateJasonSlices(models) {
|
35
|
+
const initialState = lodash_1.default.fromPairs(lodash_1.default.map(models, (model_name) => {
|
36
|
+
return [model_name, {}];
|
37
|
+
}));
|
38
|
+
const modelSliceReducer = toolkit_1.createSlice({
|
39
|
+
name: 'jasonModels',
|
40
|
+
initialState,
|
41
|
+
reducers: {
|
42
|
+
setSubscriptionIds(s, a) {
|
43
|
+
const { payload } = a;
|
44
|
+
const { subscriptionId, model, ids } = payload;
|
45
|
+
console.log({ initialState });
|
46
|
+
s[model][subscriptionId] = ids;
|
47
|
+
},
|
48
|
+
addSubscriptionId(s, a) {
|
49
|
+
const { payload } = a;
|
50
|
+
const { subscriptionId, model, id } = payload;
|
51
|
+
s[model][subscriptionId] = lodash_1.default.union(s[model][subscriptionId] || [], [id]);
|
52
|
+
},
|
53
|
+
removeSubscriptionId(s, a) {
|
54
|
+
const { payload } = a;
|
55
|
+
const { subscriptionId, model, id } = payload;
|
56
|
+
s[model][subscriptionId] = lodash_1.default.remove(s[model][subscriptionId] || [], id);
|
57
|
+
},
|
58
|
+
removeSubscription(s, a) {
|
59
|
+
const { payload: { subscriptionId } } = a;
|
60
|
+
lodash_1.default.map(models, model => {
|
61
|
+
delete s[model][subscriptionId];
|
62
|
+
});
|
63
|
+
}
|
64
|
+
}
|
65
|
+
}).reducer;
|
66
|
+
const jasonSliceReducer = toolkit_1.createSlice({
|
67
|
+
name: 'jason',
|
68
|
+
initialState: {
|
69
|
+
connected: false,
|
70
|
+
queueSize: 0
|
71
|
+
},
|
72
|
+
reducers: {
|
73
|
+
upsert: (s, a) => (Object.assign(Object.assign({}, s), a.payload))
|
74
|
+
}
|
75
|
+
}).reducer;
|
76
|
+
return { jason: jasonSliceReducer, jasonModels: modelSliceReducer };
|
77
|
+
}
|
33
78
|
function createJasonReducers(schema) {
|
34
|
-
|
79
|
+
const models = lodash_1.default.keys(schema);
|
80
|
+
return Object.assign(Object.assign({}, generateSlices(models)), generateJasonSlices(models));
|
35
81
|
}
|
36
82
|
exports.default = createJasonReducers;
|
@@ -0,0 +1 @@
|
|
1
|
+
export default function createOptDis(schema: any, dispatch: any, restClient: any, serverActionQueue: any): (action: any) => void;
|
@@ -0,0 +1,43 @@
|
|
1
|
+
"use strict";
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
4
|
+
};
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
6
|
+
const lodash_1 = __importDefault(require("lodash"));
|
7
|
+
const pluralize_1 = __importDefault(require("pluralize"));
|
8
|
+
const uuid_1 = require("uuid");
|
9
|
+
function enrich(type, payload) {
|
10
|
+
if (type.split('/')[1] === 'upsert' && !(type.split('/')[0] === 'session')) {
|
11
|
+
if (!payload.id) {
|
12
|
+
return Object.assign(Object.assign({}, payload), { id: uuid_1.v4() });
|
13
|
+
}
|
14
|
+
}
|
15
|
+
return payload;
|
16
|
+
}
|
17
|
+
function createOptDis(schema, dispatch, restClient, serverActionQueue) {
|
18
|
+
const plurals = lodash_1.default.keys(schema).map(k => pluralize_1.default(k));
|
19
|
+
function enqueueServerAction(action) {
|
20
|
+
serverActionQueue.addItem(action);
|
21
|
+
}
|
22
|
+
function dispatchServerAction() {
|
23
|
+
const action = serverActionQueue.getItem();
|
24
|
+
if (!action)
|
25
|
+
return;
|
26
|
+
restClient.post('/jason/api/action', action)
|
27
|
+
.then(serverActionQueue.itemProcessed)
|
28
|
+
.catch(e => {
|
29
|
+
dispatch({ type: 'upsertLocalUi', data: { error: JSON.stringify(e) } });
|
30
|
+
serverActionQueue.itemProcessed();
|
31
|
+
});
|
32
|
+
}
|
33
|
+
setInterval(dispatchServerAction, 10);
|
34
|
+
return function (action) {
|
35
|
+
const { type, payload } = action;
|
36
|
+
const data = enrich(type, payload);
|
37
|
+
dispatch({ type, payload: data });
|
38
|
+
if (plurals.indexOf(type.split('/')[0]) > -1) {
|
39
|
+
enqueueServerAction({ type, payload: data });
|
40
|
+
}
|
41
|
+
};
|
42
|
+
}
|
43
|
+
exports.default = createOptDis;
|
@@ -1 +1,9 @@
|
|
1
|
-
export default function createPayloadHandler(dispatch
|
1
|
+
export default function createPayloadHandler({ dispatch, serverActionQueue, transportAdapter, config }: {
|
2
|
+
dispatch: any;
|
3
|
+
serverActionQueue: any;
|
4
|
+
transportAdapter: any;
|
5
|
+
config: any;
|
6
|
+
}): {
|
7
|
+
handlePayload: (data: any) => void;
|
8
|
+
tearDown: () => void;
|
9
|
+
};
|
@@ -3,85 +3,94 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
4
4
|
};
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
6
|
-
const
|
7
|
-
const humps_1 = require("humps");
|
6
|
+
const deepCamelizeKeys_1 = __importDefault(require("./deepCamelizeKeys"));
|
8
7
|
const pluralize_1 = __importDefault(require("pluralize"));
|
9
8
|
const lodash_1 = __importDefault(require("lodash"));
|
9
|
+
const uuid_1 = require("uuid");
|
10
10
|
function diffSeconds(dt2, dt1) {
|
11
11
|
var diff = (dt2.getTime() - dt1.getTime()) / 1000;
|
12
12
|
return Math.abs(Math.round(diff));
|
13
13
|
}
|
14
|
-
function createPayloadHandler(dispatch,
|
15
|
-
|
16
|
-
let
|
17
|
-
let idx = 0;
|
14
|
+
function createPayloadHandler({ dispatch, serverActionQueue, transportAdapter, config }) {
|
15
|
+
const subscriptionId = uuid_1.v4();
|
16
|
+
let idx = {};
|
18
17
|
let patchQueue = {};
|
19
18
|
let lastCheckAt = new Date();
|
20
19
|
let updateDeadline = null;
|
21
20
|
let checkInterval;
|
22
21
|
function getPayload() {
|
23
|
-
|
24
|
-
subscription.send({ getPayload: { model, config } });
|
22
|
+
setTimeout(() => transportAdapter.getPayload(config), 1000);
|
25
23
|
}
|
26
|
-
|
27
|
-
|
28
|
-
const includeModels = (config.includeModels || []).map(m => lodash_1.default.camelCase(m));
|
29
|
-
console.log("Dispatching", { payload, includeModels });
|
30
|
-
includeModels.forEach(m => {
|
31
|
-
const subPayload = lodash_1.default.flatten(lodash_1.default.compact(humps_1.camelizeKeys(payload).map(instance => instance[m])));
|
32
|
-
console.log({ type: `${pluralize_1.default(m)}/upsertMany`, payload: subPayload });
|
33
|
-
dispatch({ type: `${pluralize_1.default(m)}/upsertMany`, payload: subPayload });
|
34
|
-
});
|
35
|
-
dispatch({ type: `${pluralize_1.default(model)}/upsertMany`, payload: humps_1.camelizeKeys(payload) });
|
24
|
+
function camelizeKeys(item) {
|
25
|
+
return deepCamelizeKeys_1.default(item, key => uuid_1.validate(key));
|
36
26
|
}
|
37
|
-
|
38
|
-
|
27
|
+
const tGetPayload = lodash_1.default.throttle(getPayload, 10000);
|
28
|
+
function processQueue(model) {
|
29
|
+
console.debug("processQueue", model, idx[model], patchQueue[model]);
|
39
30
|
lastCheckAt = new Date();
|
40
|
-
if (patchQueue[idx]) {
|
41
|
-
|
42
|
-
|
43
|
-
|
31
|
+
if (patchQueue[model][idx[model]]) {
|
32
|
+
if (!serverActionQueue.fullySynced()) {
|
33
|
+
console.debug(serverActionQueue.getData());
|
34
|
+
setTimeout(() => processQueue(model), 100);
|
35
|
+
return;
|
36
|
+
}
|
37
|
+
const { payload, destroy, id, type } = patchQueue[model][idx[model]];
|
38
|
+
if (type === 'payload') {
|
39
|
+
dispatch({ type: `${pluralize_1.default(model)}/upsertMany`, payload });
|
40
|
+
const ids = payload.map(instance => instance.id);
|
41
|
+
dispatch({ type: `jasonModels/setSubscriptionIds`, payload: { model, subscriptionId, ids } });
|
44
42
|
}
|
45
|
-
|
46
|
-
|
43
|
+
else if (destroy) {
|
44
|
+
// Middleware will determine if this model should be removed if it isn't in any other subscriptions
|
45
|
+
dispatch({ type: `jasonModels/removeSubscriptionId`, payload: { model, subscriptionId, id } });
|
46
|
+
}
|
47
|
+
else {
|
48
|
+
dispatch({ type: `${pluralize_1.default(model)}/upsert`, payload });
|
49
|
+
dispatch({ type: `jasonModels/addSubscriptionId`, payload: { model, subscriptionId, id } });
|
50
|
+
}
|
51
|
+
delete patchQueue[model][idx[model]];
|
52
|
+
idx[model]++;
|
47
53
|
updateDeadline = null;
|
48
|
-
processQueue();
|
54
|
+
processQueue(model);
|
49
55
|
// If there are updates in the queue that are ahead of the index, some have arrived out of order
|
50
56
|
// Set a deadline for new updates before it declares the update missing and refetches.
|
51
57
|
}
|
52
|
-
else if (lodash_1.default.keys(patchQueue).length > 0 && !updateDeadline) {
|
58
|
+
else if (lodash_1.default.keys(patchQueue[model]).length > 0 && !updateDeadline) {
|
53
59
|
var t = new Date();
|
54
60
|
t.setSeconds(t.getSeconds() + 3);
|
55
61
|
updateDeadline = t;
|
56
|
-
setTimeout(processQueue, 3100);
|
62
|
+
setTimeout(() => processQueue(model), 3100);
|
57
63
|
// If more than 10 updates in queue, or deadline has passed, restart
|
58
64
|
}
|
59
|
-
else if (lodash_1.default.keys(patchQueue).length > 10 || (updateDeadline && diffSeconds(updateDeadline, new Date()) < 0)) {
|
65
|
+
else if (lodash_1.default.keys(patchQueue[model]).length > 10 || (updateDeadline && diffSeconds(updateDeadline, new Date()) < 0)) {
|
60
66
|
tGetPayload();
|
61
67
|
updateDeadline = null;
|
62
68
|
}
|
63
69
|
}
|
64
70
|
function handlePayload(data) {
|
65
|
-
const {
|
66
|
-
|
71
|
+
const { idx: newIdx, model: snake_model, type } = data;
|
72
|
+
const model = lodash_1.default.camelCase(snake_model);
|
73
|
+
idx[model] = idx[model] || 0;
|
74
|
+
patchQueue[model] = patchQueue[model] || {};
|
67
75
|
if (type === 'payload') {
|
68
|
-
|
69
|
-
return null;
|
70
|
-
payload = value;
|
71
|
-
dispatchPayload();
|
72
|
-
idx = newIdx + 1;
|
76
|
+
idx[model] = newIdx;
|
73
77
|
// Clear any old changes left in the queue
|
74
|
-
patchQueue = lodash_1.default.pick(patchQueue, lodash_1.default.keys(patchQueue).filter(k => k > newIdx + 1));
|
75
|
-
return;
|
78
|
+
patchQueue[model] = lodash_1.default.pick(patchQueue[model], lodash_1.default.keys(patchQueue[model]).filter(k => k > newIdx + 1));
|
76
79
|
}
|
77
|
-
patchQueue[newIdx] =
|
78
|
-
|
80
|
+
patchQueue[model][newIdx] = camelizeKeys(Object.assign(Object.assign({}, data), { model }));
|
81
|
+
console.debug("Added to queue", model, idx[model], camelizeKeys(Object.assign(Object.assign({}, data), { model })), serverActionQueue.getData());
|
82
|
+
processQueue(model);
|
79
83
|
if (diffSeconds((new Date()), lastCheckAt) >= 3) {
|
80
84
|
lastCheckAt = new Date();
|
81
|
-
console.
|
85
|
+
console.debug('Interval lost. Pulling from server');
|
82
86
|
tGetPayload();
|
83
87
|
}
|
84
88
|
}
|
85
|
-
|
89
|
+
tGetPayload();
|
90
|
+
// Clean up after ourselves
|
91
|
+
function tearDown() {
|
92
|
+
dispatch({ type: `jasonModels/removeSubscription`, payload: { subscriptionId } });
|
93
|
+
}
|
94
|
+
return { handlePayload, tearDown };
|
86
95
|
}
|
87
96
|
exports.default = createPayloadHandler;
|