jason-rails 0.3.0 → 0.6.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.
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
  }