Skip to content

Commit

Permalink
Mark read-only _Events_ and _Stores_ with readonly
Browse files Browse the repository at this point in the history
  • Loading branch information
igorkamyshev committed Apr 18, 2023
1 parent 961f32f commit faa19ec
Show file tree
Hide file tree
Showing 13 changed files with 249 additions and 80 deletions.
5 changes: 5 additions & 0 deletions .changeset/shy-avocados-love.md
@@ -0,0 +1,5 @@
---
'@farfetched/core': minor
---

Mark read-only _Events_ and _Stores_ with `readonly`
78 changes: 58 additions & 20 deletions apps/website/docs/api/primitives/mutation.md
@@ -1,30 +1,68 @@
---
outline: [2, 3]
---

# Mutation <Badge type="tip" text="since v0.2.0" />

Representation of a mutation of remote data.

## API reference
## Commands

This section describes the [_Event_](https://effector.dev/docs/api/effector/event) that can be used to perform actions on the _Mutation_. Commands should be called in application code.

### `start`

Unconditionally starts the _Mutation_ with the given parameters.

## Stores

This section describes the [_Stores_](https://effector.dev/docs/api/effector/store) that can be used to read the _Mutation_ state.

### `$status`

[_Store_](https://effector.dev/docs/api/effector/store) with the current status of the _Mutation_. It must not be changed directly. Can be one of the following values: `"initial"`, `"pending"`, `"done"`, `"fail"`.

For convenience, there are also the following [_Stores_](https://effector.dev/docs/api/effector/store):

- `$idle` <Badge type="tip" text="since v0.8.0" /> — `true` if the _Mutation_ is in the `"initial"` state, `false` otherwise.
- `$pending``true` if the _Mutation_ is in the `"pending"` state, `false` otherwise.
- `$failed``true` if the _Mutation_ is in the `"fail"` state, `false` otherwise.
- `$succeeded``true` if the _Mutation_ is in the `"done"` state, `false` otherwise.

### `$enabled`

[_Store_](https://effector.dev/docs/api/effector/store) with the current enabled state of the _Mutation_. Disabled _Mutations_ will not be executed, instead, they will be treated as skipped. It must not be changed directly. Can be `true` or `false`.

## Events

This section describes the [_Event_](https://effector.dev/docs/api/effector/event) that can be used to listen to the _Mutation_ state changes. Events must not be called in application code.

### `finished.success`

[_Event_](https://effector.dev/docs/api/effector/event) that will be triggered when the _Mutation_ is finished with success. Payload will contain the object with the following fields:

- `params` with the parameters that were used to start the _Mutation_
- `result` with the result of the _Mutation_
- `meta` with the execution metadata

### `finished.failure`

[_Event_](https://effector.dev/docs/api/effector/event) that will be triggered when the _Mutation_ is finished with failure. Payload will contain the object with the following fields:

- `params` with the parameters that were used to start the _Mutation_
- `error` with the error of the _Mutation_
- `meta` with the execution metadata

```ts
const mutation: Mutation<Params, Data, Error>;
### `finished.skip`

// Stores
mutation.$status; // Store<'initial' | 'pending' | 'done' | 'fail'>
mutation.$idle; // Store<boolean>, since v0.8.0
mutation.$pending; // Store<boolean>
mutation.$failed; // Store<boolean>
mutation.$succeeded; // Store<boolean>
mutation.$enabled; // Store<boolean>
[_Event_](https://effector.dev/docs/api/effector/event) that will be triggered when the _Mutation_ is skipped. Payload will contain the object with the following fields:

// Commands
mutation.start; // Event<Params>;
- `params` with the parameters that were used to start the _Mutation_
- `meta` with the execution metadata

// Events
mutation.finished.success; // Event<Data>;
mutation.finished.failure; // Event<Error>;
mutation.finished.skip; // Event<void>;
mutation.finished.finally; // Event<void>;
### `finished.finally`

// Note: Store and Event are imported from 'effector' package
```
[_Event_](https://effector.dev/docs/api/effector/event) that will be triggered when the _Mutation_ is finished with success, failure or skip. Payload will contain the object with the following fields:

More information about API can be found in [the source code](https://github.com/igorkamyshev/farfetched/blob/master/packages/core/src/mutation/type.ts).
- `params` with the parameters that were used to start the _Mutation_
- `meta` with the execution metadata
116 changes: 84 additions & 32 deletions apps/website/docs/api/primitives/query.md
@@ -1,36 +1,88 @@
---
outline: [2, 3]
---

# Query

Representation of a piece of remote data.

## API reference

```ts
const query: Query<Params, Data, Error>;
const query: Query<Params, Data, Error, InitialData>; // InitialData is allowed since v0.3.0

// Stores
query.$data; // Store<Data | InitialData>
query.$error; // Store<Error | null>
query.$status; // Store<'initial' | 'pending' | 'done' | 'fail'>
query.$idle; // Store<boolean>, since v0.8.0
query.$pending; // Store<boolean>
query.$failed; // Store<boolean>, since v0.2.0
query.$succeeded; // Store<boolean>, since v0.2.0
query.$enabled; // Store<boolean>
query.$stale; // Store<boolean>

// Commands
query.start; // Event<Params>
query.reset; // Event<void>, since v0.2.0
query.refresh; // Event<Params>. since v0.8.0

// Events
query.finished.success; // Event<{ result: Data, params: Params }>
query.finished.failure; // Event<{ error: Error, params: Params }>
query.finished.skip; // Event<{ params: Params }>
query.finished.finally; // Event<{ params: Params }>

// Note: Store and Event are imported from 'effector' package
```

More information about API can be found in [the source code](https://github.com/igorkamyshev/farfetched/blob/master/packages/core/src/query/type.ts).
## Commands

This section describes the [_Event_](https://effector.dev/docs/api/effector/event) that can be used to perform actions on the _Query_. Commands should be called in application code.

### `start`

Unconditionally starts the _Query_ with the given parameters.

### `refresh` <Badge type="tip" text="since v0.8.0" />

Starts the _Query_ with the given parameters if it is `$stale`. Otherwise, it will be treated as skipped.

### `reset` <Badge type="tip" text="since v0.2.0" />

Resets the _Query_ to the initial state.

## Stores

This section describes the [_Stores_](https://effector.dev/docs/api/effector/store) that can be used to read the _Query_ state.

### `$data`

[_Store_](https://effector.dev/docs/api/effector/store) with the latest data. It must not be changed directly. In case of error, it will contain the initial data.

### `$error`

[_Store_](https://effector.dev/docs/api/effector/store) with the latest error. It must not be changed directly. In case of success, it will contain `null`.

### `$status`

[_Store_](https://effector.dev/docs/api/effector/store) with the current status of the _Query_. It must not be changed directly. Can be one of the following values: `"initial"`, `"pending"`, `"done"`, `"fail"`.

For convenience, there are also the following [_Stores_](https://effector.dev/docs/api/effector/store):

- `$idle` <Badge type="tip" text="since v0.8.0" /> — `true` if the _Query_ is in the `"initial"` state, `false` otherwise.
- `$pending``true` if the _Query_ is in the `"pending"` state, `false` otherwise.
- `$failed` <Badge type="tip" text="since v0.2.0" /> — `true` if the _Query_ is in the `"fail"` state, `false` otherwise.
- `$succeeded` <Badge type="tip" text="since v0.2.0" /> — `true` if the _Query_ is in the `"done"` state, `false` otherwise.

### `$enabled`

[_Store_](https://effector.dev/docs/api/effector/store) with the current enabled state of the _Query_. Disabled queries will not be executed, instead, they will be treated as skipped. It must not be changed directly. Can be `true` or `false`.

### `$stale`

[_Store_](https://effector.dev/docs/api/effector/store) with the current stale state of the _Query_. Stale queries will be executed on the next call to `refresh` [_Event_](https://effector.dev/docs/api/effector/event). It must not be changed directly. Can be `true` or `false`.

## Events

This section describes the [_Event_](https://effector.dev/docs/api/effector/event) that can be used to listen to the _Query_ state changes. Events must not be called in application code.

### `finished.success`

[_Event_](https://effector.dev/docs/api/effector/event) that will be triggered when the _Query_ is finished with success. Payload will contain the object with the following fields:

- `params` with the parameters that were used to start the _Query_
- `result` with the result of the _Query_
- `meta` with the execution metadata

### `finished.failure`

[_Event_](https://effector.dev/docs/api/effector/event) that will be triggered when the _Query_ is finished with failure. Payload will contain the object with the following fields:

- `params` with the parameters that were used to start the _Query_
- `error` with the error of the _Query_
- `meta` with the execution metadata

### `finished.skip`

[_Event_](https://effector.dev/docs/api/effector/event) that will be triggered when the _Query_ is skipped. Payload will contain the object with the following fields:

- `params` with the parameters that were used to start the _Query_
- `meta` with the execution metadata

### `finished.finally`

[_Event_](https://effector.dev/docs/api/effector/event) that will be triggered when the _Query_ is finished with success, failure or skip. Payload will contain the object with the following fields:

- `params` with the parameters that were used to start the _Query_
- `meta` with the execution metadata
6 changes: 6 additions & 0 deletions apps/website/docs/releases/0-9.md
Expand Up @@ -4,4 +4,10 @@

`externalCache` adapter was deprecated in [0.8](/releases/0-8), write your own adapter instead [by recipe](/recipes/server_cache).

### Read-only [_Stores_](https://effector.dev/docs/api/effector/store) and [_Events_](https://effector.dev/docs/api/effector/event)

[_Events_](https://effector.dev/docs/api/effector/event) `finished.*` have never been supposed to be called in application code. Now they are read-only. In case you call them, you will get a warning in console in Effector 22 and exception in Effector 23.

[_Stores_](https://effector.dev/docs/api/effector/store) `$data`, `$error`, `$status`, `$idle`, `$pending`, `$succeeded`, `$failed`, `$enabled` have never been supposed to be changed in application code directly. Now they are read-only. In case you change them, you will get a warning in console in Effector 22 and exception in Effector 23.

<!--@include: ./0-9.changelog.md-->
8 changes: 1 addition & 7 deletions packages/core/src/cache/key/key.ts
Expand Up @@ -39,13 +39,7 @@ export function queryUniqId(query: Query<any, any, any>) {
}

function querySid(query: Query<any, any, any>): string | null {
const sid = query.$data.sid;

if (!sid?.includes('|')) {
return null;
}

return sid;
return query.__.meta.sid ?? null;
}

const prevNames = new Set<string>();
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/libs/patronus/index.ts
Expand Up @@ -18,3 +18,4 @@ export {
export { type FetchingStatus } from './status';
export { time } from './time';
export { and } from './and';
export { readonly } from './readonly';
10 changes: 10 additions & 0 deletions packages/core/src/libs/patronus/readonly.ts
@@ -0,0 +1,10 @@
import { Event, Store } from 'effector';

export function readonly<T>(store: Store<T>): Store<T>;
export function readonly<T>(event: Event<T>): Event<T>;

export function readonly<T>(
storeOrEvent: Store<T> | Event<T>
): Store<T> | Event<T> {
return storeOrEvent.map((v) => v);
}
31 changes: 24 additions & 7 deletions packages/core/src/mutation/create_headless_mutation.ts
@@ -1,10 +1,15 @@
import { attach, type Store } from 'effector';

import { createRemoteOperation } from '../remote_operation/create_remote_operation';
import { DynamicallySourcedField, StaticOrReactive } from '../libs/patronus';
import { Mutation, MutationSymbol } from './type';
import { Contract } from '../contract/type';
import { InvalidDataError } from '../errors/type';
import { Validator } from '../validation/type';
import { attach, Store } from 'effector';
import {
type DynamicallySourcedField,
readonly,
type StaticOrReactive,
} from '../libs/patronus';
import { type Mutation, MutationSymbol } from './type';
import { type Contract } from '../contract/type';
import { type InvalidDataError } from '../errors/type';
import { type Validator } from '../validation/type';

export interface SharedMutationFactoryConfig {
name?: string;
Expand Down Expand Up @@ -100,7 +105,19 @@ export function createHeadlessMutation<
// -- Public API --

return {
...operation,
start: operation.start,
$status: readonly(operation.$status),
$idle: readonly(operation.$idle),
$pending: readonly(operation.$pending),
$succeeded: readonly(operation.$succeeded),
$failed: readonly(operation.$failed),
$enabled: readonly(operation.$enabled),
finished: {
success: readonly(operation.finished.success),
failure: readonly(operation.finished.failure),
finally: readonly(operation.finished.finally),
skip: readonly(operation.finished.skip),
},
__: { ...operation.__, experimentalAPI: { attach: attachProtocol } },
'@@unitShape': unitShapeProtocol,
};
Expand Down

0 comments on commit faa19ec

Please sign in to comment.