jason-rails 0.6.8 → 0.7.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +34 -0
  3. data/Gemfile.lock +5 -3
  4. data/README.md +20 -14
  5. data/app/controllers/jason/jason_controller.rb +26 -4
  6. data/app/workers/jason/outbound_message_queue_worker.rb +1 -1
  7. data/client/lib/JasonProvider.d.ts +3 -1
  8. data/client/lib/JasonProvider.js +2 -2
  9. data/client/lib/addRelations.d.ts +1 -0
  10. data/client/lib/addRelations.js +39 -0
  11. data/client/lib/createJasonReducers.js +4 -2
  12. data/client/lib/createOptDis.d.ts +1 -1
  13. data/client/lib/createOptDis.js +9 -8
  14. data/client/lib/createServerActionQueue.d.ts +3 -2
  15. data/client/lib/createServerActionQueue.js +32 -6
  16. data/client/lib/createServerActionQueue.test.js +61 -6
  17. data/client/lib/createThenable.d.ts +1 -0
  18. data/client/lib/createThenable.js +5 -0
  19. data/client/lib/createTransportAdapter.d.ts +1 -1
  20. data/client/lib/createTransportAdapter.js +2 -2
  21. data/client/lib/index.d.ts +8 -1
  22. data/client/lib/index.js +3 -1
  23. data/client/lib/transportAdapters/actionCableAdapter.d.ts +1 -1
  24. data/client/lib/transportAdapters/actionCableAdapter.js +27 -6
  25. data/client/lib/transportAdapters/pusherAdapter.js +1 -1
  26. data/client/lib/useDraft.d.ts +1 -0
  27. data/client/lib/useDraft.js +13 -0
  28. data/client/lib/useEager.d.ts +1 -1
  29. data/client/lib/useEager.js +10 -5
  30. data/client/lib/useJason.d.ts +3 -1
  31. data/client/lib/useJason.js +4 -7
  32. data/client/package.json +1 -1
  33. data/client/src/JasonProvider.tsx +2 -2
  34. data/client/src/addRelations.ts +33 -0
  35. data/client/src/createJasonReducers.ts +4 -2
  36. data/client/src/createOptDis.ts +10 -8
  37. data/client/src/createServerActionQueue.test.ts +60 -6
  38. data/client/src/createServerActionQueue.ts +41 -6
  39. data/client/src/createTransportAdapter.ts +2 -2
  40. data/client/src/index.ts +2 -0
  41. data/client/src/transportAdapters/actionCableAdapter.ts +28 -7
  42. data/client/src/transportAdapters/pusherAdapter.ts +1 -2
  43. data/client/src/useDraft.ts +17 -0
  44. data/client/src/useEager.ts +9 -6
  45. data/client/src/useJason.ts +10 -7
  46. data/lib/jason.rb +9 -2
  47. data/lib/jason/api_model.rb +0 -4
  48. data/lib/jason/channel.rb +0 -7
  49. data/lib/jason/conditions_matcher.rb +88 -0
  50. data/lib/jason/consistency_checker.rb +65 -0
  51. data/lib/jason/graph_helper.rb +4 -0
  52. data/lib/jason/publisher.rb +36 -36
  53. data/lib/jason/subscription.rb +51 -15
  54. data/lib/jason/version.rb +1 -1
  55. metadata +12 -5
  56. data/client/src/makeEager.ts +0 -46
  57. data/lib/jason/publisher_old.rb +0 -112
  58. data/lib/jason/subscription_old.rb +0 -171
@@ -0,0 +1 @@
1
+ export default function createThenable(): void;
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ function createThenable() {
4
+ }
5
+ exports.default = createThenable;
@@ -1,4 +1,4 @@
1
- export default function createTransportAdapter(jasonConfig: any, handlePayload: any, dispatch: any, onConnect: any): {
1
+ export default function createTransportAdapter(jasonConfig: any, handlePayload: any, dispatch: any, onConnect: any, transportOptions: any): {
2
2
  getPayload: (config: any, options: any) => void;
3
3
  createSubscription: (config: any) => void;
4
4
  removeSubscription: (config: any) => void;
@@ -5,10 +5,10 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  const actionCableAdapter_1 = __importDefault(require("./transportAdapters/actionCableAdapter"));
7
7
  const pusherAdapter_1 = __importDefault(require("./transportAdapters/pusherAdapter"));
8
- function createTransportAdapter(jasonConfig, handlePayload, dispatch, onConnect) {
8
+ function createTransportAdapter(jasonConfig, handlePayload, dispatch, onConnect, transportOptions) {
9
9
  const { transportService } = jasonConfig;
10
10
  if (transportService === 'action_cable') {
11
- return actionCableAdapter_1.default(jasonConfig, handlePayload, dispatch, onConnect);
11
+ return actionCableAdapter_1.default(jasonConfig, handlePayload, dispatch, onConnect, transportOptions);
12
12
  }
13
13
  else if (transportService === 'pusher') {
14
14
  return pusherAdapter_1.default(jasonConfig, handlePayload, dispatch);
@@ -2,10 +2,17 @@
2
2
  import _useAct from './useAct';
3
3
  import _useSub from './useSub';
4
4
  import _useEager from './useEager';
5
- export declare const JasonProvider: ({ reducers, middleware, extraActions, children }: {
5
+ export declare const JasonContext: import("react").Context<{
6
+ actions: any;
7
+ subscribe: null;
8
+ eager: (entity: any, id: any, relations: any) => void;
9
+ }>;
10
+ export declare const JasonProvider: ({ reducers, middleware, enhancers, extraActions, transportOptions, children }: {
6
11
  reducers?: any;
7
12
  middleware?: any;
13
+ enhancers?: any;
8
14
  extraActions?: any;
15
+ transportOptions?: any;
9
16
  children?: import("react").FC<{}> | undefined;
10
17
  }) => JSX.Element;
11
18
  export declare const useAct: typeof _useAct;
data/client/lib/index.js CHANGED
@@ -3,11 +3,13 @@ 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
- exports.useEager = exports.useSub = exports.useAct = exports.JasonProvider = void 0;
6
+ exports.useEager = exports.useSub = exports.useAct = exports.JasonProvider = exports.JasonContext = void 0;
7
+ const JasonContext_1 = __importDefault(require("./JasonContext"));
7
8
  const JasonProvider_1 = __importDefault(require("./JasonProvider"));
8
9
  const useAct_1 = __importDefault(require("./useAct"));
9
10
  const useSub_1 = __importDefault(require("./useSub"));
10
11
  const useEager_1 = __importDefault(require("./useEager"));
12
+ exports.JasonContext = JasonContext_1.default;
11
13
  exports.JasonProvider = JasonProvider_1.default;
12
14
  exports.useAct = useAct_1.default;
13
15
  exports.useSub = useSub_1.default;
@@ -1,4 +1,4 @@
1
- export default function actionCableAdapter(jasonConfig: any, handlePayload: any, dispatch: any, onConnected: any): {
1
+ export default function actionCableAdapter(jasonConfig: any, handlePayload: any, dispatch: any, onConnected: any, transportOptions: any): {
2
2
  getPayload: (config: any, options: any) => void;
3
3
  createSubscription: (config: any) => void;
4
4
  removeSubscription: (config: any) => void;
@@ -1,8 +1,16 @@
1
1
  "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
2
5
  Object.defineProperty(exports, "__esModule", { value: true });
3
6
  const actioncable_1 = require("@rails/actioncable");
4
- function actionCableAdapter(jasonConfig, handlePayload, dispatch, onConnected) {
5
- const consumer = actioncable_1.createConsumer();
7
+ const restClient_1 = __importDefault(require("../restClient"));
8
+ const uuid_1 = require("uuid");
9
+ const lodash_1 = __importDefault(require("lodash"));
10
+ function actionCableAdapter(jasonConfig, handlePayload, dispatch, onConnected, transportOptions) {
11
+ const consumerId = uuid_1.v4();
12
+ const { cableUrl } = transportOptions;
13
+ const consumer = cableUrl ? actioncable_1.createConsumer(cableUrl) : actioncable_1.createConsumer();
6
14
  const subscription = (consumer.subscriptions.create({
7
15
  channel: 'Jason::Channel'
8
16
  }, {
@@ -21,14 +29,27 @@ function actionCableAdapter(jasonConfig, handlePayload, dispatch, onConnected) {
21
29
  console.warn('Disconnected from ActionCable');
22
30
  }
23
31
  }));
24
- function getPayload(config, options) {
25
- subscription.send(Object.assign({ getPayload: config }, options));
26
- }
27
32
  function createSubscription(config) {
28
33
  subscription.send({ createSubscription: config });
29
34
  }
30
35
  function removeSubscription(config) {
31
- subscription.send({ removeSubscription: config });
36
+ restClient_1.default.post('/jason/api/remove_subscription', { config, consumerId })
37
+ .catch(e => console.error(e));
38
+ }
39
+ function getPayload(config, options) {
40
+ restClient_1.default.post('/jason/api/get_payload', {
41
+ config,
42
+ options
43
+ })
44
+ .then(({ data }) => {
45
+ lodash_1.default.map(data, (payload, modelName) => {
46
+ handlePayload(payload);
47
+ });
48
+ })
49
+ .catch(e => console.error(e));
50
+ }
51
+ function fullChannelName(channelName) {
52
+ return channelName;
32
53
  }
33
54
  return { getPayload, createSubscription, removeSubscription };
34
55
  }
@@ -8,7 +8,7 @@ const restClient_1 = __importDefault(require("../restClient"));
8
8
  const uuid_1 = require("uuid");
9
9
  const lodash_1 = __importDefault(require("lodash"));
10
10
  function pusherAdapter(jasonConfig, handlePayload, dispatch) {
11
- let consumerId = uuid_1.v4();
11
+ const consumerId = uuid_1.v4();
12
12
  const { pusherKey, pusherRegion, pusherChannelPrefix } = jasonConfig;
13
13
  const pusher = new pusher_js_1.default(pusherKey, {
14
14
  cluster: 'eu',
@@ -0,0 +1 @@
1
+ export default function useDraft(entity: any, id: any, relations?: never[]): void;
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ /* Can be called as
4
+ useDraft() => draft object for making updates
5
+ useDraft('entity', id) => returns [draft, object]
6
+ useDraft('entity', id, relations) => returns [draft, objectWithEmbeddedRelations]
7
+ */
8
+ function useDraft(entity, id, relations = []) {
9
+ // const entityDraft =`${entity}Draft`
10
+ // const object = { ...s[entityDraft].entities[String(id)] }
11
+ // return useSelector(s => addRelations(s, object, entity, relations, 'Draft'), _.isEqual)
12
+ }
13
+ exports.default = useDraft;
@@ -1 +1 @@
1
- export default function useEager(entity: any, id?: null, relations?: never[]): void;
1
+ export default function useEager(entity: string, id?: string, relations?: any): any;
@@ -3,10 +3,15 @@ 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 JasonContext_1 = __importDefault(require("./JasonContext"));
7
- const react_1 = require("react");
8
- function useEager(entity, id = null, relations = []) {
9
- const { eager } = react_1.useContext(JasonContext_1.default);
10
- return eager(entity, id, relations);
6
+ const lodash_1 = __importDefault(require("lodash"));
7
+ const react_redux_1 = require("react-redux");
8
+ const addRelations_1 = __importDefault(require("./addRelations"));
9
+ function useEager(entity, id = '', relations = []) {
10
+ if (id) {
11
+ return react_redux_1.useSelector(s => addRelations_1.default(s, Object.assign({}, s[entity].entities[String(id)]), entity, relations), lodash_1.default.isEqual);
12
+ }
13
+ else {
14
+ return react_redux_1.useSelector(s => addRelations_1.default(s, lodash_1.default.values(s[entity].entities), entity, relations), lodash_1.default.isEqual);
15
+ }
11
16
  }
12
17
  exports.default = useEager;
@@ -1,5 +1,7 @@
1
- export default function useJason({ reducers, middleware, extraActions }: {
1
+ export default function useJason({ reducers, middleware, enhancers, transportOptions, extraActions }: {
2
2
  reducers?: any;
3
3
  middleware?: any[];
4
+ enhancers?: any[];
4
5
  extraActions?: any;
6
+ transportOptions?: any;
5
7
  }): any[];
@@ -12,12 +12,11 @@ const restClient_1 = __importDefault(require("./restClient"));
12
12
  const pruneIdsMiddleware_1 = __importDefault(require("./pruneIdsMiddleware"));
13
13
  const createTransportAdapter_1 = __importDefault(require("./createTransportAdapter"));
14
14
  const toolkit_1 = require("@reduxjs/toolkit");
15
- const makeEager_1 = __importDefault(require("./makeEager"));
16
15
  const humps_1 = require("humps");
17
16
  const blueimp_md5_1 = __importDefault(require("blueimp-md5"));
18
17
  const lodash_1 = __importDefault(require("lodash"));
19
18
  const react_1 = require("react");
20
- function useJason({ reducers, middleware = [], extraActions }) {
19
+ function useJason({ reducers, middleware = [], enhancers = [], transportOptions = {}, extraActions }) {
21
20
  const [store, setStore] = react_1.useState(null);
22
21
  const [value, setValue] = react_1.useState(null);
23
22
  react_1.useEffect(() => {
@@ -29,17 +28,16 @@ function useJason({ reducers, middleware = [], extraActions }) {
29
28
  const serverActionQueue = createServerActionQueue_1.default();
30
29
  const allReducers = Object.assign(Object.assign({}, reducers), createJasonReducers_1.default(schema));
31
30
  console.debug({ allReducers });
32
- const store = toolkit_1.configureStore({ reducer: allReducers, middleware: [...middleware, pruneIdsMiddleware_1.default(schema)] });
31
+ const store = toolkit_1.configureStore({ reducer: allReducers, middleware: [...middleware, pruneIdsMiddleware_1.default(schema)], enhancers });
33
32
  const dispatch = store.dispatch;
34
33
  const optDis = createOptDis_1.default(schema, dispatch, restClient_1.default, serverActionQueue);
35
34
  const actions = createActions_1.default(schema, store, restClient_1.default, optDis, extraActions);
36
- const eager = makeEager_1.default(schema);
37
35
  let payloadHandlers = {};
38
36
  let configs = {};
39
37
  let subOptions = {};
40
38
  function handlePayload(payload) {
41
39
  const { md5Hash } = payload;
42
- const { handlePayload } = payloadHandlers[md5Hash];
40
+ const { handlePayload } = payloadHandlers[md5Hash] || {};
43
41
  if (handlePayload) {
44
42
  handlePayload(payload);
45
43
  }
@@ -47,7 +45,7 @@ function useJason({ reducers, middleware = [], extraActions }) {
47
45
  console.warn("Payload arrived with no handler", payload, payloadHandlers);
48
46
  }
49
47
  }
50
- const transportAdapter = createTransportAdapter_1.default(jasonConfig, handlePayload, dispatch, () => lodash_1.default.keys(configs).forEach(md5Hash => createSubscription(configs[md5Hash], subOptions[md5Hash])));
48
+ const transportAdapter = createTransportAdapter_1.default(jasonConfig, handlePayload, dispatch, () => lodash_1.default.keys(configs).forEach(md5Hash => createSubscription(configs[md5Hash], subOptions[md5Hash])), transportOptions);
51
49
  function createSubscription(config, options = {}) {
52
50
  // We need the hash to be consistent in Ruby / Javascript
53
51
  const hashableConfig = lodash_1.default(Object.assign({ conditions: {}, includes: {} }, config)).toPairs().sortBy(0).fromPairs().value();
@@ -84,7 +82,6 @@ function useJason({ reducers, middleware = [], extraActions }) {
84
82
  setValue({
85
83
  actions: actions,
86
84
  subscribe: createSubscription,
87
- eager,
88
85
  handlePayload
89
86
  });
90
87
  setStore(store);
data/client/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jamesr2323/jason",
3
- "version": "0.6.7",
3
+ "version": "0.7.4",
4
4
  "module": "./lib/index.js",
5
5
  "types": "./lib/index.d.ts",
6
6
  "scripts": {
@@ -3,8 +3,8 @@ import useJason from './useJason'
3
3
  import { Provider } from 'react-redux'
4
4
  import JasonContext from './JasonContext'
5
5
 
6
- const JasonProvider = ({ reducers, middleware, extraActions, children }: { reducers?: any, middleware?: any, extraActions?: any, children?: React.FC }) => {
7
- const [store, value] = useJason({ reducers, middleware, extraActions })
6
+ const JasonProvider = ({ reducers, middleware, enhancers, extraActions, transportOptions = {}, children }: { reducers?: any, middleware?: any, enhancers?: any, extraActions?: any, transportOptions?: any, children?: React.FC }) => {
7
+ const [store, value] = useJason({ reducers, middleware, enhancers, extraActions, transportOptions })
8
8
 
9
9
  if(!(store && value)) return <div /> // Wait for async fetch of schema to complete
10
10
 
@@ -0,0 +1,33 @@
1
+ import pluralize from 'pluralize'
2
+ import _ from 'lodash'
3
+
4
+ export default function addRelations(s, objects, objectType, relations, suffix = '') {
5
+ // first find out relation name
6
+ if (_.isArray(relations)) {
7
+ relations.forEach(relation => {
8
+ objects = addRelations(s, objects, objectType, relation)
9
+ })
10
+ } else if (typeof(relations) === 'object') {
11
+ const relation = Object.keys(relations)[0]
12
+ const subRelations = relations[relation]
13
+
14
+ objects = addRelations(s, objects, objectType, relation)
15
+ objects[relation] = addRelations(s, objects[relation], pluralize(relation), subRelations)
16
+ // #
17
+ } else if (typeof(relations) === 'string') {
18
+ const relation = relations
19
+ if (_.isArray(objects)) {
20
+ objects = objects.map(obj => addRelations(s, obj, objectType, relation))
21
+ } else if (_.isObject(objects)) {
22
+ const relatedObjects = _.values(s[pluralize(relation) + suffix].entities)
23
+
24
+ if(pluralize.isSingular(relation)) {
25
+ objects = { ...objects, [relation]: _.find(relatedObjects, { id: objects[relation + 'Id'] }) }
26
+ } else {
27
+ objects = { ...objects, [relation]: relatedObjects.filter(e => e[pluralize.singular(objectType) + 'Id'] === objects.id) }
28
+ }
29
+ }
30
+ }
31
+
32
+ return objects
33
+ }
@@ -3,7 +3,8 @@ import pluralize from 'pluralize'
3
3
  import _ from 'lodash'
4
4
 
5
5
  function generateSlices(models) {
6
- const sliceNames = models.map(k => pluralize(k))
6
+ // create two slices for each model. One to hold the persisted data, and one to hold draft data
7
+ const sliceNames = models.map(k => pluralize(k)).concat(models.map(k => `${pluralize(k)}Drafts`))
7
8
  const adapter = createEntityAdapter()
8
9
 
9
10
  return _.fromPairs(_.map(sliceNames, name => {
@@ -67,7 +68,8 @@ function generateJasonSlices(models) {
67
68
  name: 'jason',
68
69
  initialState: {
69
70
  connected: false,
70
- queueSize: 0
71
+ queueSize: 0,
72
+ error: null
71
73
  },
72
74
  reducers: {
73
75
  upsert: (s,a) => ({ ...s, ...a.payload })
@@ -15,18 +15,20 @@ export default function createOptDis(schema, dispatch, restClient, serverActionQ
15
15
  const plurals = _.keys(schema).map(k => pluralize(k))
16
16
 
17
17
  function enqueueServerAction (action) {
18
- serverActionQueue.addItem(action)
18
+ return serverActionQueue.addItem(action)
19
19
  }
20
20
 
21
21
  function dispatchServerAction() {
22
- const action = serverActionQueue.getItem()
23
- if (!action) return
22
+ const item = serverActionQueue.getItem()
23
+ if (!item) return
24
+
25
+ const { id, action } = item
24
26
 
25
27
  restClient.post('/jason/api/action', action)
26
- .then(serverActionQueue.itemProcessed)
27
- .catch(e => {
28
- dispatch({ type: 'upsertLocalUi', data: { error: JSON.stringify(e) } })
29
- serverActionQueue.itemProcessed()
28
+ .then(({ data }) => serverActionQueue.itemProcessed(id, data))
29
+ .catch(error => {
30
+ dispatch({ type: 'jason/upsert', payload: { error } })
31
+ serverActionQueue.itemFailed(id, error)
30
32
  })
31
33
  }
32
34
 
@@ -39,7 +41,7 @@ export default function createOptDis(schema, dispatch, restClient, serverActionQ
39
41
  dispatch({ type, payload: data })
40
42
 
41
43
  if (plurals.indexOf(type.split('/')[0]) > -1) {
42
- enqueueServerAction({ type, payload: data })
44
+ return enqueueServerAction({ type, payload: data })
43
45
  }
44
46
  }
45
47
  }
@@ -4,7 +4,7 @@ test('Adding items', () => {
4
4
  const serverActionQueue = createServerActionQueue()
5
5
  serverActionQueue.addItem({ type: 'entity/add', payload: { id: 'abc', attribute: 1 } })
6
6
  const item = serverActionQueue.getItem()
7
- expect(item).toStrictEqual({ type: 'entity/add', payload: { id: 'abc', attribute: 1 } })
7
+ expect(item.action).toStrictEqual({ type: 'entity/add', payload: { id: 'abc', attribute: 1 } })
8
8
  })
9
9
 
10
10
  test('Deduping of items that will overwrite each other', () => {
@@ -15,7 +15,7 @@ test('Deduping of items that will overwrite each other', () => {
15
15
 
16
16
  const item = serverActionQueue.getItem()
17
17
 
18
- expect(item).toStrictEqual({ type: 'entity/upsert', payload: { id: 'abc', attribute: 3 } })
18
+ expect(item.action).toStrictEqual({ type: 'entity/upsert', payload: { id: 'abc', attribute: 3 } })
19
19
  })
20
20
 
21
21
  test('Deduping of items with a superset', () => {
@@ -25,7 +25,7 @@ test('Deduping of items with a superset', () => {
25
25
 
26
26
  const item = serverActionQueue.getItem()
27
27
 
28
- expect(item).toStrictEqual({ type: 'entity/upsert', payload: { id: 'abc', attribute: 2, attribute2: 'test' } })
28
+ expect(item.action).toStrictEqual({ type: 'entity/upsert', payload: { id: 'abc', attribute: 2, attribute2: 'test' } })
29
29
  })
30
30
 
31
31
  test("doesn't dedupe items with some attributes missing", () => {
@@ -34,9 +34,63 @@ test("doesn't dedupe items with some attributes missing", () => {
34
34
  serverActionQueue.addItem({ type: 'entity/upsert', payload: { id: 'abc', attribute2: 'test' } })
35
35
 
36
36
  const item = serverActionQueue.getItem()
37
- serverActionQueue.itemProcessed()
37
+ serverActionQueue.itemProcessed(item.id)
38
38
  const item2 = serverActionQueue.getItem()
39
39
 
40
- expect(item).toStrictEqual({ type: 'entity/upsert', payload: { id: 'abc', attribute: 1 } })
41
- expect(item2).toStrictEqual({ type: 'entity/upsert', payload: { id: 'abc', attribute2: 'test' } })
40
+ expect(item.action).toStrictEqual({ type: 'entity/upsert', payload: { id: 'abc', attribute: 1 } })
41
+ expect(item2.action).toStrictEqual({ type: 'entity/upsert', payload: { id: 'abc', attribute2: 'test' } })
42
42
  })
43
+
44
+ test("executes success callback", async function() {
45
+ const serverActionQueue = createServerActionQueue()
46
+ let cb = ''
47
+ let data = ''
48
+
49
+ // Check it can resolve chained promises
50
+ const promise = serverActionQueue.addItem({ type: 'entity/upsert', payload: { id: 'abc', attribute: 1 } })
51
+ .then(d => data = d)
52
+ .then(() => cb = 'resolved')
53
+
54
+ const item = serverActionQueue.getItem()
55
+ serverActionQueue.itemProcessed(item.id, 'testdata');
56
+
57
+ await promise
58
+ expect(data).toEqual('testdata')
59
+ expect(cb).toEqual('resolved')
60
+ })
61
+
62
+ test("executes error callback", async function() {
63
+ const serverActionQueue = createServerActionQueue()
64
+ let cb = ''
65
+ let error = ''
66
+
67
+ // Check it can resolve chained promises
68
+ const promise = serverActionQueue.addItem({ type: 'entity/upsert', payload: { id: 'abc', attribute: 1 } })
69
+ .then(() => cb = 'resolved')
70
+ .catch(e => error = e)
71
+
72
+ const item = serverActionQueue.getItem()
73
+ serverActionQueue.itemFailed(item.id, 'testerror');
74
+
75
+ await promise
76
+ expect(cb).toEqual('')
77
+ expect(error).toEqual('testerror')
78
+ })
79
+
80
+
81
+ test("merges success callbacks", async function() {
82
+ const results: any[] = []
83
+
84
+ const serverActionQueue = createServerActionQueue()
85
+ const p1 = serverActionQueue.addItem({ type: 'entity/upsert', payload: { id: 'abc', attribute: 1 } })
86
+ .then(data => results.push(data))
87
+
88
+ const p2 = serverActionQueue.addItem({ type: 'entity/upsert', payload: { id: 'abc', attribute: 2, attribute2: 'test' } })
89
+ .then(data => results.push(data))
90
+
91
+ const item = serverActionQueue.getItem()
92
+ serverActionQueue.itemProcessed(item.id, 'complete')
93
+
94
+ await Promise.all([p1,p2])
95
+ expect(results).toEqual(['complete', 'complete'])
96
+ })