Skip to content
This repository has been archived by the owner on Jul 30, 2018. It is now read-only.

Shaping/Transforming Data #7

Closed
kitsonk opened this issue Jul 15, 2016 · 4 comments
Closed

Shaping/Transforming Data #7

kitsonk opened this issue Jul 15, 2016 · 4 comments

Comments

@kitsonk
Copy link
Member

kitsonk commented Jul 15, 2016

This is an Epic issue which originally came out of the identification that the process of mutating application state and business data state was a highly "manual" process in TodoMVC and that we clearly needed a way to express the logic necessary to take business objects and have that populate application state.

At a high level, take this use case for example:

  • We have a list of todo items that are persisted somewhere and we need to build an application that allows a user to interact with those items. The items are available as a RESTful collection at /todoitems/.
  • We provide an interface to those items via a RESTful dojo-store.
  • We then need to query those items that apply to our logged in user from that store.
  • We then need to transform the resulting set of items into into several instances of widget state:
    • We need to identify the count of todo items
    • We need to identify the count of completed todo items
    • For each todo item, we need to have a widget state that conforms to the state of a TodoItemWidget and have those states be children of a TodoItemList
  • Once we have transformed our data we need to materialise it in the appropriate application state stores so that the dojo-app instance can ensure that the application properly represents the underling business sate.
  • When there is a mutation to items in the RESTful collection, we need to reflect those changes throughout the above cycle, so the application reacts to those changes.
@kitsonk kitsonk added this to the 2016.07 milestone Jul 19, 2016
@kitsonk kitsonk modified the milestones: 2016.07, 2016.08 Aug 1, 2016
@kitsonk
Copy link
Member Author

kitsonk commented Sep 6, 2016

Based on a conversation with @maier49 and @agubler here is what I see as the main "use case" for stores and widgets when operating in a Dojo 2 application:

diagram of data transform

Which the following describes the process:

  • Data is present in a business store.
  • That data is actively queried
  • Then that data is transformed (reshaped)
  • Then that data is materialised in two ways:
    • A widget state store, which contains the widget state
    • Managing instances of widgets which are wired to that widget state
  • The widgets are wired to actions which mutate the objects in the business store
  • Because the data is being actively queried, changes to the business store are reflected in the state of the widgets and their instances managed.

@agubler
Copy link
Member

agubler commented Sep 7, 2016

Will the user register a pipeline, .query(), .transform(), .materialize() that gets automatically called on the business store being updated? or will the the user need to include this in a subscription on the store?

@kitsonk
Copy link
Member Author

kitsonk commented Sep 7, 2016

My feeling was that a pipeline like that would imply that it is being tracked, as that would be the most common use case, with an options to produce it as a one off. I would expect .query() and .transform() to produce observables and .materialize() to return handle. Something like this:

const source = store
    .query({ /* query options */})
    .transform({ /* transform options */);

const target = createMemoryStore();

const handle = materialize({
    source,
    target,
    reducer(item, source, target): ChangeRecord | Promise<ChangeRecord> {
         /* do whatever */
    }
});

handle.destroy();

agubler added a commit to agubler/stores that referenced this issue Oct 11, 2016
agubler added a commit to agubler/stores that referenced this issue Oct 11, 2016
agubler pushed a commit that referenced this issue Oct 18, 2016
* Wipe out files for merging new stores.

* Starting work on new store

* Start conversion to use observables, and incorporate dojo-2-package template

* Compiles with Memory and Request Stores commented out - WIP

* Fix dependency issues with new version of grunt-dojo2

* Update some dependencies and fix folder case

* Fix capitalization, make interfaces default exports

* Refactoring

* Make Patches and Queries have two generic parameters to
express the original type as well as the resulting type.

* Create a CompoundQuery class to allow for any arbitrary
queries to be combined into a single query.

* Remove the second generic type in BaseStore. For the most
part, the type of the items in the store will not change
between the source and the subStore, so they can use the
same generic type.

If they did change types, in one case the
items could be mapped to a completely different type. In
this case updates can no longer happen by delegating to
the parent because there's no way to reverse engineer
the relationship between the items.

In the case where a selection or a similar operation has
been performed, it would be useful, but the direction of
the type relationship is contravariant. If the source has
Items of type {a: string, b: string}, the child would have
elements of either {a: string}, {a: string, b: string}, or
{b: string}. In any other case we have the problem mentioned
above. But in this case, the resulting item is a superclass
of the source store. Which means the signature for this
opertion would need to be something like
```
Store<A, B extends A> {
	source: Store<B>
	select<C extendedBy A>: Store<C, A>;
}
```
But we can't express that.

* Refactoring

* Add more options for serialization

* Move queries to their own package

* Add select query

* Change pointer add method to push, and add pop

* Change factory names to match compose pattern

* Fix testing configuration and dist build

* Add a few simple unit tests for sort.

* Add store 'actions', minor refactoring

* Change `type` in filter to `filterType`, query already
has a queryType so this is hopefully more
consistent/clearer.

* Add store 'actions'. They're not necessarily proper
actions but they express a similar pattern. They also,
with the StoreActionManager, form the start of an attempt
at handling conflicts and out of date data.

* Adding in "actions"

Store "Actions" are meant to wrap an update and allow for
 * Handling conflicts and other failures gracefully
 * Handle ordering of concurrent requests

* Use an observer instead of a promise for a single action's results

Using an observer instead of a promise for a single
action's result allows a lot of code passing promises
through to be eliminated. It also simplified the
interaction for an end user of the API, as retrying a
failed request repeatedly no longer requires a potentially
endless chain of promises.

* Implement memory store and add some unit tests for it

Also includes refactoring

* Adding tests - in a broken state

* More tests

* Minor changes to make code compile.

* Fix dojo dependency versions

* Add more unit tests

* Add another test for subcollections
* Start adding more detailed tests for each method

* bump peer deps to 'next' tag and config for UMD typings

* change deps to peer deps in line with dojo2 convention, add grunt task for peer deps

* update .gitignore for node_modules and .tsconfig*.json files

* implement 'noImplicitThis'

* Fix the build(compile) issue by switching back to previous working version of dependencies.

The tsc compile issue is cased by some issue in the `next` tag of `dojo-core` package. Until a more stable version of `dojo-core` is released,
we have to use previous working version for now.

* Add more unit tests for MemoryStore. Fix minor code issue.

Note: a few unit tests are still failing. Need to either update code to
pass the unit tests, or remove the tests if we feel the tests are making
wrong assumptions.

* Minor API change, fixes to Actions, add method, and tests

Action result 'errors' really represent data conflicts
only, as other errors will still be handled through the
error callback of the action. The relevant flag has been
renamed to better reflect that.

Action observers should only call `retryAll` or `filter`
synchronously within the callback, and if they are not an
appropriate error will be thrown. This is mainly so that
the observer can be completed if the action is not going to
be retried, by checking after its next callback whether
`retryAll` or `filter` was called on the result.

Actions now also throw appropriate errors when `retryAll` or
`filter` is called more than once on the same result object,
or on a successful result object.

`Add` now calls `put` on retry, as retrying an add means that
the item already exists but we want to update it anyway.

Changed tests to reflect that:
 * Adding an existing item should be considered a data
   conflict, but the action should be able to be retried,
   and in that case it should update the existing item.
 * When subscribing to the store's observable, an initial
   update should be received that indicates the state of the
   store at the time of subscription.

Fixes two other miscellaneous bugs:
 * `_add` in `MemoryStore` was adding all passed items to
   the store's data. Now it correctly only adds only the new
   items.
 * On retry, the action was being executed immediately
   instead of being queued.

* Add grunt watch task registered as the default task.

* Add unit tests around `store#fetch`.

The factory function `rangeFactory` is changed to `createRange` to be
consistent with the rest of application such as filter#createFilter etc.

* fix TS2 version and bump dojo deps (#7)

* Minor refactor and more tests

* Minor changes to update interface so that all updates can
optionally have an item or index property. This avoids a lot
of casting to different update types.

* Updates to track and release API so that they return a
promise to the store.

* Don't send out an initial update of current items when
observing the store. If using fetch, it's not performant,
and if not using fetch, the results can be surprising
because the local data may not be what is expected at
the time of observation.

* Getting rid of fat arrow functions to match dojo style
guide

* Making the order of actions more controllable via custom
store managers by adding a retry function. The default
manager currently just executes the next available action
asynchronously as soon as the current action executes once.
Any retries on that action are treated as new actions and
just queued normally. With the separate retry method an
action manager could be implemented that waits until the
current action is completed, including waiting for any
retries.

* Refactoring API and breaking out into separate compose mixins

* Separate query module into a mixin.

Use instance constructor as subcollection factory

Make observableStoreMixin subcollection aware

* Add more unit tests for query mixin

* Fix query mixin so it doesn't query recursively

* Adding track and release mixin - No tests yet

* Add unit tests from previous code.

Add unit tests for track mixin. (doesn't compile yet)

Add unit tests for Patch/JsonPointer.

* achieved 100% coverage.
* a few issues were caught and fixed.

* Interface cleanup and test case for trackable mixin

Fix ordering for operations and tracking.

Doesn't resolve the case where fetching occurs around the
operation.

* Add more test cases for and fix issues with operation ordering

* Split else onto a separate line

* Update readme

* Fix internal link in readme

* Really fix internal link in readme

* Add unit tests.

* Most modules has 100% coverage.
* Overall coverage is over 80%, while a few corner cases are not covered
yet.
* Fix a few issues caught by tests.
* Cleanup.

* Fix build issues.

* Comment out failing unit tests. See dojo/compose/#81 for details.

* Add missing all.ts to fix build issue.

* Switch back to previous version of compose, uncomment unit tests.

* Will update accordingly based on discussion in /dojo/compose/#81
* Attempt to fix build issue by adding `Rx.config.Promise`

* Fix build issues on IE 10/11 caused by unavailable functionality.

* Update IOS version due to issues with saucelabs environments.

* Update IOS version to 9.3 due to issues with saucelabs environments.

* Trigger Build. (Previous build #32 seems to hang for no reason.)

* Add more tests to cover more areas of logic.

* Feedback changes: package name and version etc.

* Move file into mixin dir.

* Add createTransactionMixin.

* Remove dtsGenerator grunt config

* Add tests for createTransactionMixin. Fix issues caught by tests.
agubler pushed a commit to agubler/stores that referenced this issue Oct 18, 2016
* Wipe out files for merging new stores.

* Starting work on new store

* Start conversion to use observables, and incorporate dojo-2-package template

* Compiles with Memory and Request Stores commented out - WIP

* Fix dependency issues with new version of grunt-dojo2

* Update some dependencies and fix folder case

* Fix capitalization, make interfaces default exports

* Refactoring

* Make Patches and Queries have two generic parameters to
express the original type as well as the resulting type.

* Create a CompoundQuery class to allow for any arbitrary
queries to be combined into a single query.

* Remove the second generic type in BaseStore. For the most
part, the type of the items in the store will not change
between the source and the subStore, so they can use the
same generic type.

If they did change types, in one case the
items could be mapped to a completely different type. In
this case updates can no longer happen by delegating to
the parent because there's no way to reverse engineer
the relationship between the items.

In the case where a selection or a similar operation has
been performed, it would be useful, but the direction of
the type relationship is contravariant. If the source has
Items of type {a: string, b: string}, the child would have
elements of either {a: string}, {a: string, b: string}, or
{b: string}. In any other case we have the problem mentioned
above. But in this case, the resulting item is a superclass
of the source store. Which means the signature for this
opertion would need to be something like
```
Store<A, B extends A> {
	source: Store<B>
	select<C extendedBy A>: Store<C, A>;
}
```
But we can't express that.

* Refactoring

* Add more options for serialization

* Move queries to their own package

* Add select query

* Change pointer add method to push, and add pop

* Change factory names to match compose pattern

* Fix testing configuration and dist build

* Add a few simple unit tests for sort.

* Add store 'actions', minor refactoring

* Change `type` in filter to `filterType`, query already
has a queryType so this is hopefully more
consistent/clearer.

* Add store 'actions'. They're not necessarily proper
actions but they express a similar pattern. They also,
with the StoreActionManager, form the start of an attempt
at handling conflicts and out of date data.

* Adding in "actions"

Store "Actions" are meant to wrap an update and allow for
 * Handling conflicts and other failures gracefully
 * Handle ordering of concurrent requests

* Use an observer instead of a promise for a single action's results

Using an observer instead of a promise for a single
action's result allows a lot of code passing promises
through to be eliminated. It also simplified the
interaction for an end user of the API, as retrying a
failed request repeatedly no longer requires a potentially
endless chain of promises.

* Implement memory store and add some unit tests for it

Also includes refactoring

* Adding tests - in a broken state

* More tests

* Minor changes to make code compile.

* Fix dojo dependency versions

* Add more unit tests

* Add another test for subcollections
* Start adding more detailed tests for each method

* bump peer deps to 'next' tag and config for UMD typings

* change deps to peer deps in line with dojo2 convention, add grunt task for peer deps

* update .gitignore for node_modules and .tsconfig*.json files

* implement 'noImplicitThis'

* Fix the build(compile) issue by switching back to previous working version of dependencies.

The tsc compile issue is cased by some issue in the `next` tag of `dojo-core` package. Until a more stable version of `dojo-core` is released,
we have to use previous working version for now.

* Add more unit tests for MemoryStore. Fix minor code issue.

Note: a few unit tests are still failing. Need to either update code to
pass the unit tests, or remove the tests if we feel the tests are making
wrong assumptions.

* Minor API change, fixes to Actions, add method, and tests

Action result 'errors' really represent data conflicts
only, as other errors will still be handled through the
error callback of the action. The relevant flag has been
renamed to better reflect that.

Action observers should only call `retryAll` or `filter`
synchronously within the callback, and if they are not an
appropriate error will be thrown. This is mainly so that
the observer can be completed if the action is not going to
be retried, by checking after its next callback whether
`retryAll` or `filter` was called on the result.

Actions now also throw appropriate errors when `retryAll` or
`filter` is called more than once on the same result object,
or on a successful result object.

`Add` now calls `put` on retry, as retrying an add means that
the item already exists but we want to update it anyway.

Changed tests to reflect that:
 * Adding an existing item should be considered a data
   conflict, but the action should be able to be retried,
   and in that case it should update the existing item.
 * When subscribing to the store's observable, an initial
   update should be received that indicates the state of the
   store at the time of subscription.

Fixes two other miscellaneous bugs:
 * `_add` in `MemoryStore` was adding all passed items to
   the store's data. Now it correctly only adds only the new
   items.
 * On retry, the action was being executed immediately
   instead of being queued.

* Add grunt watch task registered as the default task.

* Add unit tests around `store#fetch`.

The factory function `rangeFactory` is changed to `createRange` to be
consistent with the rest of application such as filter#createFilter etc.

* fix TS2 version and bump dojo deps (dojo#7)

* Minor refactor and more tests

* Minor changes to update interface so that all updates can
optionally have an item or index property. This avoids a lot
of casting to different update types.

* Updates to track and release API so that they return a
promise to the store.

* Don't send out an initial update of current items when
observing the store. If using fetch, it's not performant,
and if not using fetch, the results can be surprising
because the local data may not be what is expected at
the time of observation.

* Getting rid of fat arrow functions to match dojo style
guide

* Making the order of actions more controllable via custom
store managers by adding a retry function. The default
manager currently just executes the next available action
asynchronously as soon as the current action executes once.
Any retries on that action are treated as new actions and
just queued normally. With the separate retry method an
action manager could be implemented that waits until the
current action is completed, including waiting for any
retries.

* Refactoring API and breaking out into separate compose mixins

* Separate query module into a mixin.

Use instance constructor as subcollection factory

Make observableStoreMixin subcollection aware

* Add more unit tests for query mixin

* Fix query mixin so it doesn't query recursively

* Adding track and release mixin - No tests yet

* Add unit tests from previous code.

Add unit tests for track mixin. (doesn't compile yet)

Add unit tests for Patch/JsonPointer.

* achieved 100% coverage.
* a few issues were caught and fixed.

* Interface cleanup and test case for trackable mixin

Fix ordering for operations and tracking.

Doesn't resolve the case where fetching occurs around the
operation.

* Add more test cases for and fix issues with operation ordering

* Split else onto a separate line

* Update readme

* Fix internal link in readme

* Really fix internal link in readme

* Add unit tests.

* Most modules has 100% coverage.
* Overall coverage is over 80%, while a few corner cases are not covered
yet.
* Fix a few issues caught by tests.
* Cleanup.

* Fix build issues.

* Comment out failing unit tests. See dojo/compose/dojo#81 for details.

* Add missing all.ts to fix build issue.

* Switch back to previous version of compose, uncomment unit tests.

* Will update accordingly based on discussion in /dojo/compose/dojo#81
* Attempt to fix build issue by adding `Rx.config.Promise`

* Fix build issues on IE 10/11 caused by unavailable functionality.

* Update IOS version due to issues with saucelabs environments.

* Update IOS version to 9.3 due to issues with saucelabs environments.

* Trigger Build. (Previous build dojo#32 seems to hang for no reason.)

* Add more tests to cover more areas of logic.

* Feedback changes: package name and version etc.

* Move file into mixin dir.

* Add createTransactionMixin.

* Remove dtsGenerator grunt config

* Add tests for createTransactionMixin. Fix issues caught by tests.
@dylans dylans modified the milestones: 2016.10, 2016.08 Oct 24, 2016
@dylans dylans modified the milestones: 2016.11, 2016.10 Oct 31, 2016
@dylans dylans modified the milestones: 2016.11, 2016.12 Dec 5, 2016
@dylans dylans added this to the 2017.01 milestone Dec 20, 2016
@dylans dylans removed this from the 2016.12 milestone Dec 20, 2016
@eheasley eheasley modified the milestones: 2017.02, 2017.01 Jan 24, 2017
@dylans
Copy link
Member

dylans commented Jan 31, 2017

All dependent issues have been resolved, anything else can be handled via separate issues.

@dylans dylans closed this as completed Jan 31, 2017
@dylans dylans modified the milestones: 2017.01, 2017.02 Feb 1, 2017
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

5 participants