-
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
249 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
import { expect, test, describe } from 'vitest'; | ||
import { createStore, createEvent, sample } from 'effector'; | ||
import { model, keyval, define, lens } from '@effector/model'; | ||
|
||
function createUpdatableEntities( | ||
fill?: Array<{ id: string; count: number; tag: string }>, | ||
) { | ||
const entities = keyval({ | ||
getKey: 'id', | ||
model: model({ | ||
props: { | ||
id: define.store<string>(), | ||
count: define.store<number>(), | ||
tag: define.store<string>(), | ||
}, | ||
create() { | ||
return {}; | ||
}, | ||
}), | ||
}); | ||
if (fill) { | ||
entities.edit.add(fill); | ||
} | ||
return entities; | ||
} | ||
|
||
describe('lens read value of field in keyval', () => { | ||
test('with store', () => { | ||
const entities = createUpdatableEntities([ | ||
{ id: 'foo', count: 0, tag: 'x' }, | ||
{ id: 'bar', count: 0, tag: 'y' }, | ||
{ id: 'baz', count: 0, tag: 'z' }, | ||
]); | ||
|
||
const $currentKey = createStore('bar'); | ||
|
||
const $currentTag = lens(entities, $currentKey).tag.store; | ||
expect($currentTag.getState()).toBe('y'); | ||
}); | ||
test('with constant', () => { | ||
const entities = createUpdatableEntities([ | ||
{ id: 'foo', count: 0, tag: 'x' }, | ||
{ id: 'bar', count: 0, tag: 'y' }, | ||
]); | ||
|
||
const $currentTag = lens(entities, 'bar').tag.store; | ||
expect($currentTag.getState()).toBe('y'); | ||
}); | ||
}); | ||
|
||
test('lens store change value when entity changed', () => { | ||
const entities = createUpdatableEntities([ | ||
{ id: 'foo', count: 0, tag: 'x' }, | ||
{ id: 'bar', count: 0, tag: 'y' }, | ||
]); | ||
|
||
const $currentTag = lens(entities, 'bar').tag.store; | ||
expect($currentTag.getState()).toBe('y'); | ||
|
||
entities.edit.update({ id: 'bar', tag: 'z' }); | ||
expect($currentTag.getState()).toBe('z'); | ||
}); | ||
|
||
test('lens store change value when key changed', () => { | ||
const entities = createUpdatableEntities([ | ||
{ id: 'foo', count: 0, tag: 'x' }, | ||
{ id: 'bar', count: 0, tag: 'y' }, | ||
]); | ||
|
||
const changeKey = createEvent<string>(); | ||
const $currentKey = createStore('bar'); | ||
sample({ clock: changeKey, target: $currentKey }); | ||
|
||
const $currentTag = lens(entities, $currentKey).tag.store; | ||
expect($currentTag.getState()).toBe('y'); | ||
|
||
changeKey('foo'); | ||
expect($currentTag.getState()).toBe('x'); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,94 @@ | ||
import { Keyval, KeyStore } from './types'; | ||
import { combine, Store } from 'effector'; | ||
import { Keyval, KeyStore, LensStore, LensEvent, StructKeyval } from './types'; | ||
|
||
type PathDecl = | ||
| { | ||
type: 'index'; | ||
/** position of index value in path itself */ | ||
pathIndex: number; | ||
} | ||
| { | ||
type: 'field'; | ||
value: string; | ||
}; | ||
|
||
function createLensStruct( | ||
struct: StructKeyval, | ||
pathDecl: PathDecl[], | ||
path: Array<KeyStore | string | number>, | ||
items: Store<any[]>, | ||
) { | ||
const shape = {} as any; | ||
for (const key in struct.shape) { | ||
const item = struct.shape[key]; | ||
if (item.type === 'structUnit') { | ||
switch (item.unit) { | ||
case 'store': { | ||
const $value = combine( | ||
[items, ...path], | ||
([items, ...pathKeysRaw]) => { | ||
const pathKeys = pathKeysRaw as Array<string | number>; | ||
let value: any = items; | ||
for (const segment of pathDecl) { | ||
if (value === undefined) return undefined; | ||
switch (segment.type) { | ||
case 'index': { | ||
const id = pathKeys[segment.pathIndex]; | ||
value = value.find((e: any) => struct.getKey(e) === id); | ||
break; | ||
} | ||
case 'field': { | ||
value = value[segment.value]; | ||
break; | ||
} | ||
} | ||
} | ||
return value?.[key]; | ||
}, | ||
); | ||
shape[key] = { | ||
__type: 'lensStore', | ||
store: $value, | ||
} as LensStore<any>; | ||
break; | ||
} | ||
case 'event': { | ||
shape[key] = { | ||
__type: 'lensEvent', | ||
__value: null, | ||
} as LensEvent<any>; | ||
break; | ||
} | ||
case 'effect': { | ||
console.error('effects are not supported in lens'); | ||
break; | ||
} | ||
} | ||
} else { | ||
shape[key] = (childKey: KeyStore | string | number) => | ||
createLensStruct( | ||
item, | ||
[ | ||
...pathDecl, | ||
{ type: 'field', value: key }, | ||
{ type: 'index', pathIndex: path.length }, | ||
], | ||
[...path, childKey], | ||
items, | ||
); | ||
} | ||
} | ||
return shape; | ||
} | ||
|
||
export function lens<Shape>( | ||
keyval: Keyval<any, any, any, Shape>, | ||
key: KeyStore, | ||
) { | ||
return keyval.__lens; | ||
key: KeyStore | string | number, | ||
): Shape { | ||
return createLensStruct( | ||
keyval.__struct, | ||
[{ type: 'index', pathIndex: 0 }], | ||
[key], | ||
keyval.$items, | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters