Skip to content

Commit

Permalink
initial implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
achou11 committed Jan 22, 2025
1 parent 045c570 commit eac209b
Show file tree
Hide file tree
Showing 6 changed files with 165 additions and 43 deletions.
29 changes: 29 additions & 0 deletions docs/API.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
- [useCreateDocument](#usecreatedocument)
- [useUpdateDocument](#useupdatedocument)
- [useDeleteDocument](#usedeletedocument)
- [useInvalidateRead](#useinvalidateread)
- [useAcceptInvite](#useacceptinvite)
- [useRejectInvite](#userejectinvite)
- [useSendInvite](#usesendinvite)
Expand Down Expand Up @@ -588,6 +589,34 @@ Parameters:
* `opts.projectId`: Public ID of project document belongs to.


### useInvalidateRead

Provides a function that invalidates a specified read when called.

| Function | Type |
| ---------- | ---------- |
| `useInvalidateRead` | `() => <Path extends keyof typeof PATH_TO_QUERY_KEY_FACTORY>(path: Path, params: Parameters<{ readonly '/': () => string; readonly '/maps': () => readonly ["@comapeo/core-react", "maps"]; readonly '/maps/stylejson_url': ({ refreshToken, }: { refreshToken?: string or undefined; }) => readonly [...]; ... 16 more ...; re...` |

Examples:

```tsx
function App() {
const invalidateRead = useInvalidateRead()

return (
<button
onClick={() => {
// Invalidate all reads!
invalidateRead('/', undefined)
}}
>
Invalidate everything!
</button>
)
}
```


### useAcceptInvite

Accept an invite that has been received.
Expand Down
2 changes: 1 addition & 1 deletion src/hooks/documents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ import {
documentByVersionIdQueryOptions,
documentsQueryOptions,
updateDocumentMutationOptions,
type WriteableDocumentType,
} from '../lib/react-query/documents.js'
import type { WriteableDocumentType } from '../lib/types.js' with { 'resolution-mode': 'import' }
import { useSingleProject } from './projects.js'

type ReadHookResult<D> = {
Expand Down
109 changes: 109 additions & 0 deletions src/hooks/invalidation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import { useQueryClient } from '@tanstack/react-query'

import {
getClientQueryKey,
getDeviceInfoQueryKey,
getIsArchiveDeviceQueryKey,
} from '../lib/react-query/client.js'
import {
getDocumentByDocIdQueryKey,
getDocumentByVersionIdQueryKey,
getDocumentsQueryKey,
getManyDocumentsQueryKey,
} from '../lib/react-query/documents.js'
import {
getInvitesQueryKey,
getPendingInvitesQueryKey,
} from '../lib/react-query/invites.js'
import {
getMapsQueryKey,
getStyleJsonUrlQueryKey,
} from '../lib/react-query/maps.js'
import {
getAttachmentUrlQueryKey,
getDocumentCreatedByQueryKey,
getIconUrlQueryKey,
getMemberByIdQueryKey,
getMembersQueryKey,
getProjectByIdQueryKey,
getProjectRoleQueryKey,
getProjectSettingsQueryKey,
getProjectsQueryKey,
} from '../lib/react-query/projects.js'
import { ROOT_QUERY_KEY } from '../lib/react-query/shared.js'

const PATH_TO_QUERY_KEY_FACTORY = {
'/': () => ROOT_QUERY_KEY,
'/maps': getMapsQueryKey,
'/maps/stylejson_url': getStyleJsonUrlQueryKey,
'/invites': getInvitesQueryKey,
'/invites/pending': getPendingInvitesQueryKey,
'/client': getClientQueryKey,
'/client/device_info': getDeviceInfoQueryKey,
'/client/is_archive_device': getIsArchiveDeviceQueryKey,
'/projects': getProjectsQueryKey,
'/projects/:projectId': getProjectByIdQueryKey,
'/projects/:projectId/settings': getProjectSettingsQueryKey,
'/projects/:projectId/role': getProjectRoleQueryKey,
'/projects/:projectId/members': getMembersQueryKey,
'/projects/:projectId/members/:deviceId': getMemberByIdQueryKey,
'/projects/:projectId/icons/:iconId': getIconUrlQueryKey,
'/projects/:projectId/document_created_by/:originalVersionId':
getDocumentCreatedByQueryKey,
'/projects/:project_id/attachments/:blobId': getAttachmentUrlQueryKey,
'/projects/:project_id/:doc_type': (
opts: Parameters<
typeof getDocumentsQueryKey | typeof getManyDocumentsQueryKey
>[0],
) => {
if ('lang' in opts || 'includeDeleted' in opts) {
return getManyDocumentsQueryKey(opts)
}
return getDocumentsQueryKey(opts)
},
'/projects/:project_id/:doc_type/:docId': getDocumentByDocIdQueryKey,
'/projects/:project_id/:doc_type/:versionId': getDocumentByVersionIdQueryKey,
} as const

/**
* Provides a function that invalidates a specified read when called.
*
* @example
* ```tsx
* function App() {
* const invalidateRead = useInvalidateRead()
*
* return (
* <button
* onClick={() => {
* // Invalidate all reads!
* invalidateRead('/', undefined)
* }}
* >
* Invalidate everything!
* </button>
* )
* }
* ```
*/
export function useInvalidateRead(): <
Path extends keyof typeof PATH_TO_QUERY_KEY_FACTORY,
>(
path: Path,
params: Parameters<(typeof PATH_TO_QUERY_KEY_FACTORY)[Path]>[0],
invalidationOpts?: {
exact: boolean
},
) => Promise<void> {
const queryClient = useQueryClient()

return (path, pathParams, invalidationOpts) => {
return queryClient.invalidateQueries({
exact: invalidationOpts?.exact,
queryKey: PATH_TO_QUERY_KEY_FACTORY[path](
// @ts-expect-error TS not capable enough to get this right
pathParams,
),
})
}
}
27 changes: 2 additions & 25 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export {
useSingleDocByVersionId,
useUpdateDocument,
} from './hooks/documents.js'
export { useInvalidateRead } from './hooks/invalidation.js'
export {
useAcceptInvite,
useRejectInvite,
Expand Down Expand Up @@ -43,31 +44,7 @@ export {
getIsArchiveDeviceQueryKey,
} from './lib/react-query/client.js'
export {
getDocumentByDocIdQueryKey,
getDocumentByVersionIdQueryKey,
getDocumentsQueryKey,
getManyDocumentsQueryKey,
type WriteableDocument,
type WriteableDocumentType,
type WriteableValue,
} from './lib/react-query/documents.js'
export {
getInvitesQueryKey,
getPendingInvitesQueryKey,
} from './lib/react-query/invites.js'
export {
getMapsQueryKey,
getStyleJsonUrlQueryKey,
} from './lib/react-query/maps.js'
export {
getAttachmentUrlQueryKey,
getDocumentCreatedByQueryKey,
getIconUrlQueryKey,
getMemberByIdQueryKey,
getMembersQueryKey,
getProjectByIdQueryKey,
getProjectRoleQueryKey,
getProjectSettingsQueryKey,
getProjectsQueryKey,
} from './lib/react-query/projects.js'
export { ROOT_QUERY_KEY } from './lib/react-query/shared.js'
} from './lib/types.js'
22 changes: 5 additions & 17 deletions src/lib/react-query/documents.ts
Original file line number Diff line number Diff line change
@@ -1,33 +1,21 @@
import type { MapeoProjectApi } from '@comapeo/ipc' with { 'resolution-mode': 'import' }
import type {
MapeoDoc,
MapeoValue,
} from '@comapeo/schema' with { 'resolution-mode': 'import' }
import {
queryOptions,
type QueryClient,
type UseMutationOptions,
} from '@tanstack/react-query'

import type {
WriteableDocument,
WriteableDocumentType,
WriteableValue,
} from '../types.js' with { 'resolution-mode': 'import' }
import {
baseMutationOptions,
baseQueryOptions,
ROOT_QUERY_KEY,
} from './shared.js'

export type WriteableDocumentType = Extract<
MapeoDoc['schemaName'],
'field' | 'observation' | 'preset' | 'track' | 'remoteDetectionAlert'
>
export type WriteableValue<D extends WriteableDocumentType> = Extract<
MapeoValue,
{ schemaName: D }
>
export type WriteableDocument<D extends WriteableDocumentType> = Extract<
MapeoDoc,
{ schemaName: D }
>

export function getDocumentsQueryKey<D extends WriteableDocumentType>({
projectId,
docType,
Expand Down
19 changes: 19 additions & 0 deletions src/lib/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import type {
MapeoDoc,
MapeoValue,
} from '@comapeo/schema' with { 'resolution-mode': 'import' }

export type WriteableDocumentType = Extract<
MapeoDoc['schemaName'],
'field' | 'observation' | 'preset' | 'track' | 'remoteDetectionAlert'
>
export type WriteableValue<D extends WriteableDocumentType> = Extract<
MapeoValue,
{ schemaName: D }
>
export type WriteableDocument<D extends WriteableDocumentType> = Extract<
MapeoDoc,
{ schemaName: D }
>

export {}

0 comments on commit eac209b

Please sign in to comment.