From 51421c1052322fb19aebfb60ffa2962682662d39 Mon Sep 17 00:00:00 2001 From: Yanick Champoux Date: Tue, 30 Aug 2022 10:09:24 -0400 Subject: [PATCH] adding the findSelectors --- src/Updux.js | 2 +- src/dux-selectors.test.js | 47 ++++++++++++++++++++++++++++++++++++++- src/selectors.js | 22 ++++++++++-------- src/utils.js | 6 +++++ 4 files changed, 66 insertions(+), 11 deletions(-) create mode 100644 src/utils.js diff --git a/src/Updux.js b/src/Updux.js index 5eb76b3..b0407d3 100644 --- a/src/Updux.js +++ b/src/Updux.js @@ -40,7 +40,7 @@ export class Updux { this.#selectors = buildSelectors( config.selectors, - config.splatSelectors, + config.findSelectors, this.#subduxes, ); diff --git a/src/dux-selectors.test.js b/src/dux-selectors.test.js index 5ddbd5c..011b796 100644 --- a/src/dux-selectors.test.js +++ b/src/dux-selectors.test.js @@ -1,6 +1,8 @@ import { test, expect } from 'vitest'; +import R from 'remeda'; -import { dux } from './Updux.js'; +import { dux, Updux } from './Updux.js'; +import { matches } from './utils.js'; test('basic selectors', () => { const foo = dux({ @@ -22,3 +24,46 @@ test('basic selectors', () => { expect(foo.selectors.getY({ bar: { y: 3 } })).toBe(3); }); + +test('splat selector', async () => { + const bar = new Updux({ + initial: { id: 0, label: '' }, + selectors: { + getLabel: R.prop('label'), + getLabelAppended: (state) => (suffix) => state.label + ' ' + suffix, + }, + }); + + const foo = new Updux({ + initial: [], + findSelectors: { + getBar: (state) => (id) => { + return state.find(matches({ id })); + }, + }, + selectors: { + getNbrBars: (state) => state.length, + }, + subduxes: { + '*': bar, + }, + }); + + const state = [ + { id: 1, label: 'one' }, + { id: 2, label: 'two' }, + ]; + + const store = foo.createStore(state); + + expect(foo.selectors.getBar(state)(2).state).toMatchObject(state[1]); + expect(store.getState.getBar(2).state).toMatchObject(state[1]); + + expect(store.getState.getNbrBars()).toBe(2); + + expect(store.getState.getBar(1).getLabel()).toEqual('one'); + + expect(store.getState.getBar(1).getLabelAppended('plus one')).toEqual( + 'one plus one', + ); +}); diff --git a/src/selectors.js b/src/selectors.js index 00af786..69f73e2 100644 --- a/src/selectors.js +++ b/src/selectors.js @@ -2,7 +2,7 @@ import R from 'remeda'; export function buildSelectors( localSelectors, - splatSelector = {}, + findSelectors = {}, subduxes = {}, ) { const subSelectors = Object.entries(subduxes).map( @@ -19,18 +19,22 @@ export function buildSelectors( let splat = {}; - for (const name in splatSelector) { + for (const name in findSelectors) { splat[name] = - (state) => + (mainState) => (...args) => { - const value = splatSelector[name](state)(...args); + const state = findSelectors[name](mainState)(...args); - const res = () => value; - return merge( - res, - mapValues( + return R.merge( + { state }, + R.mapValues( subduxes['*'].selectors, - (selector) => () => selector(value), + (selector) => + (...args) => { + let value = selector(state); + if (typeof value !== 'function') return value; + return value(...args); + }, ), ); }; diff --git a/src/utils.js b/src/utils.js new file mode 100644 index 0000000..956a5ff --- /dev/null +++ b/src/utils.js @@ -0,0 +1,6 @@ +export const matches = (conditions) => (target) => + Object.entries(conditions).every(([key, value]) => + typeof value === 'function' + ? value(target[key]) + : target[key] === value, + );