/**
 * React hooks and components that build on top of the functions exposed in `./helpers`.
 *
 *
 * It assumes a global datastore for some React sub-tree, set by a node that sets a context.
 * This is implicility passed down to all sub-components, to make it less verbose to get and set data.
 *
 * However, it doesn't put the schemas on a context, because we need to refer to them for typing purpose
 *
 *
 * It also makes these assumptions about React best practices:
 *
 * 1. Only pass in primitive data types to nodes, not rich objects with methods. Makes it easier to debug in the provided debugger.
 * 2. Use hooks to get at state that changes over time to abstract that away.
 * 3. Only pass in minimum information down react tree, so that only edge nodes are re-rendered when data changes occur.
 *
 * Also somewhat inspired by Recoil (https://recoiljs.org/) for best practices and naming.
 */ import { Datastore , Record , Schema , Table } from "@lumino/datastore" ; import { useObservableState } from "observable-hooks" ; import React from "react" ; import { Observable } from "rxjs" ; import { createRecord , ids , record , getSchemas , updateRecord , updateRecords , withTransaction , records , getOrCreateRecord , } from "./helpers" ; import { ObservableWithInitial } from "./ObservableWithInitial" ; const DatastoreContext = React . createContext < null | Datastore > ( null ) ; /**
 * Sets the global datastore context. Either pass in an existing datastore
 * or args to create a new one.
 *
 * Components that use the other hooks must have this as a root.
 *
 * TODO: In the future use suspense for this once it's not beta.
 */ export const DatastoreRoot = ( { children , datastore , } ) => { const datastoreState = useObservableState ( datastore ) ; if ( datastoreState === undefined ) { return < div > Loading ... < /div>; } return ( < DatastoreContext . Provider value = { datastoreState } > { children } < /DatastoreContext.Provider>); } ; function useDatastore ( ) { const maybeDatastore = React . useContext ( DatastoreContext ) ; if ( maybeDatastore === null ) { throw new Error ( "Datastore not set, use DatastoreRoot as parent" ) ; } return maybeDatastore ; } function useDatastoreObservable < T > ( fn ) { const datastore = useDatastore ( ) ; const [ initial , changes ] = fn ( datastore ) ; return useObservableState ( changes , initial ) ; } export function useSchemas ( ) { return getSchemas ( useDatastore ( ) ) ; } export function useIds ( schema ) { return useDatastoreObservable ( React . useCallback ( ( datastore ) => ids ( datastore , schema ) , [ schema ] ) ) ; } export function useIdsFiltered < SCHEMA extends Schema > ( schema , filterFn ) { const records_ = useDatastoreObservable ( React . useCallback ( ( datastore ) => records ( datastore , schema ) , [ schema , filterFn ] ) ) ; return records_ . filter ( ( record ) => filterFn ( record ) ) . map ( ( record ) => record . $id ) ; } export function useWithTransaction ( ) { const datastore = useDatastore ( ) ; return React . useCallback ( ( callback ) => withTransaction ( datastore , callback ) , [ datastore , ] ) ; } export function useRecordValue < SCHEMA extends Schema > ( schema , id ) { return useDatastoreObservable ( React . useCallback ( ( datastore ) => record ( datastore , schema , id ) , [ schema , id , ] ) ) ; } export function useGetOrCreateRecord < SCHEMA extends Schema > ( schema , isValid , newRecord ) { return getOrCreateRecord ( useDatastore ( ) , schema , isValid , newRecord ) ; } export function useSetRecords < SCHEMA extends Schema > ( schema ) { const datastore = useDatastore ( ) ; return React . useCallback ( ( update ) => updateRecords ( datastore , schema , update ) , [ datastore , schema ] ) ; } export function useCreateRecord < SCHEMA extends Schema > ( schema ) { const datastore = useDatastore ( ) ; return React . useCallback ( ( update , options = { id : null } ) => createRecord ( datastore , schema , update , options ) , [ datastore , schema ] ) ; } export function useSetRecord < SCHEMA extends Schema > ( schema , id ) { const datastore = useDatastore ( ) ; return React . useCallback ( ( update ) => updateRecord ( datastore , schema , id , update ) , [ datastore , schema , id ] ) ; } export function useRecord < SCHEMA extends Schema > ( schema , id ) { return [ useRecordValue ( schema , id ) , useSetRecord ( schema , id ) ] ; }