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.
Files changed (80) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +4 -1
  3. data/.ruby-version +1 -0
  4. data/Gemfile.lock +184 -0
  5. data/README.md +118 -10
  6. data/app/controllers/jason/api/pusher_controller.rb +15 -0
  7. data/app/controllers/jason/api_controller.rb +78 -0
  8. data/client/babel.config.js +13 -0
  9. data/client/lib/JasonContext.d.ts +6 -1
  10. data/client/lib/JasonProvider.d.ts +6 -5
  11. data/client/lib/JasonProvider.js +5 -97
  12. data/client/lib/actionFactory.js +1 -1
  13. data/client/lib/createActions.d.ts +1 -1
  14. data/client/lib/createActions.js +2 -27
  15. data/client/lib/createJasonReducers.js +49 -3
  16. data/client/lib/createOptDis.d.ts +1 -0
  17. data/client/lib/createOptDis.js +43 -0
  18. data/client/lib/createPayloadHandler.d.ts +9 -1
  19. data/client/lib/createPayloadHandler.js +52 -43
  20. data/client/lib/createServerActionQueue.d.ts +10 -0
  21. data/client/lib/createServerActionQueue.js +48 -0
  22. data/client/lib/createServerActionQueue.test.d.ts +1 -0
  23. data/client/lib/createServerActionQueue.test.js +37 -0
  24. data/client/lib/createTransportAdapter.d.ts +5 -0
  25. data/client/lib/createTransportAdapter.js +20 -0
  26. data/client/lib/deepCamelizeKeys.d.ts +1 -0
  27. data/client/lib/deepCamelizeKeys.js +23 -0
  28. data/client/lib/deepCamelizeKeys.test.d.ts +1 -0
  29. data/client/lib/deepCamelizeKeys.test.js +106 -0
  30. data/client/lib/index.d.ts +6 -5
  31. data/client/lib/pruneIdsMiddleware.d.ts +2 -0
  32. data/client/lib/pruneIdsMiddleware.js +24 -0
  33. data/client/lib/restClient.d.ts +2 -0
  34. data/client/lib/restClient.js +17 -0
  35. data/client/lib/transportAdapters/actionCableAdapter.d.ts +5 -0
  36. data/client/lib/transportAdapters/actionCableAdapter.js +35 -0
  37. data/client/lib/transportAdapters/pusherAdapter.d.ts +5 -0
  38. data/client/lib/transportAdapters/pusherAdapter.js +68 -0
  39. data/client/lib/useJason.d.ts +5 -0
  40. data/client/lib/useJason.js +94 -0
  41. data/client/lib/useJason.test.d.ts +1 -0
  42. data/client/lib/useJason.test.js +85 -0
  43. data/client/lib/useSub.d.ts +1 -1
  44. data/client/lib/useSub.js +6 -3
  45. data/client/package.json +19 -4
  46. data/client/src/JasonProvider.tsx +6 -96
  47. data/client/src/actionFactory.ts +1 -1
  48. data/client/src/createActions.ts +2 -33
  49. data/client/src/createJasonReducers.ts +57 -3
  50. data/client/src/createOptDis.ts +45 -0
  51. data/client/src/createPayloadHandler.ts +58 -47
  52. data/client/src/createServerActionQueue.test.ts +42 -0
  53. data/client/src/createServerActionQueue.ts +47 -0
  54. data/client/src/createTransportAdapter.ts +13 -0
  55. data/client/src/deepCamelizeKeys.test.ts +113 -0
  56. data/client/src/deepCamelizeKeys.ts +17 -0
  57. data/client/src/pruneIdsMiddleware.ts +24 -0
  58. data/client/src/restClient.ts +14 -0
  59. data/client/src/transportAdapters/actionCableAdapter.ts +38 -0
  60. data/client/src/transportAdapters/pusherAdapter.ts +72 -0
  61. data/client/src/useJason.test.ts +87 -0
  62. data/client/src/useJason.ts +110 -0
  63. data/client/src/useSub.ts +6 -3
  64. data/client/yarn.lock +4607 -81
  65. data/config/routes.rb +8 -0
  66. data/jason-rails.gemspec +9 -0
  67. data/lib/jason.rb +40 -1
  68. data/lib/jason/api_model.rb +15 -9
  69. data/lib/jason/broadcaster.rb +19 -0
  70. data/lib/jason/channel.rb +50 -21
  71. data/lib/jason/engine.rb +5 -0
  72. data/lib/jason/graph_helper.rb +165 -0
  73. data/lib/jason/includes_helper.rb +108 -0
  74. data/lib/jason/lua_generator.rb +71 -0
  75. data/lib/jason/publisher.rb +103 -30
  76. data/lib/jason/publisher_old.rb +112 -0
  77. data/lib/jason/subscription.rb +352 -101
  78. data/lib/jason/subscription_old.rb +171 -0
  79. data/lib/jason/version.rb +1 -1
  80. metadata +151 -4
@@ -0,0 +1,5 @@
1
+ export default function useJason({ reducers, middleware, extraActions }: {
2
+ reducers?: any;
3
+ middleware?: any[];
4
+ extraActions?: any;
5
+ }): any[];
@@ -0,0 +1,94 @@
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 createActions_1 = __importDefault(require("./createActions"));
7
+ const createJasonReducers_1 = __importDefault(require("./createJasonReducers"));
8
+ const createPayloadHandler_1 = __importDefault(require("./createPayloadHandler"));
9
+ const createOptDis_1 = __importDefault(require("./createOptDis"));
10
+ const createServerActionQueue_1 = __importDefault(require("./createServerActionQueue"));
11
+ const restClient_1 = __importDefault(require("./restClient"));
12
+ const pruneIdsMiddleware_1 = __importDefault(require("./pruneIdsMiddleware"));
13
+ const createTransportAdapter_1 = __importDefault(require("./createTransportAdapter"));
14
+ const toolkit_1 = require("@reduxjs/toolkit");
15
+ const makeEager_1 = __importDefault(require("./makeEager"));
16
+ const humps_1 = require("humps");
17
+ const blueimp_md5_1 = __importDefault(require("blueimp-md5"));
18
+ const lodash_1 = __importDefault(require("lodash"));
19
+ const react_1 = require("react");
20
+ function useJason({ reducers, middleware = [], extraActions }) {
21
+ const [store, setStore] = react_1.useState(null);
22
+ const [value, setValue] = react_1.useState(null);
23
+ react_1.useEffect(() => {
24
+ restClient_1.default.get('/jason/api/config')
25
+ .then(({ data: jasonConfig }) => {
26
+ const { schema: snakey_schema } = jasonConfig;
27
+ const schema = humps_1.camelizeKeys(snakey_schema);
28
+ console.debug({ schema });
29
+ const serverActionQueue = createServerActionQueue_1.default();
30
+ const allReducers = Object.assign(Object.assign({}, reducers), createJasonReducers_1.default(schema));
31
+ console.debug({ allReducers });
32
+ const store = toolkit_1.configureStore({ reducer: allReducers, middleware: [...middleware, pruneIdsMiddleware_1.default(schema)] });
33
+ const dispatch = store.dispatch;
34
+ const optDis = createOptDis_1.default(schema, dispatch, restClient_1.default, serverActionQueue);
35
+ const actions = createActions_1.default(schema, store, restClient_1.default, optDis, extraActions);
36
+ const eager = makeEager_1.default(schema);
37
+ let payloadHandlers = {};
38
+ let configs = {};
39
+ let subOptions = {};
40
+ function handlePayload(payload) {
41
+ const { md5Hash } = payload;
42
+ const { handlePayload } = payloadHandlers[md5Hash];
43
+ if (handlePayload) {
44
+ handlePayload(payload);
45
+ }
46
+ else {
47
+ console.warn("Payload arrived with no handler", payload, payloadHandlers);
48
+ }
49
+ }
50
+ const transportAdapter = createTransportAdapter_1.default(jasonConfig, handlePayload, dispatch, () => lodash_1.default.keys(configs).forEach(md5Hash => createSubscription(configs[md5Hash], subOptions[md5Hash])));
51
+ function createSubscription(config, options = {}) {
52
+ // We need the hash to be consistent in Ruby / Javascript
53
+ const hashableConfig = lodash_1.default(Object.assign({ conditions: {}, includes: {} }, config)).toPairs().sortBy(0).fromPairs().value();
54
+ const md5Hash = blueimp_md5_1.default(JSON.stringify(hashableConfig));
55
+ payloadHandlers[md5Hash] = createPayloadHandler_1.default({ dispatch, serverActionQueue, transportAdapter, config });
56
+ configs[md5Hash] = hashableConfig;
57
+ subOptions[md5Hash] = options;
58
+ setTimeout(() => transportAdapter.createSubscription(hashableConfig), 500);
59
+ let pollInterval = null;
60
+ // This is only for debugging / dev - not prod!
61
+ // @ts-ignore
62
+ if (options.pollInterval) {
63
+ // @ts-ignore
64
+ pollInterval = setInterval(() => transportAdapter.getPayload(hashableConfig, { forceRefresh: true }), options.pollInterval);
65
+ }
66
+ return {
67
+ remove() {
68
+ removeSubscription(hashableConfig);
69
+ if (pollInterval)
70
+ clearInterval(pollInterval);
71
+ },
72
+ md5Hash
73
+ };
74
+ }
75
+ function removeSubscription(config) {
76
+ transportAdapter.removeSubscription(config);
77
+ const md5Hash = blueimp_md5_1.default(JSON.stringify(config));
78
+ payloadHandlers[md5Hash].tearDown();
79
+ delete payloadHandlers[md5Hash];
80
+ delete configs[md5Hash];
81
+ delete subOptions[md5Hash];
82
+ }
83
+ setValue({
84
+ actions: actions,
85
+ subscribe: createSubscription,
86
+ eager,
87
+ handlePayload
88
+ });
89
+ setStore(store);
90
+ });
91
+ }, []);
92
+ return [store, value];
93
+ }
94
+ exports.default = useJason;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,85 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ const react_hooks_1 = require("@testing-library/react-hooks");
16
+ const useJason_1 = __importDefault(require("./useJason"));
17
+ const restClient_1 = __importDefault(require("./restClient"));
18
+ jest.mock('./restClient');
19
+ test('it works', () => __awaiter(void 0, void 0, void 0, function* () {
20
+ const resp = { data: {
21
+ schema: { post: {} },
22
+ transportService: 'action_cable'
23
+ } };
24
+ // @ts-ignore
25
+ restClient_1.default.get.mockResolvedValue(resp);
26
+ const { result, waitForNextUpdate } = react_hooks_1.renderHook(() => useJason_1.default({ reducers: {
27
+ test: (s, a) => s || {}
28
+ } }));
29
+ yield waitForNextUpdate();
30
+ const [store, value, connected] = result.current;
31
+ const { handlePayload, subscribe } = value;
32
+ const subscription = subscribe({ post: {} });
33
+ handlePayload({
34
+ type: 'payload',
35
+ model: 'post',
36
+ payload: [{ id: 4, name: 'test' }],
37
+ md5Hash: subscription.md5Hash,
38
+ idx: 1
39
+ });
40
+ handlePayload({
41
+ id: 4,
42
+ model: 'post',
43
+ destroy: true,
44
+ md5Hash: subscription.md5Hash,
45
+ idx: 2
46
+ });
47
+ handlePayload({
48
+ id: 5,
49
+ model: 'post',
50
+ payload: { id: 5, name: 'test2' },
51
+ md5Hash: subscription.md5Hash,
52
+ idx: 3
53
+ });
54
+ }));
55
+ test('pruning IDs', () => __awaiter(void 0, void 0, void 0, function* () {
56
+ const resp = { data: {
57
+ schema: { post: {} },
58
+ transportService: 'action_cable'
59
+ } };
60
+ // @ts-ignore
61
+ restClient_1.default.get.mockResolvedValue(resp);
62
+ const { result, waitForNextUpdate } = react_hooks_1.renderHook(() => useJason_1.default({ reducers: {
63
+ test: (s, a) => s || {}
64
+ } }));
65
+ yield waitForNextUpdate();
66
+ const [store, value, connected] = result.current;
67
+ const { handlePayload, subscribe } = value;
68
+ const subscription = subscribe({ post: {} });
69
+ handlePayload({
70
+ type: 'payload',
71
+ model: 'post',
72
+ payload: [{ id: 4, name: 'test' }],
73
+ md5Hash: subscription.md5Hash,
74
+ idx: 1
75
+ });
76
+ handlePayload({
77
+ type: 'payload',
78
+ model: 'post',
79
+ payload: [{ id: 5, name: 'test it out' }],
80
+ md5Hash: subscription.md5Hash,
81
+ idx: 2
82
+ });
83
+ // The ID 4 should have been pruned
84
+ expect(store.getState().posts.ids).toStrictEqual([5]);
85
+ }));
@@ -1 +1 @@
1
- export default function useSub(config: any): void;
1
+ export default function useSub(config: any, options?: {}): void;
data/client/lib/useSub.js CHANGED
@@ -5,10 +5,13 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  const JasonContext_1 = __importDefault(require("./JasonContext"));
7
7
  const react_1 = require("react");
8
- function useSub(config) {
8
+ function useSub(config, options = {}) {
9
+ // useEffect uses strict equality
10
+ const configJson = JSON.stringify(config);
9
11
  const subscribe = react_1.useContext(JasonContext_1.default).subscribe;
10
12
  react_1.useEffect(() => {
11
- return subscribe(config);
12
- }, []);
13
+ // @ts-ignore
14
+ return subscribe(config, options).remove;
15
+ }, [configJson]);
13
16
  }
14
17
  exports.default = useSub;
data/client/package.json CHANGED
@@ -1,9 +1,11 @@
1
1
  {
2
2
  "name": "@jamesr2323/jason",
3
- "version": "0.3.0",
3
+ "version": "0.6.0",
4
4
  "module": "./lib/index.js",
5
+ "types": "./lib/index.d.ts",
5
6
  "scripts": {
6
- "build": "tsc"
7
+ "build": "tsc",
8
+ "test": "jest"
7
9
  },
8
10
  "dependencies": {
9
11
  "@rails/actioncable": "^6.0.3-4",
@@ -14,14 +16,27 @@
14
16
  "jsonpatch": "^3.0.1",
15
17
  "lodash": "^4.17.20",
16
18
  "pluralize": "^8.0.0",
19
+ "pusher-js": "^7.0.3",
17
20
  "uuid": "^8.3.1"
18
21
  },
19
22
  "devDependencies": {
23
+ "@babel/core": "^7.12.10",
24
+ "@babel/preset-env": "^7.12.11",
25
+ "@babel/preset-typescript": "^7.12.7",
26
+ "@reduxjs/toolkit": "^1.5.0",
27
+ "@testing-library/react-hooks": "^5.0.3",
28
+ "@types/jest": "^26.0.19",
29
+ "babel-jest": "^26.6.3",
30
+ "jest": "^26.6.3",
31
+ "react": "^16.9.x",
32
+ "react-dom": "^16.9.x",
33
+ "react-redux": "^7.2.2",
20
34
  "typescript": "^4.1.2"
21
35
  },
22
36
  "peerDependencies": {
37
+ "@reduxjs/toolkit": "^1.5.0",
23
38
  "react": "^16.8.3",
24
- "react-redux": "^7.2.2",
25
- "@reduxjs/toolkit": "^1.5.0"
39
+ "react-dom": "^16.8.3",
40
+ "react-redux": "^7.2.2"
26
41
  }
27
42
  }
@@ -1,102 +1,12 @@
1
- import createActions from './createActions'
2
- import { createConsumer } from "@rails/actioncable"
3
- import JasonContext from './JasonContext'
4
- import axios from 'axios'
5
- import applyCaseMiddleware from 'axios-case-converter'
1
+ import React from 'react'
2
+ import useJason from './useJason'
6
3
  import { Provider } from 'react-redux'
7
- import { createEntityAdapter, createSlice, createReducer, configureStore } from '@reduxjs/toolkit'
8
- import createJasonReducers from './createJasonReducers'
9
- import createPayloadHandler from './createPayloadHandler'
10
- import makeEager from './makeEager'
11
- import { camelizeKeys } from 'humps'
12
- import md5 from 'blueimp-md5'
13
- import _ from 'lodash'
14
- import React, { useState, useEffect } from 'react'
15
-
16
- const JasonProvider = ({ reducers, middleware, extraActions, children }) => {
17
- const [store, setStore] = useState(null)
18
- const [value, setValue] = useState(null)
19
- const [connected, setConnected] = useState(false)
20
-
21
- const csrfToken = (document.querySelector("meta[name=csrf-token]") as any).content
22
- axios.defaults.headers.common['X-CSRF-Token'] = csrfToken
23
- const restClient = applyCaseMiddleware(axios.create())
24
-
25
- useEffect(() => {
26
- restClient.get('/jason/api/schema')
27
- .then(({ data: snakey_schema }) => {
28
- const schema = camelizeKeys(snakey_schema)
29
-
30
- const consumer = createConsumer()
31
- const allReducers = {
32
- ...reducers,
33
- ...createJasonReducers(schema)
34
- }
35
-
36
- console.log({ schema, allReducers })
37
- const store = configureStore({ reducer: allReducers, middleware })
38
-
39
- let payloadHandlers = {}
40
- function handlePayload(payload) {
41
- const { model, md5Hash } = payload
42
- console.log({ md5Hash, fn: `${model}:${md5Hash}`, payloadHandlers, model: _.camelCase(model), payload })
43
- const handler = payloadHandlers[`${_.camelCase(model)}:${md5Hash}`]
44
- if (handler) {
45
- handler({ ...payload, model: _.camelCase(model) })
46
- }
47
- }
48
-
49
- const subscription = (consumer.subscriptions.create({
50
- channel: 'Jason::Channel'
51
- }, {
52
- connected: () => {
53
- setConnected(true)
54
- },
55
- received: payload => {
56
- console.log("Payload received", payload)
57
- handlePayload(payload)
58
- },
59
- disconnected: () => console.warn('Disconnected from ActionCable')
60
- }));
61
-
62
- console.log('sending message')
63
- subscription.send({ message: 'test' })
64
-
65
- function createSubscription(config) {
66
- const md5Hash = md5(JSON.stringify(config))
67
- console.log('Subscribe with', config, md5Hash)
68
-
69
- _.map(config, (v, model) => {
70
- payloadHandlers[`${model}:${md5Hash}`] = createPayloadHandler(store.dispatch, subscription, model, schema[model])
71
- })
72
- subscription.send({ createSubscription: config })
73
-
74
- return () => removeSubscription(config)
75
- }
76
-
77
- function removeSubscription(config) {
78
- subscription.send({ removeSubscription: config })
79
- const md5Hash = md5(JSON.stringify(config))
80
- _.map(config, (v, model) => {
81
- delete payloadHandlers[`${model}:${md5Hash}`]
82
- })
83
- }
84
-
85
- const actions = createActions(schema, store, restClient, extraActions)
86
- const eager = makeEager(schema)
87
-
88
- console.log({ actions })
4
+ import JasonContext from './JasonContext'
89
5
 
90
- setValue({
91
- actions: actions,
92
- subscribe: (config) => createSubscription(config),
93
- eager
94
- })
95
- setStore(store)
96
- })
97
- }, [])
6
+ const JasonProvider = ({ reducers, middleware, extraActions, children }: { reducers?: any, middleware?: any, extraActions?: any, children?: React.FC }) => {
7
+ const [store, value] = useJason({ reducers, middleware, extraActions })
98
8
 
99
- if(!(store && value && connected)) return <div /> // Wait for async fetch of schema to complete
9
+ if(!(store && value)) return <div /> // Wait for async fetch of schema to complete
100
10
 
101
11
  return <Provider store={store}>
102
12
  <JasonContext.Provider value={value}>{ children }</JasonContext.Provider>
@@ -24,7 +24,7 @@ export default (dis, store, entity, { extraActions = {}, hasPriority = false } =
24
24
  return dis({ type: `${pluralize(entity)}/remove`, payload: id })
25
25
  }
26
26
 
27
- const extraActionsResolved = _.mapValues(extraActions, v => v(dis, store, entity))
27
+ const extraActionsResolved = extraActions ? _.mapValues(extraActions, v => v(dis, store, entity)) : {}
28
28
 
29
29
  if (hasPriority) {
30
30
  return { add, upsert, setAll, remove, movePriority, ...extraActionsResolved }
@@ -1,39 +1,8 @@
1
1
  import actionFactory from './actionFactory'
2
2
  import pluralize from 'pluralize'
3
3
  import _ from 'lodash'
4
- import { v4 as uuidv4 } from 'uuid'
5
-
6
- function enrich(type, payload) {
7
- if (type.split('/')[1] === 'upsert' && !(type.split('/')[0] === 'session')) {
8
- if (!payload.id) {
9
- return { ...payload, id: uuidv4() }
10
- }
11
- }
12
- return payload
13
- }
14
-
15
- function makeOptDis(schema, dispatch, restClient) {
16
- const plurals = _.keys(schema).map(k => pluralize(k))
17
-
18
- return function (action) {
19
- const { type, payload } = action
20
- const data = enrich(type, payload)
21
-
22
- dispatch(action)
23
-
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
-
33
- function createActions(schema, store, restClient, extraActions) {
34
- const dis = store.dispatch;
35
- const optDis = makeOptDis(schema, dis, restClient)
36
4
 
5
+ function createActions(schema, store, restClient, optDis, extraActions) {
37
6
  const actions = _.fromPairs(_.map(schema, (config, model: string) => {
38
7
  if (config.priorityScope) {
39
8
  return [pluralize(model), actionFactory(optDis, store, model, { hasPriority: true })]
@@ -42,7 +11,7 @@ function createActions(schema, store, restClient, extraActions) {
42
11
  }
43
12
  }))
44
13
 
45
- const extraActionsResolved = extraActions(optDis, store, restClient)
14
+ const extraActionsResolved = extraActions ? extraActions(optDis, store, restClient, actions) : {}
46
15
 
47
16
  return _.merge(actions, extraActionsResolved)
48
17
  }
@@ -2,8 +2,8 @@ import { createEntityAdapter, createSlice } from '@reduxjs/toolkit'
2
2
  import pluralize from 'pluralize'
3
3
  import _ from 'lodash'
4
4
 
5
- function generateSlices(schema) {
6
- const sliceNames = schema.map(k => pluralize(k))
5
+ function generateSlices(models) {
6
+ const sliceNames = models.map(k => pluralize(k))
7
7
  const adapter = createEntityAdapter()
8
8
 
9
9
  return _.fromPairs(_.map(sliceNames, name => {
@@ -16,6 +16,7 @@ function generateSlices(schema) {
16
16
  add: adapter.addOne,
17
17
  setAll: adapter.setAll,
18
18
  remove: adapter.removeOne,
19
+ removeMany: adapter.removeMany,
19
20
  movePriority: (s, { payload: { id, priority, parentFilter } }) => {
20
21
  // Get IDs and insert our item at the new index
21
22
  var affectedIds = _.orderBy(_.filter(_.values(s.entities), parentFilter).filter(e => e.id !== id), 'priority').map(e => e.id)
@@ -29,6 +30,59 @@ function generateSlices(schema) {
29
30
  }))
30
31
  }
31
32
 
33
+ function generateJasonSlices(models) {
34
+ const initialState = _.fromPairs(_.map(models, (model_name) => {
35
+ return [model_name, {}]
36
+ }))
37
+
38
+ const modelSliceReducer = 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] = _.union(s[model][subscriptionId] || [], [id])
52
+ },
53
+ removeSubscriptionId(s,a) {
54
+ const { payload } = a
55
+ const { subscriptionId, model, id } = payload
56
+ s[model][subscriptionId] = _.remove(s[model][subscriptionId] || [], id)
57
+ },
58
+ removeSubscription(s, a) {
59
+ const { payload: { subscriptionId } } = a
60
+ _.map(models, model => {
61
+ delete s[model][subscriptionId]
62
+ })
63
+ }
64
+ }
65
+ }).reducer
66
+
67
+ const jasonSliceReducer = createSlice({
68
+ name: 'jason',
69
+ initialState: {
70
+ connected: false,
71
+ queueSize: 0
72
+ },
73
+ reducers: {
74
+ upsert: (s,a) => ({ ...s, ...a.payload })
75
+ }
76
+ }).reducer
77
+
78
+ return { jason: jasonSliceReducer, jasonModels: modelSliceReducer }
79
+ }
80
+
32
81
  export default function createJasonReducers(schema) {
33
- return generateSlices(_.keys(schema))
82
+ const models = _.keys(schema)
83
+
84
+ return {
85
+ ...generateSlices(models),
86
+ ...generateJasonSlices(models)
87
+ }
34
88
  }