jason-rails 0.4.1 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/.ruby-version +1 -0
  3. data/Gemfile.lock +152 -2
  4. data/app/controllers/jason/api_controller.rb +1 -1
  5. data/client/lib/JasonContext.d.ts +6 -1
  6. data/client/lib/JasonProvider.d.ts +2 -2
  7. data/client/lib/JasonProvider.js +5 -124
  8. data/client/lib/createJasonReducers.js +41 -3
  9. data/client/lib/createOptDis.js +0 -2
  10. data/client/lib/createPayloadHandler.d.ts +6 -1
  11. data/client/lib/createPayloadHandler.js +42 -54
  12. data/client/lib/createServerActionQueue.d.ts +10 -0
  13. data/client/lib/createServerActionQueue.js +48 -0
  14. data/client/lib/createServerActionQueue.test.d.ts +1 -0
  15. data/client/lib/createServerActionQueue.test.js +37 -0
  16. data/client/lib/index.d.ts +3 -2
  17. data/client/lib/pruneIdsMiddleware.d.ts +2 -0
  18. data/client/lib/pruneIdsMiddleware.js +26 -0
  19. data/client/lib/restClient.d.ts +2 -0
  20. data/client/lib/restClient.js +17 -0
  21. data/client/lib/useJason.d.ts +5 -0
  22. data/client/lib/useJason.js +99 -0
  23. data/client/lib/useJason.test.d.ts +1 -0
  24. data/client/lib/useJason.test.js +79 -0
  25. data/client/lib/useSub.js +1 -0
  26. data/client/package.json +4 -3
  27. data/client/src/JasonProvider.tsx +5 -123
  28. data/client/src/createJasonReducers.ts +49 -3
  29. data/client/src/createOptDis.ts +0 -2
  30. data/client/src/createPayloadHandler.ts +47 -63
  31. data/client/src/createServerActionQueue.test.ts +42 -0
  32. data/client/src/createServerActionQueue.ts +47 -0
  33. data/client/src/pruneIdsMiddleware.ts +24 -0
  34. data/client/src/restClient.ts +13 -0
  35. data/client/src/useJason.test.ts +81 -0
  36. data/client/src/useJason.ts +115 -0
  37. data/client/src/useSub.ts +1 -0
  38. data/client/yarn.lock +59 -3
  39. data/jason-rails.gemspec +4 -0
  40. data/lib/jason.rb +12 -0
  41. data/lib/jason/api_model.rb +2 -12
  42. data/lib/jason/channel.rb +43 -21
  43. data/lib/jason/lua_generator.rb +49 -0
  44. data/lib/jason/publisher.rb +76 -35
  45. data/lib/jason/publisher_old.rb +112 -0
  46. data/lib/jason/subscription.rb +322 -99
  47. data/lib/jason/subscription_old.rb +171 -0
  48. data/lib/jason/version.rb +1 -1
  49. metadata +67 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 66c465280dc28e42bdd02b400ef514408a4839df70240aad2d660fc7b7dc1ed2
4
- data.tar.gz: 0ae40af767936631bc8ab174682073a2ad860578ad363bdab7b7080116be2e34
3
+ metadata.gz: 6e6d1d960c2bb555ccaa555a17de7730ce90c35aa57594256bcb73bc96dade09
4
+ data.tar.gz: b096c733bd15195ac383097a8138507915caa5fba29d9099325755972a64fe2a
5
5
  SHA512:
6
- metadata.gz: 6e27560fdd5953ef4a86cc371577b1e8e4f88d3e8f9099abd3f6fd41ad234071a348f67236c24106345acb700ffc16ed99d0036811e8d2bb29914462d89577cb
7
- data.tar.gz: 8deefbe678cebd020e5439ed3264f5b016d3c066d1d24baf3c9146ee32cd8404a6ef2c6e9bda350f276f4d1775ec3a50a9c5570960228c1f253b7adaae45f7ed
6
+ metadata.gz: 4ce914a0e658fe97051ff6a64a48a29bccde202ad3fa60bc3aadc287f4a50a4f169d647b66f456e3147da8551b5b321185caa05c9790c964202d5275b20a8732
7
+ data.tar.gz: ebde6f3323cb516915e3ddea2f747595a864df2cac9f52e05c67b1320c46f20693c479d7b39b11f391638dc9e5027b92e86ad65089282c6c190b6ba4982b3de3
@@ -0,0 +1 @@
1
+ 2.7.2
@@ -1,13 +1,137 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- jason-rails (0.3.0)
4
+ jason-rails (0.4.1)
5
+ connection_pool (>= 2.2.3)
6
+ jsondiff
7
+ rails (>= 5)
8
+ redis (>= 4)
5
9
 
6
10
  GEM
7
11
  remote: https://rubygems.org/
8
12
  specs:
13
+ actioncable (6.1.1)
14
+ actionpack (= 6.1.1)
15
+ activesupport (= 6.1.1)
16
+ nio4r (~> 2.0)
17
+ websocket-driver (>= 0.6.1)
18
+ actionmailbox (6.1.1)
19
+ actionpack (= 6.1.1)
20
+ activejob (= 6.1.1)
21
+ activerecord (= 6.1.1)
22
+ activestorage (= 6.1.1)
23
+ activesupport (= 6.1.1)
24
+ mail (>= 2.7.1)
25
+ actionmailer (6.1.1)
26
+ actionpack (= 6.1.1)
27
+ actionview (= 6.1.1)
28
+ activejob (= 6.1.1)
29
+ activesupport (= 6.1.1)
30
+ mail (~> 2.5, >= 2.5.4)
31
+ rails-dom-testing (~> 2.0)
32
+ actionpack (6.1.1)
33
+ actionview (= 6.1.1)
34
+ activesupport (= 6.1.1)
35
+ rack (~> 2.0, >= 2.0.9)
36
+ rack-test (>= 0.6.3)
37
+ rails-dom-testing (~> 2.0)
38
+ rails-html-sanitizer (~> 1.0, >= 1.2.0)
39
+ actiontext (6.1.1)
40
+ actionpack (= 6.1.1)
41
+ activerecord (= 6.1.1)
42
+ activestorage (= 6.1.1)
43
+ activesupport (= 6.1.1)
44
+ nokogiri (>= 1.8.5)
45
+ actionview (6.1.1)
46
+ activesupport (= 6.1.1)
47
+ builder (~> 3.1)
48
+ erubi (~> 1.4)
49
+ rails-dom-testing (~> 2.0)
50
+ rails-html-sanitizer (~> 1.1, >= 1.2.0)
51
+ activejob (6.1.1)
52
+ activesupport (= 6.1.1)
53
+ globalid (>= 0.3.6)
54
+ activemodel (6.1.1)
55
+ activesupport (= 6.1.1)
56
+ activerecord (6.1.1)
57
+ activemodel (= 6.1.1)
58
+ activesupport (= 6.1.1)
59
+ activestorage (6.1.1)
60
+ actionpack (= 6.1.1)
61
+ activejob (= 6.1.1)
62
+ activerecord (= 6.1.1)
63
+ activesupport (= 6.1.1)
64
+ marcel (~> 0.3.1)
65
+ mimemagic (~> 0.3.2)
66
+ activesupport (6.1.1)
67
+ concurrent-ruby (~> 1.0, >= 1.0.2)
68
+ i18n (>= 1.6, < 2)
69
+ minitest (>= 5.1)
70
+ tzinfo (~> 2.0)
71
+ zeitwerk (~> 2.3)
72
+ builder (3.2.4)
73
+ coderay (1.1.3)
74
+ concurrent-ruby (1.1.7)
75
+ connection_pool (2.2.3)
76
+ crass (1.0.6)
9
77
  diff-lcs (1.4.4)
78
+ erubi (1.10.0)
79
+ globalid (0.4.2)
80
+ activesupport (>= 4.2.0)
81
+ i18n (1.8.7)
82
+ concurrent-ruby (~> 1.0)
83
+ jsondiff (0.0.5)
84
+ loofah (2.8.0)
85
+ crass (~> 1.0.2)
86
+ nokogiri (>= 1.5.9)
87
+ mail (2.7.1)
88
+ mini_mime (>= 0.1.1)
89
+ marcel (0.3.3)
90
+ mimemagic (~> 0.3.2)
91
+ method_source (1.0.0)
92
+ mimemagic (0.3.5)
93
+ mini_mime (1.0.2)
94
+ mini_portile2 (2.5.0)
95
+ minitest (5.14.3)
96
+ nio4r (2.5.4)
97
+ nokogiri (1.11.1)
98
+ mini_portile2 (~> 2.5.0)
99
+ racc (~> 1.4)
100
+ pry (0.13.1)
101
+ coderay (~> 1.1)
102
+ method_source (~> 1.0)
103
+ racc (1.5.2)
104
+ rack (2.2.3)
105
+ rack-test (1.1.0)
106
+ rack (>= 1.0, < 3)
107
+ rails (6.1.1)
108
+ actioncable (= 6.1.1)
109
+ actionmailbox (= 6.1.1)
110
+ actionmailer (= 6.1.1)
111
+ actionpack (= 6.1.1)
112
+ actiontext (= 6.1.1)
113
+ actionview (= 6.1.1)
114
+ activejob (= 6.1.1)
115
+ activemodel (= 6.1.1)
116
+ activerecord (= 6.1.1)
117
+ activestorage (= 6.1.1)
118
+ activesupport (= 6.1.1)
119
+ bundler (>= 1.15.0)
120
+ railties (= 6.1.1)
121
+ sprockets-rails (>= 2.0.0)
122
+ rails-dom-testing (2.0.3)
123
+ activesupport (>= 4.2.0)
124
+ nokogiri (>= 1.6)
125
+ rails-html-sanitizer (1.3.0)
126
+ loofah (~> 2.3)
127
+ railties (6.1.1)
128
+ actionpack (= 6.1.1)
129
+ activesupport (= 6.1.1)
130
+ method_source
131
+ rake (>= 0.8.7)
132
+ thor (~> 1.0)
10
133
  rake (12.3.3)
134
+ redis (4.2.5)
11
135
  rspec (3.10.0)
12
136
  rspec-core (~> 3.10.0)
13
137
  rspec-expectations (~> 3.10.0)
@@ -20,15 +144,41 @@ GEM
20
144
  rspec-mocks (3.10.0)
21
145
  diff-lcs (>= 1.2.0, < 2.0)
22
146
  rspec-support (~> 3.10.0)
147
+ rspec-rails (4.0.2)
148
+ actionpack (>= 4.2)
149
+ activesupport (>= 4.2)
150
+ railties (>= 4.2)
151
+ rspec-core (~> 3.10)
152
+ rspec-expectations (~> 3.10)
153
+ rspec-mocks (~> 3.10)
154
+ rspec-support (~> 3.10)
23
155
  rspec-support (3.10.0)
156
+ sprockets (4.0.2)
157
+ concurrent-ruby (~> 1.0)
158
+ rack (> 1, < 3)
159
+ sprockets-rails (3.2.2)
160
+ actionpack (>= 4.0)
161
+ activesupport (>= 4.0)
162
+ sprockets (>= 3.0.0)
163
+ sqlite3 (1.4.2)
164
+ thor (1.0.1)
165
+ tzinfo (2.0.4)
166
+ concurrent-ruby (~> 1.0)
167
+ websocket-driver (0.7.3)
168
+ websocket-extensions (>= 0.1.0)
169
+ websocket-extensions (0.1.5)
170
+ zeitwerk (2.4.2)
24
171
 
25
172
  PLATFORMS
26
173
  ruby
27
174
 
28
175
  DEPENDENCIES
29
176
  jason-rails!
177
+ pry
30
178
  rake (~> 12.0)
31
179
  rspec (~> 3.0)
180
+ rspec-rails
181
+ sqlite3
32
182
 
33
183
  BUNDLED WITH
34
- 1.17.3
184
+ 2.1.4
@@ -1,6 +1,6 @@
1
1
  class Jason::ApiController < ::ApplicationController
2
2
  def schema
3
- render json: JASON_API_MODEL.to_json
3
+ render json: Jason.schema
4
4
  end
5
5
 
6
6
  def action
@@ -1,2 +1,7 @@
1
- declare const context: any;
1
+ /// <reference types="react" />
2
+ declare const context: import("react").Context<{
3
+ actions: any;
4
+ subscribe: null;
5
+ eager: null;
6
+ }>;
2
7
  export default context;
@@ -3,6 +3,6 @@ declare const JasonProvider: ({ reducers, middleware, extraActions, children }:
3
3
  reducers?: any;
4
4
  middleware?: any;
5
5
  extraActions?: any;
6
- children?: any;
7
- }) => any;
6
+ children?: React.FC<{}> | undefined;
7
+ }) => JSX.Element;
8
8
  export default JasonProvider;
@@ -1,134 +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 createActions_1 = __importDefault(require("./createActions"));
26
- const actioncable_1 = require("@rails/actioncable");
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 toolkit_1 = require("@reduxjs/toolkit");
32
- const createJasonReducers_1 = __importDefault(require("./createJasonReducers"));
33
- const createPayloadHandler_1 = __importDefault(require("./createPayloadHandler"));
34
- const createOptDis_1 = __importDefault(require("./createOptDis"));
35
- const makeEager_1 = __importDefault(require("./makeEager"));
36
- const humps_1 = require("humps");
37
- const blueimp_md5_1 = __importDefault(require("blueimp-md5"));
38
- const lodash_1 = __importDefault(require("lodash"));
39
- const react_1 = __importStar(require("react"));
40
- const uuid_1 = require("uuid");
9
+ const JasonContext_1 = __importDefault(require("./JasonContext"));
41
10
  const JasonProvider = ({ reducers, middleware, extraActions, children }) => {
42
- const [store, setStore] = react_1.useState(null);
43
- const [value, setValue] = react_1.useState(null);
44
- const [connected, setConnected] = react_1.useState(false);
45
- const csrfToken = document.querySelector("meta[name=csrf-token]").content;
46
- axios_1.default.defaults.headers.common['X-CSRF-Token'] = csrfToken;
47
- const restClient = axios_case_converter_1.default(axios_1.default.create(), {
48
- preservedKeys: (key) => {
49
- return uuid_1.validate(key);
50
- }
51
- });
52
- react_1.useEffect(() => {
53
- restClient.get('/jason/api/schema')
54
- .then(({ data: snakey_schema }) => {
55
- const schema = humps_1.camelizeKeys(snakey_schema);
56
- const serverActionQueue = function () {
57
- const queue = [];
58
- let inFlight = false;
59
- return {
60
- addItem: (item) => queue.push(item),
61
- getItem: () => {
62
- if (inFlight)
63
- return false;
64
- const item = queue.shift();
65
- if (item) {
66
- inFlight = true;
67
- return item;
68
- }
69
- return false;
70
- },
71
- itemProcessed: () => inFlight = false,
72
- fullySynced: () => queue.length === 0 && !inFlight,
73
- getData: () => ({ queue, inFlight })
74
- };
75
- }();
76
- const consumer = actioncable_1.createConsumer();
77
- const allReducers = Object.assign(Object.assign({}, reducers), createJasonReducers_1.default(schema));
78
- console.log({ schema, allReducers });
79
- const store = toolkit_1.configureStore({ reducer: allReducers, middleware });
80
- let payloadHandlers = {};
81
- function handlePayload(payload) {
82
- const { model, md5Hash } = payload;
83
- console.log({ md5Hash, fn: `${model}:${md5Hash}`, payloadHandlers, model: lodash_1.default.camelCase(model), payload });
84
- const handler = payloadHandlers[`${lodash_1.default.camelCase(model)}:${md5Hash}`];
85
- if (handler) {
86
- handler(Object.assign(Object.assign({}, payload), { model: lodash_1.default.camelCase(model) }));
87
- }
88
- }
89
- const subscription = (consumer.subscriptions.create({
90
- channel: 'Jason::Channel'
91
- }, {
92
- connected: () => {
93
- setConnected(true);
94
- },
95
- received: payload => {
96
- console.log("Payload received", payload);
97
- handlePayload(payload);
98
- },
99
- disconnected: () => console.warn('Disconnected from ActionCable')
100
- }));
101
- console.log('sending message');
102
- subscription.send({ message: 'test' });
103
- function createSubscription(config) {
104
- const md5Hash = blueimp_md5_1.default(JSON.stringify(config));
105
- console.log('Subscribe with', config, md5Hash);
106
- lodash_1.default.map(config, (v, model) => {
107
- payloadHandlers[`${model}:${md5Hash}`] = createPayloadHandler_1.default(store.dispatch, serverActionQueue, subscription, model, schema[model]);
108
- });
109
- subscription.send({ createSubscription: config });
110
- return () => removeSubscription(config);
111
- }
112
- function removeSubscription(config) {
113
- subscription.send({ removeSubscription: config });
114
- const md5Hash = blueimp_md5_1.default(JSON.stringify(config));
115
- lodash_1.default.map(config, (v, model) => {
116
- delete payloadHandlers[`${model}:${md5Hash}`];
117
- });
118
- }
119
- const optDis = createOptDis_1.default(schema, store.dispatch, restClient, serverActionQueue);
120
- const actions = createActions_1.default(schema, store, restClient, optDis, extraActions);
121
- const eager = makeEager_1.default(schema);
122
- console.log({ actions });
123
- setValue({
124
- actions: actions,
125
- subscribe: (config) => createSubscription(config),
126
- eager
127
- });
128
- setStore(store);
129
- });
130
- }, []);
131
- if (!(store && value && connected))
11
+ const [store, value, connected] = useJason_1.default({ reducers, middleware, extraActions });
12
+ if (!(store && value))
132
13
  return react_1.default.createElement("div", null); // Wait for async fetch of schema to complete
133
14
  return react_1.default.createElement(react_redux_1.Provider, { store: store },
134
15
  react_1.default.createElement(JasonContext_1.default.Provider, { value: value }, children));
@@ -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(schema) {
10
- const sliceNames = schema.map(k => pluralize_1.default(k));
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({
@@ -31,7 +31,45 @@ function generateSlices(schema) {
31
31
  }).reducer];
32
32
  }));
33
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
+ s[model][subscriptionId] = ids;
46
+ },
47
+ addSubscriptionId(s, a) {
48
+ const { payload } = a;
49
+ const { subscriptionId, model, id } = payload;
50
+ s[model][subscriptionId] = lodash_1.default.union(s[model][subscriptionId] || [], [id]);
51
+ },
52
+ removeSubscriptionId(s, a) {
53
+ const { payload } = a;
54
+ const { subscriptionId, model, id } = payload;
55
+ s[model][subscriptionId] = lodash_1.default.remove(s[model][subscriptionId] || [], id);
56
+ }
57
+ }
58
+ }).reducer;
59
+ const jasonSliceReducer = toolkit_1.createSlice({
60
+ name: 'jason',
61
+ initialState: {
62
+ connected: false,
63
+ queueSize: 0
64
+ },
65
+ reducers: {
66
+ upsert: (s, a) => (Object.assign(Object.assign({}, s), a.payload))
67
+ }
68
+ }).reducer;
69
+ return { jason: jasonSliceReducer, jasonModels: modelSliceReducer };
70
+ }
34
71
  function createJasonReducers(schema) {
35
- return generateSlices(lodash_1.default.keys(schema));
72
+ const models = lodash_1.default.keys(schema);
73
+ return Object.assign(Object.assign({}, generateSlices(models)), generateJasonSlices(models));
36
74
  }
37
75
  exports.default = createJasonReducers;
@@ -16,7 +16,6 @@ function enrich(type, payload) {
16
16
  }
17
17
  function createOptDis(schema, dispatch, restClient, serverActionQueue) {
18
18
  const plurals = lodash_1.default.keys(schema).map(k => pluralize_1.default(k));
19
- let inFlight = false;
20
19
  function enqueueServerAction(action) {
21
20
  serverActionQueue.addItem(action);
22
21
  }
@@ -24,7 +23,6 @@ function createOptDis(schema, dispatch, restClient, serverActionQueue) {
24
23
  const action = serverActionQueue.getItem();
25
24
  if (!action)
26
25
  return;
27
- inFlight = true;
28
26
  restClient.post('/jason/api/action', action)
29
27
  .then(serverActionQueue.itemProcessed)
30
28
  .catch(e => {
@@ -1 +1,6 @@
1
- export default function createPayloadHandler(dispatch: any, serverActionQueue: any, subscription: any, model: any, config: any): (data: any) => null | undefined;
1
+ export default function createPayloadHandler({ dispatch, serverActionQueue, subscription, config }: {
2
+ dispatch: any;
3
+ serverActionQueue: any;
4
+ subscription: any;
5
+ config: any;
6
+ }): (data: any) => void;
@@ -3,7 +3,6 @@ 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 jsonpatch_1 = require("jsonpatch");
7
6
  const deepCamelizeKeys_1 = __importDefault(require("./deepCamelizeKeys"));
8
7
  const pluralize_1 = __importDefault(require("pluralize"));
9
8
  const lodash_1 = __importDefault(require("lodash"));
@@ -12,93 +11,82 @@ function diffSeconds(dt2, dt1) {
12
11
  var diff = (dt2.getTime() - dt1.getTime()) / 1000;
13
12
  return Math.abs(Math.round(diff));
14
13
  }
15
- function createPayloadHandler(dispatch, serverActionQueue, subscription, model, config) {
16
- console.log({ model, config });
17
- let payload = [];
18
- let previousPayload = [];
19
- let idx = 0;
14
+ function createPayloadHandler({ dispatch, serverActionQueue, subscription, config }) {
15
+ const subscriptionId = uuid_1.v4();
16
+ let idx = {};
20
17
  let patchQueue = {};
21
18
  let lastCheckAt = new Date();
22
19
  let updateDeadline = null;
23
20
  let checkInterval;
24
21
  function getPayload() {
25
- console.log({ getPayload: model, subscription });
26
- subscription.send({ getPayload: { model, config } });
22
+ setTimeout(() => subscription.send({ getPayload: config }), 1000);
27
23
  }
28
24
  function camelizeKeys(item) {
29
25
  return deepCamelizeKeys_1.default(item, key => uuid_1.validate(key));
30
26
  }
31
27
  const tGetPayload = lodash_1.default.throttle(getPayload, 10000);
32
- function dispatchPayload() {
33
- // We want to avoid updates from server overwriting changes to local state, so if there is a queue then wait.
34
- if (!serverActionQueue.fullySynced()) {
35
- console.log(serverActionQueue.getData());
36
- setTimeout(dispatchPayload, 100);
37
- return;
38
- }
39
- const includeModels = (config.includeModels || []).map(m => lodash_1.default.camelCase(m));
40
- console.log("Dispatching", { payload, includeModels });
41
- includeModels.forEach(m => {
42
- const subPayload = lodash_1.default.flatten(lodash_1.default.compact(camelizeKeys(payload).map(instance => instance[m])));
43
- const previousSubPayload = lodash_1.default.flatten(lodash_1.default.compact(camelizeKeys(previousPayload).map(instance => instance[m])));
44
- // Find IDs that were in the payload but are no longer
45
- const idsToRemove = lodash_1.default.difference(previousSubPayload.map(i => i.id), subPayload.map(i => i.id));
46
- dispatch({ type: `${pluralize_1.default(m)}/upsertMany`, payload: subPayload });
47
- dispatch({ type: `${pluralize_1.default(m)}/removeMany`, payload: idsToRemove });
48
- });
49
- const idsToRemove = lodash_1.default.difference(previousPayload.map(i => i.id), payload.map(i => i.id));
50
- dispatch({ type: `${pluralize_1.default(model)}/upsertMany`, payload: camelizeKeys(payload) });
51
- dispatch({ type: `${pluralize_1.default(model)}/removeMany`, payload: idsToRemove });
52
- previousPayload = payload;
53
- }
54
- function processQueue() {
55
- console.log({ idx, patchQueue });
28
+ function processQueue(model) {
29
+ console.debug("processQueue", model, idx[model], patchQueue[model]);
56
30
  lastCheckAt = new Date();
57
- if (patchQueue[idx]) {
58
- payload = jsonpatch_1.apply_patch(payload, patchQueue[idx]);
59
- if (patchQueue[idx]) {
60
- dispatchPayload();
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 } });
42
+ }
43
+ else if (destroy) {
44
+ dispatch({ type: `${pluralize_1.default(model)}/remove`, payload: id });
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 } });
61
50
  }
62
- delete patchQueue[idx];
63
- idx++;
51
+ delete patchQueue[model][idx[model]];
52
+ idx[model]++;
64
53
  updateDeadline = null;
65
- processQueue();
54
+ processQueue(model);
66
55
  // If there are updates in the queue that are ahead of the index, some have arrived out of order
67
56
  // Set a deadline for new updates before it declares the update missing and refetches.
68
57
  }
69
- else if (lodash_1.default.keys(patchQueue).length > 0 && !updateDeadline) {
58
+ else if (lodash_1.default.keys(patchQueue[model]).length > 0 && !updateDeadline) {
70
59
  var t = new Date();
71
60
  t.setSeconds(t.getSeconds() + 3);
72
61
  updateDeadline = t;
73
- setTimeout(processQueue, 3100);
62
+ setTimeout(() => processQueue(model), 3100);
74
63
  // If more than 10 updates in queue, or deadline has passed, restart
75
64
  }
76
- 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)) {
77
66
  tGetPayload();
78
67
  updateDeadline = null;
79
68
  }
80
69
  }
81
70
  function handlePayload(data) {
82
- const { value, idx: newIdx, diff, latency, type } = data;
83
- console.log({ data });
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] || {};
84
75
  if (type === 'payload') {
85
- if (!value)
86
- return null;
87
- payload = value;
88
- dispatchPayload();
89
- idx = newIdx + 1;
76
+ idx[model] = newIdx;
90
77
  // Clear any old changes left in the queue
91
- patchQueue = lodash_1.default.pick(patchQueue, lodash_1.default.keys(patchQueue).filter(k => k > newIdx + 1));
92
- return;
78
+ patchQueue[model] = lodash_1.default.pick(patchQueue[model], lodash_1.default.keys(patchQueue[model]).filter(k => k > newIdx + 1));
93
79
  }
94
- patchQueue[newIdx] = diff;
95
- processQueue();
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);
96
83
  if (diffSeconds((new Date()), lastCheckAt) >= 3) {
97
84
  lastCheckAt = new Date();
98
- console.log('Interval lost. Pulling from server');
85
+ console.debug('Interval lost. Pulling from server');
99
86
  tGetPayload();
100
87
  }
101
88
  }
89
+ tGetPayload();
102
90
  return handlePayload;
103
91
  }
104
92
  exports.default = createPayloadHandler;