Skip to content

Commit

Permalink
feat(classic): Pass all props on read (#101)
Browse files Browse the repository at this point in the history
* Add new readMeta prop to read responses

* Add props validation for readMeta

* Pass all props action -> reader. Keep original

* Adjust __read ui to correctly dispatch the action

* Refined refreshAction

- it replays previous action only if provided uri is undefined, otherwise takes the refresh action as the instruction
  • Loading branch information
filipboev authored and Blagoja Evkoski committed Aug 29, 2018
1 parent 5d2eadd commit 6b39241
Show file tree
Hide file tree
Showing 6 changed files with 81 additions and 39 deletions.
10 changes: 3 additions & 7 deletions packages/classic/src/core/elements/read.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,17 @@ import { read as readAction } from '../../read/actions'
export default class Read extends React.Component {
static propTypes = {
dispatch: PropTypes.func.isRequired,
kind: PropTypes.oneOfType([
PropTypes.string,
PropTypes.arrayOf(PropTypes.string),
]).isRequired,
uri: PropTypes.string.isRequired,
revalidate: PropTypes.bool,
opts: PropTypes.object.isRequired,
}

constructor(props) {
super(props)
}

componentDidMount() {
const { dispatch, uri, revalidate } = this.props
dispatch(readAction(uri, { revalidate }))
const { dispatch, uri, opts } = this.props
dispatch(readAction(uri, opts))
}

render() {
Expand Down
16 changes: 8 additions & 8 deletions packages/classic/src/core/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import Read from './elements/read'
import Loading from './elements/loading'
import Error from './elements/error'

import * as propNames from '../propNames'
/**
* This is the 'default' subsystem where all 'global' registrations go to
*/
Expand Down Expand Up @@ -45,14 +46,13 @@ core.defaultSubsystems = defaultSubsystems
core.read.register(core.read.default, core.read.http.httpRead)

core.ui.register(['__read'], ({ element, dispatch }) => {
return (
<Read
kind={element.get('kind').toJS()}
uri={element.get('uri')}
dispatch={dispatch}
revalidate={element.get('revalidate')}
/>
)
const opts = element
.delete('kind')
.delete('uri')
.delete(propNames.children)
.toJS()

return <Read uri={element.get('uri')} opts={opts} dispatch={dispatch} />
})
core.ui.register(['__loading'], ({ element, dispatch }) => {
return (
Expand Down
25 changes: 21 additions & 4 deletions packages/classic/src/read/__tests__/read.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import * as data from '../../data'
import * as readActions from '../actions'
import * as propNames from '../../propNames'

describe('Read Subsytem', () => {
describe('Read Subsystem', () => {
const app = Subsystem.create(() => ({
name: 'app',
}))
Expand Down Expand Up @@ -70,6 +70,9 @@ describe('Read Subsytem', () => {
content = kernel.query(['content'])
expect(data.isExactlyOfKind('scene', content)).toBeTruthy()
expect(content.get('title')).toEqual('Scene Title')
expect(content.getIn([propNames.metadata, 'request']).toJS()).toEqual(
readAction
)
})

it('handles failures', async () => {
Expand Down Expand Up @@ -126,7 +129,10 @@ describe('Read function', () => {
kernel.dispatch(
action.atCursor(
content,
readActions.read(content.get('uri'), { revalidate: true })
readActions.read(content.get('uri'), {
revalidate: true,
alpha: 'beta',
})
)
)

Expand All @@ -136,6 +142,7 @@ describe('Read function', () => {
'https://netcetera.com/test.json',
{
revalidate: true,
alpha: 'beta',
},
expect.any(Object)
)
Expand Down Expand Up @@ -214,7 +221,7 @@ describe('Refreshing', () => {
kernel.dispatch(
action.atCursor(
content,
readActions.readRefresh('https://netcetera.com/x.json')
readActions.readRefresh('https://netcetera.com/x.json', { foo: 'bar' })
)
)

Expand All @@ -224,7 +231,10 @@ describe('Refreshing', () => {
expect(content.get('title')).toEqual('Scene Title X')

expect(refresher.mock.calls[0][0]).toEqual('https://netcetera.com/x.json')
expect(refresher.mock.calls[0][1]).toMatchObject({ revalidate: true })
expect(refresher.mock.calls[0][1]).toMatchObject({
revalidate: true,
foo: 'bar',
})

kernel.dispatch(
action.atCursor(
Expand Down Expand Up @@ -292,6 +302,13 @@ describe('Performing reads manually', async () => {
expect(result.value.getIn([propNames.metadata, 'uri'])).toEqual(
'https://netcetera.com/test.json'
)
expect(
result.value.getIn([propNames.metadata, 'request']).toJS()
).toMatchObject({
revalidate: true,
a: 1,
uri: 'https://netcetera.com/test.json',
})
})

function sleep(ms) {
Expand Down
28 changes: 26 additions & 2 deletions packages/classic/src/read/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,19 @@ export const types = {
fail: '@@skele/actions.read.fail',
}

export function read(uri, opts) {
/**
* Creates a read action.
*
* @param { String } uri the URI to be read, or an ob
* @param {*} opts read options that will be passed onto the reader.
* Currently, only `revalidate` is supported
* (which instructs the reader to perform revalidation of the content).
* If used in conjuction with the standard httpRead, one controls
* the http options eventually passed to `fetch` via this argument.
* Any extra properties are allowed. These may affect specific readers.
*
*/
export function read(uri, opts = {}) {
const defaults = {
revalidate: false,
}
Expand All @@ -23,9 +35,21 @@ export function read(uri, opts) {
}
}

export function readRefresh(uri = undefined) {
export function readRefresh(uri = undefined, opts = undefined) {
const defaults = {
revalidate: true,
}

let options = {}
if (opts != null) {
options = {
...defaults,
...opts,
}
}
return {
type: types.readRefresh,
...options,
uri,
}
}
39 changes: 22 additions & 17 deletions packages/classic/src/read/impl.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ export function fail(element, action) {
)
}

export async function performRead(context, readParams) {
export async function performRead(context, action) {
const {
registry,
enrichment,
Expand All @@ -91,7 +91,8 @@ export async function performRead(context, readParams) {

const kernel = context

const { uri, opts } = readParams
const { uri, ...opts } = R.omit(['type', propNames.actionMeta], action)

const reader = registry.get(uri) || registry.get(fallback)

if (reader != null) {
Expand Down Expand Up @@ -126,7 +127,9 @@ export async function performRead(context, readParams) {
}
if (isOK(readResponse)) {
const readValue = fromJS(readResponse.value).merge({
[propNames.metadata]: fromJS(readResponse.meta || defaultMeta(uri)),
[propNames.metadata]: fromJS(
readResponse.meta || defaultMeta(uri)
).merge({ request: R.omit([propNames.actionMeta], action) }),
})

enhanceContext = {
Expand Down Expand Up @@ -181,7 +184,7 @@ export async function performRead(context, readParams) {
url: uri,
uri,
status: 999,
message: `There's no reader defined for ${pattern}. Did you forget to register a fallback reader?`,
message: `There's no reader defined for ${uri}. Did you forget to register a fallback reader?`,
},
}
}
Expand All @@ -205,10 +208,7 @@ export async function read(context, action) {
const readResponse = await time(
`TIME-performRead-(${action.uri})`,
performRead
)(context, {
uri: action.uri,
opts: R.pick(['revalidate'], action),
})
)(context, action)

if (isOK(readResponse)) {
dispatch({
Expand Down Expand Up @@ -245,25 +245,30 @@ export async function read(context, action) {
export async function readRefresh(context, action) {
const { dispatch } = context
const element = context.query()
const uri = action.uri || element.getIn([propNames.metadata, 'uri'])
const readId = uuid()

let readAction
if (action.uri != null) {
readAction = action
} else {
readAction = element.getIn([propNames.metadata, 'request']).toJS()
}

invariant(
uri != null,
'The element you are refreshing must have been loaded via a read'
readAction != null,
'The element you are refreshing must have been loaded via a read, or you must provide an uri yourself.'
)

readAction.revalidate = flow(action, R.prop('revalidate'), R.defaultTo(true))

context.dispatch({
...action,
readId,
type: readActions.types.setRefreshing,
})

try {
const response = await performRead(context, {
uri: uri,
opts: { ...{ revalidate: true }, ...R.pick(['revalidate'], action) },
})
const response = await performRead(context, readAction)

if (isOK(response)) {
dispatch({
Expand All @@ -274,7 +279,7 @@ export async function readRefresh(context, action) {
readValue: response.value,
})
} else {
info(`Unsuccessful refreshing (read) ${uri} `, response)
info(`Unsuccessful refreshing (read) ${readAction.uri} `, response)

dispatch({
...action,
Expand All @@ -284,7 +289,7 @@ export async function readRefresh(context, action) {
})
}
} catch (e) {
error(`Error while refreshing (read) ${uri} `, e)
error(`Error while refreshing (read) ${readAction.uri} `, e)

dispatch({
...action,
Expand Down
2 changes: 1 addition & 1 deletion packages/classic/src/read/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ const read = SubSystem.create((system, instantiatedSubsystems) => {
*
* @returns Promise<ReadResponse> the read response
*/
perform: (uri, opts = {}) => impl.performRead(system, { uri, opts }),
perform: (uri, opts = {}) => impl.performRead(system, { ...opts, uri }),
}
})

Expand Down

0 comments on commit 6b39241

Please sign in to comment.