-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Create metastore and datastore custom hooks and resource component to…
… use them (#4) * rewrite hook to take parameters * Saved work * Add sort to datastore query * Rename useDatastore and add tests for transformSort * Add tests for transformConditions * Adds tests for resource and usedatastore
- Loading branch information
Showing
17 changed files
with
479 additions
and
22 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
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,11 @@ | ||
import { createContext } from 'react'; | ||
|
||
export const ResourceDispatch = createContext(null); | ||
|
||
// Build columns in correct structure for Datatable component. | ||
export function prepareColumns(columns) { | ||
return columns.map((column) => ({ | ||
Header: column, | ||
accessor: column, | ||
})); | ||
} |
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,12 @@ | ||
import { prepareColumns } from './helpers'; | ||
|
||
describe('prepareColumns', () => { | ||
test('transform an array into React Table columns', async () => { | ||
const testArray1 = ['my_column', 'column_2']; | ||
|
||
expect(prepareColumns(testArray1)).toEqual([ | ||
{Header: 'my_column', accessor: 'my_column'}, | ||
{Header: 'column_2', accessor: 'column_2'}, | ||
]); | ||
}); | ||
}); |
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,72 @@ | ||
import React, { useState } from 'react'; | ||
import PropTypes from 'prop-types'; | ||
import useDatastore from '../hooks/useDatastore'; | ||
import { ResourceDispatch } from './helpers'; | ||
|
||
const Resource = ({ distribution, rootUrl, children, options }) => { | ||
const { identifier } = distribution; | ||
const [currentPage, setCurrentPage] = useState(0); | ||
const { | ||
loading, | ||
values, | ||
columns, | ||
count, | ||
limit, | ||
offset, | ||
setResource, | ||
setLimit, | ||
setOffset, | ||
setConditions, | ||
setSort, | ||
} = useDatastore(identifier, rootUrl, options); | ||
const actions = { | ||
setResource, | ||
setLimit, | ||
setOffset, | ||
setCurrentPage, | ||
setConditions, | ||
setSort, | ||
}; | ||
return ( | ||
<ResourceDispatch.Provider value={{ | ||
loading: loading, | ||
items: values, | ||
columns: columns, | ||
actions: actions, | ||
totalRows: count, | ||
limit: limit, | ||
offset: offset, | ||
currentPage: currentPage, | ||
}}> | ||
{(values.length) | ||
&& children | ||
} | ||
</ResourceDispatch.Provider> | ||
); | ||
} | ||
|
||
Resource.defaultProps = { | ||
options: {}, | ||
}; | ||
|
||
Resource.propTypes = { | ||
distribution: PropTypes.shape({ | ||
identifier: PropTypes.string.isRequired, | ||
data: PropTypes.shape({ | ||
downloadURL: PropTypes.string.isRequired, | ||
format: PropTypes.string, | ||
title: PropTypes.string, | ||
mediaType: PropTypes.string, | ||
}) | ||
}).isRequired, | ||
rootUrl: PropTypes.string.isRequired, | ||
children: PropTypes.element.isRequired, | ||
options: PropTypes.shape({ | ||
limit: PropTypes.number, | ||
offset: PropTypes.number, | ||
keys: PropTypes.bool, | ||
prepareColumns: PropTypes.func | ||
}) | ||
}; | ||
|
||
export default Resource; |
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,63 @@ | ||
import React from 'react'; | ||
import axios from 'axios'; | ||
import {act} from 'react-dom/test-utils'; | ||
import { render, screen } from '@testing-library/react'; | ||
import userEvent from '@testing-library/user-event' | ||
import '@testing-library/jest-dom/extend-expect'; | ||
import Resource from './index'; | ||
import { ResourceDispatch } from './helpers'; | ||
|
||
jest.mock('axios'); | ||
const rootUrl = 'http://dkan.com/api/1'; | ||
const data = { | ||
data: { | ||
results: [{record_id: '1', column_1: 'fizz', column_2: 'dkan'}], | ||
count: '1' | ||
} | ||
} | ||
const distribution = { | ||
identifier: "1234-1234", | ||
data: { | ||
downloadURL: `${rootUrl}/files/file.csv`, | ||
format: "csv", | ||
title: "Dist Title" | ||
} | ||
} | ||
|
||
const MyTestComponent = () => { | ||
const { totalRows, items, actions, limit, offset } = React.useContext(ResourceDispatch) | ||
const { setLimit, setOffset } = actions; | ||
return ( | ||
<div> | ||
<p>{items[0].column_1} and {totalRows} and {limit} and {offset}</p> | ||
<button onClick={() => setLimit(25)}>Up Limit</button> | ||
<button onClick={() => setOffset(10)}>Up Offset</button> | ||
</div> | ||
) | ||
} | ||
|
||
describe('<Resource />', () => { | ||
test('renders data', async () => { | ||
await act(async () => { | ||
await axios.post.mockImplementation(() => Promise.resolve(data)); | ||
render( | ||
<Resource | ||
distribution={distribution} | ||
rootUrl={rootUrl} | ||
> | ||
<MyTestComponent /> | ||
</Resource> | ||
); | ||
}); | ||
expect(screen.getByText('fizz and 1 and 20 and 0')).toBeInTheDocument(); | ||
await act(async () => { | ||
userEvent.click(screen.getByText('Up Limit')); | ||
}); | ||
expect(screen.getByText('fizz and 1 and 25 and 0')).toBeInTheDocument(); | ||
await act(async () => { | ||
userEvent.click(screen.getByText('Up Offset')); | ||
}); | ||
expect(screen.getByText('fizz and 1 and 25 and 10')).toBeInTheDocument(); | ||
|
||
}); | ||
}); |
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,32 @@ | ||
import axios from 'axios'; | ||
|
||
export async function fetchDataFromQuery(id, rootUrl, options) { | ||
const { keys, limit, offset, conditions, sort, prepareColumns, setValues, setCount, setColumns, setLoading } = options; | ||
if(!id) { | ||
// TODO: Throw error | ||
return false; | ||
} | ||
if(typeof setLoading === 'function') { | ||
setLoading(true); | ||
} | ||
return await axios.post(`${rootUrl}/datastore/query/?`, { | ||
resources: [{id: id, alias: 't'}], | ||
keys: keys, | ||
limit: limit, | ||
offset: offset, | ||
conditions: conditions, | ||
sort: sort, | ||
}) | ||
.then((res) => { | ||
const { data } = res; | ||
setValues(data.results), | ||
setCount(data.count) | ||
if(data.results.length) { | ||
setColumns(prepareColumns ? prepareColumns(Object.keys(data.results[0])) : Object.keys(data.results[0])) | ||
} | ||
if(typeof setLoading === 'function') { | ||
setLoading(false); | ||
} | ||
return data; | ||
}) | ||
} |
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,37 @@ | ||
import axios from 'axios'; | ||
import { fetchDataFromQuery } from './fetch'; | ||
|
||
jest.mock('axios'); | ||
const rootUrl = 'http://dkan.com/api/1'; | ||
const data = { | ||
data: { | ||
results: [{record_id: '1', column_1: 'fizz', column_2: 'dkan'}], | ||
count: '1' | ||
} | ||
} | ||
const distribution = { | ||
identifier: "1234-1234", | ||
data: { | ||
downloadURL: `${rootUrl}/files/file.csv`, | ||
format: "csv", | ||
title: "Dist Title" | ||
} | ||
} | ||
|
||
describe('fetchDataFromQuery', () => { | ||
test('returns data from datastore query endpoint', async () => { | ||
axios.post.mockImplementation(() => Promise.resolve(data)); | ||
const results = await fetchDataFromQuery(distribution.identifier, rootUrl, { | ||
keys: true, | ||
limit: 20, | ||
offset: 0, | ||
conditions: [], | ||
sort: {asc: [], desc: []}, | ||
setValues: () => {}, | ||
setCount: () => {}, | ||
setColumns: () => {} | ||
}) | ||
expect(results.count).toEqual(data.data.count); | ||
expect(results.results).toEqual(data.data.results); | ||
}) | ||
}); |
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,44 @@ | ||
import {useState, useEffect} from 'react'; | ||
import { fetchDataFromQuery } from './fetch'; | ||
|
||
const useDatastore = (resourceId, rootAPIUrl, options) => { | ||
const keys = options.keys ? options.keys : true; | ||
const { prepareColumns } = options; | ||
const [values, setValues] = useState([]); | ||
const [id, setResource] = useState(resourceId); | ||
const [rootUrl, setRootUrl] = useState(rootAPIUrl); | ||
const [limit, setLimit] = useState(options.limit ? options.limit : 20); | ||
const [count, setCount] = useState(null); | ||
const [columns, setColumns] = useState([]); | ||
const [offset, setOffset] = useState(options.offset ? options.offset : 0); | ||
const [loading, setLoading] = useState(false); | ||
const [conditions, setConditions] = useState() | ||
const [sort, setSort] = useState() | ||
// const [joins, setJoins] = useState() | ||
// const [properties, setProperties] = useState() | ||
|
||
useEffect(() => { | ||
if(!loading) { | ||
fetchDataFromQuery(id, rootUrl, | ||
{ keys, limit, offset, conditions, sort, prepareColumns, setValues, setCount, setColumns, setLoading} | ||
) | ||
} | ||
}, [id, rootUrl, limit, offset, conditions, sort]) | ||
|
||
return { | ||
loading, | ||
values, | ||
count, | ||
columns, | ||
limit, | ||
offset, | ||
setResource, | ||
setRootUrl, | ||
setLimit, | ||
setOffset, | ||
setConditions, | ||
setSort, | ||
} | ||
} | ||
|
||
export default useDatastore; |
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,35 @@ | ||
// OPERATORS | ||
// = | ||
// <> not equal to | ||
// BETWEEN | ||
// IN | ||
// NOT IN | ||
// >= | ||
// <= | ||
// like | ||
|
||
export function transformTableFilterToQueryCondition(filterArray) { | ||
const conditions = filterArray.map((f) => { | ||
return { | ||
resource: 't', | ||
property: f.id, | ||
value: `%${f.value}%`, | ||
operator: 'LIKE', | ||
} | ||
}); | ||
return conditions; | ||
} | ||
|
||
export function transformTableFilterToSQLCondition(filterArray) { | ||
if(!filterArray || filterArray.length === 0) { | ||
return ''; | ||
} | ||
|
||
const where_clauses = []; | ||
filterArray.forEach((v, i) => { | ||
// Switch delimiter to, and strip any double-quote for Dkan2's sql query. | ||
let value = `%25${v.value}%25`; | ||
where_clauses[i] = `${v.id} = "${v.value.replace('"', '')}"`; | ||
}); | ||
return `[WHERE ${where_clauses.join(' AND ')}]`; | ||
} |
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,16 @@ | ||
import { transformTableFilterToQueryCondition } from './transformConditions'; | ||
|
||
describe('transformTableFilterToQueryCondition', () => { | ||
test('transform an array from of filters from React Table into DKAN query format', async () => { | ||
const testArray1 = [{id: "my_label", value: 'abcd'}]; | ||
const testArray2 = [{id: "my_label", value: 'abcd'}, {id: "another_label", value: '1234'}]; | ||
|
||
expect(transformTableFilterToQueryCondition(testArray1)).toEqual([ | ||
{resource: 't', property: 'my_label', value: '%abcd%', operator: 'LIKE'} | ||
]); | ||
expect(transformTableFilterToQueryCondition(testArray2)).toEqual([ | ||
{resource: 't', property: 'my_label', value: '%abcd%', operator: 'LIKE'}, | ||
{resource: 't', property: 'another_label', value: '%1234%', operator: 'LIKE'} | ||
]); | ||
}); | ||
}); |
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,14 @@ | ||
export function transformTableSortToQuerySort(sortArray) { | ||
let newQuery = { | ||
asc: [], | ||
desc: [], | ||
} | ||
sortArray.forEach((s) => { | ||
if (s.desc) { | ||
return newQuery.desc.push(s.id) | ||
} else { | ||
return newQuery.asc.push(s.id) | ||
} | ||
}) | ||
return newQuery; | ||
} |
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,12 @@ | ||
import { transformTableSortToQuerySort } from './transformSorts'; | ||
|
||
describe('transformTableSortToQuerySort', () => { | ||
test('transform an array from of sorts from React Table into DKAN query format', async () => { | ||
const testArray1 = [{id: "my_label", desc: true}] | ||
const testArray2 = [{id: "another_label", desc: false}] | ||
|
||
expect(transformTableSortToQuerySort(testArray1)).toEqual({asc: [], desc:['my_label']}); | ||
expect(transformTableSortToQuerySort(testArray2)).toEqual({asc: ['another_label'], desc:[]}); | ||
expect(transformTableSortToQuerySort(testArray1.concat(testArray2))).toEqual({asc: ['another_label'], desc:['my_label']}); | ||
}); | ||
}); |
Oops, something went wrong.