├── .gitignore ├── .ocamlformat ├── Makefile ├── README.md ├── dune-project ├── melange-react-query.opam ├── melange-react-query.opam.template ├── package.json ├── src ├── ReactQuery.ml ├── ReactQuery_Client.ml ├── ReactQuery_DevTools.ml ├── ReactQuery_Hooks.ml ├── ReactQuery_InfiniteQuery.ml ├── ReactQuery_Mutation.ml ├── ReactQuery_Query.ml ├── ReactQuery_Types.ml ├── ReactQuery_Utils.ml └── dune └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.gitignore.io/api/node 3 | 4 | ### Node ### 5 | # Logs 6 | logs 7 | *.log 8 | npm-debug.log* 9 | yarn-debug.log* 10 | yarn-error.log* 11 | 12 | # Runtime data 13 | pids 14 | *.pid 15 | *.seed 16 | *.pid.lock 17 | 18 | # Directory for instrumented libs generated by jscoverage/JSCover 19 | lib-cov 20 | 21 | # Coverage directory used by tools like istanbul 22 | coverage 23 | 24 | # nyc test coverage 25 | .nyc_output 26 | 27 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 28 | .grunt 29 | 30 | # Bower dependency directory (https://bower.io/) 31 | bower_components 32 | 33 | # node-waf configuration 34 | .lock-wscript 35 | 36 | # Compiled binary addons (http://nodejs.org/api/addons.html) 37 | build/Release 38 | 39 | # Dependency directories 40 | node_modules/ 41 | jspm_packages/ 42 | 43 | # Typescript v1 declaration files 44 | typings/ 45 | 46 | # Optional npm cache directory 47 | .npm 48 | 49 | # Optional eslint cache 50 | .eslintcache 51 | 52 | # Optional REPL history 53 | .node_repl_history 54 | 55 | # Output of 'npm pack' 56 | *.tgz 57 | 58 | # Yarn Integrity file 59 | .yarn-integrity 60 | 61 | # dotenv environment variables file 62 | .env 63 | 64 | 65 | # End of https://www.gitignore.io/api/node 66 | 67 | .merlin 68 | 69 | _build 70 | _opam 71 | 72 | .vscode/ -------------------------------------------------------------------------------- /.ocamlformat: -------------------------------------------------------------------------------- 1 | profile=default 2 | break-infix=fit-or-vertical 3 | break-cases=fit-or-vertical 4 | break-fun-decl=fit-or-vertical 5 | break-fun-sig=fit-or-vertical 6 | if-then-else=vertical 7 | let-and=sparse 8 | let-binding-spacing=double-semicolon 9 | margin=90 10 | parens-ite=true 11 | type-decl=sparse 12 | wrap-fun-args=false -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | project_name = melange-moment 2 | 3 | DUNE = opam exec -- dune 4 | 5 | .DEFAULT_GOAL := help 6 | 7 | .PHONY: help 8 | help: ## Print this help message 9 | @echo "List of available make commands"; 10 | @echo ""; 11 | @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf " \033[36m%-15s\033[0m %s\n", $$1, $$2}'; 12 | @echo ""; 13 | 14 | .PHONY: create-switch 15 | create-switch: ## Create opam switch 16 | opam switch create . 5.1.0 -y --deps-only 17 | 18 | .PHONY: init 19 | init: create-switch install ## Configure everything to develop this repository in local 20 | 21 | .PHONY: install 22 | install: ## Install development dependencies 23 | yarn 24 | opam update 25 | opam install -y . --deps-only 26 | 27 | .PHONY: build 28 | build: ## Build the project 29 | $(DUNE) build 30 | 31 | .PHONY: build_verbose 32 | build_verbose: ## Build the project in verbose mode 33 | $(DUNE) build --verbose 34 | 35 | .PHONY: clean 36 | clean: ## Clean build artifacts and other generated files 37 | $(DUNE) clean 38 | 39 | .PHONY: format 40 | format: ## Format the codebase with ocamlformat 41 | $(DUNE) build @fmt --auto-promote 42 | 43 | .PHONY: format-check 44 | format-check: ## Checks if format is correct 45 | $(DUNE) build @fmt 46 | 47 | .PHONY: watch 48 | watch: ## Watch for the filesystem and rebuild on every change 49 | $(DUNE) build --watch 50 | 51 | .PHONY: test 52 | test: ## Run the tests 53 | $(DUNE) build @runtest --no-buffer 54 | 55 | .PHONY: test-watch 56 | test-watch: ## Run the tests and watch for changes 57 | $(DUNE) build -w @runtest -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # melange-react-query 2 | 3 | Bindings to [@tanstack/react-query](https://tanstack.com/query/latest) for [Melange](https://melange.re/). 4 | 5 | ## Installation 6 | 7 | ```sh 8 | opam install melange-react-query 9 | ``` 10 | 11 | Then add `melange-react-query` to the `libraries` field in your dune file: 12 | 13 | ```lisp 14 | (melange.emit ;; or (library ...) 15 | ... 16 | (libraries melange-react-query)) 17 | ``` 18 | 19 | ## Usage 20 | 21 | ### `Provider.createClient()` 22 | 23 | The function responsible to create the query client 24 | 25 | Usage: 26 | 27 | ```reason 28 | let client = Provider.createClient(); 29 | ``` 30 | 31 | ### `Provider.make()` 32 | 33 | The React Context Provider responsible to hold all the react-query context 34 | 35 | ```reason 36 | children 37 | ``` 38 | 39 | ### `DevTools.make(...)` 40 | 41 | The React Query DevTools Provider, which is responsible to initialize the React Query devtools 42 | 43 | ```reason 44 | 45 | ``` 46 | 47 | ### `useQueryClient()` 48 | 49 | The queryClient fetched from a hook 50 | 51 | ```reason 52 | let queryClient = ReactQuery.useQueryClient(); 53 | let queryResult = queryClient.fetchQuery( 54 | ReactQuery.fetchQueryOptions( 55 | ~queryKey=[|"articles"|], 56 | ~retryOnMount=true, 57 | (), 58 | ) 59 | ); 60 | ``` 61 | 62 | ### `useQuery` 63 | 64 | ```reason 65 | let queryResult = ReactQuery.useQuery( 66 | ReactQuery.queryOptions( 67 | ~queryKey=[|"articles"|], 68 | ~queryFn=fetchArticles, 69 | () 70 | ) 71 | ); 72 | ``` 73 | 74 | ### `useMutation` 75 | 76 | The hook responsible to mutate a query, when update/create/delete anything 77 | 78 | ```reason 79 | let mutationResult = ReactQuery.useMutation( 80 | ReactQuery.mutationOptions( 81 | ~mutationKey=[|"articles"|], 82 | ~mutationFn=(article) => addArticle(article), 83 | () 84 | ) 85 | ); 86 | ``` 87 | -------------------------------------------------------------------------------- /dune-project: -------------------------------------------------------------------------------- 1 | (lang dune 3.8) 2 | 3 | (using melange 0.1) 4 | 5 | (generate_opam_files true) 6 | 7 | (name melange-react-query) 8 | 9 | (version 0.1.0) 10 | 11 | (source 12 | (github ewert-online/melange-react-query)) 13 | 14 | (authors "Torben Ewert ") 15 | 16 | (maintainers "Torben Ewert ") 17 | 18 | (homepage "https://github.com/ewert-online/melange-react-query") 19 | 20 | (bug_reports "https://github.com/ewert-online/melange-react-query") 21 | 22 | (license "MIT") 23 | 24 | (package 25 | (name melange-react-query) 26 | (synopsis "React Query support for Melange") 27 | (depends 28 | (ocaml 29 | (>= "5.1")) 30 | (melange 31 | (>= "2.0.0")) 32 | reason-react 33 | reason-react-ppx 34 | (opam-check-npm-deps :with-test))) 35 | -------------------------------------------------------------------------------- /melange-react-query.opam: -------------------------------------------------------------------------------- 1 | # This file is generated by dune, edit dune-project instead 2 | opam-version: "2.0" 3 | version: "0.1.0" 4 | synopsis: "React Query support for Melange" 5 | maintainer: ["Torben Ewert "] 6 | authors: ["Torben Ewert "] 7 | license: "MIT" 8 | homepage: "https://github.com/ewert-online/melange-react-query" 9 | bug-reports: "https://github.com/ewert-online/melange-react-query" 10 | depends: [ 11 | "dune" {>= "3.8"} 12 | "ocaml" {>= "5.1"} 13 | "melange" {>= "2.0.0"} 14 | "reason-react" 15 | "reason-react-ppx" 16 | "opam-check-npm-deps" {with-test} 17 | "odoc" {with-doc} 18 | ] 19 | build: [ 20 | ["dune" "subst"] {dev} 21 | [ 22 | "dune" 23 | "build" 24 | "-p" 25 | name 26 | "-j" 27 | jobs 28 | "@install" 29 | "@runtest" {with-test} 30 | "@doc" {with-doc} 31 | ] 32 | ] 33 | dev-repo: "git+https://github.com/ewert-online/melange-react-query.git" 34 | depexts: [ 35 | ["@tanstack/react-query"] {npm-version = "^4.2.1"} 36 | ] -------------------------------------------------------------------------------- /melange-react-query.opam.template: -------------------------------------------------------------------------------- 1 | depexts: [ 2 | ["@tanstack/react-query"] {npm-version = "^4.2.1"} 3 | ] -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "devDependencies": { 3 | "react": "^18.2.0", 4 | "react-dom": "^18.2.0", 5 | "@tanstack/react-query": "^4.2.1" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/ReactQuery.ml: -------------------------------------------------------------------------------- 1 | include ReactQuery_InfiniteQuery 2 | include ReactQuery_Query 3 | include ReactQuery_Mutation 4 | include ReactQuery_Hooks 5 | include ReactQuery_Utils 6 | include ReactQuery_Client 7 | include ReactQuery_DevTools 8 | -------------------------------------------------------------------------------- /src/ReactQuery_Client.ml: -------------------------------------------------------------------------------- 1 | type queryClientValue 2 | type fetchMeta 3 | 4 | type notifyOnChangePropsKeys = 5 | [ `error 6 | | `isError 7 | | `isIdle 8 | | `isLoading 9 | | `isLoadingError 10 | | `isRefetchError 11 | | `isSuccess 12 | | `status 13 | | `tracked 14 | ] 15 | 16 | type infiniteQueryObserverResultProps = 17 | [ `error 18 | | `isError 19 | | `isIdle 20 | | `isLoading 21 | | `isLoadingError 22 | | `isRefetchError 23 | | `isSuccess 24 | | `status 25 | | `tracked 26 | ] 27 | 28 | type fetchContext 29 | type queryBehavior = { onFetch : fetchContext -> unit } 30 | 31 | let queryBehavior ~onFetch = { onFetch } 32 | 33 | type 'data getPreviousPageParamFunction = { 34 | firstPage : 'data; 35 | allPages : 'data array; 36 | } 37 | 38 | let getPreviousPageParamFunction ~firstPage ~allPages = { firstPage; allPages } 39 | 40 | type 'data getNextPageParamFunction = { 41 | lastPage : 'data; 42 | allPages : 'data array; 43 | } 44 | 45 | let getNextPageParamFunction ~lastPage ~allPages = { lastPage; allPages } 46 | 47 | type ('error, 'data, 'queryData, 'queryKey, 'pageParam) queryObserverOptions = { 48 | retry : 'error ReactQuery_Types.retryValue option; [@optional] 49 | retryDelay : 'error ReactQuery_Types.retryValue option; [@optional] 50 | cacheTime : int option; [@optional] 51 | isDataEqual : ('data option -> 'data -> bool) option; [@optional] 52 | queryHash : string option; [@optional] 53 | queryKey : 'queryKey option; [@optional] 54 | queryKeyHashFn : ('queryKey -> string) option; [@optional] 55 | initialData : (unit -> 'data) option; [@optional] 56 | initialDataUpdatedAt : (unit -> int option) option; [@optional] 57 | behavior : queryBehavior option; [@optional] 58 | structuralSharing : bool option; [@optional] 59 | getPreviousPageParam : 'data getPreviousPageParamFunction option; [@optional] 60 | getNextPageParam : 'data getNextPageParamFunction option; [@optional] 61 | defaulted : bool option; [@optional] 62 | enabled : bool option; [@optional] 63 | staleTime : int option; [@optional] 64 | refetchInterval : ReactQuery_Types.refetchIntervalValue option; [@optional] 65 | refetchIntervalInBackground : bool option; [@optional] 66 | refetchOnWindowFocus : ReactQuery_Types.boolOrAlwaysValue option; [@optional] 67 | refetchOnReconnect : ReactQuery_Types.boolOrAlwaysValue option; [@optional] 68 | refetchOnMount : ReactQuery_Types.boolOrAlwaysValue option; [@optional] 69 | retryOnMount : bool option; [@optional] 70 | notifyOnChangeProps : notifyOnChangePropsKeys array option; [@optional] 71 | notifyOnChangePropsExclusions : bool array option; [@optional] 72 | onSuccess : ('data -> unit) option; [@optional] 73 | onError : ('error -> unit) option; [@optional] 74 | onSettled : ('data option -> 'error option -> unit) option; [@optional] 75 | useErrorBoundary : bool option; [@optional] 76 | select : ('queryData -> 'data) option; [@optional] 77 | suspense : bool option; [@optional] 78 | keepPreviousData : bool option; [@optional] 79 | placeholderData : ReactQuery_Types.placeholderDataValue option; [@optional] 80 | optimisticResults : bool option; [@optional] 81 | queryFn : 82 | ('queryKey, 'pageParam) ReactQuery_Types.queryFunctionContext -> 83 | 'queryData Js.Promise.t; 84 | } 85 | 86 | type ('error, 'data, 'queryData, 'queryKey, 'pageParam) defaultOptions = { 87 | queries : ('error, 'data, 'queryData, 'queryKey, 'pageParam) queryObserverOptions option; 88 | } 89 | 90 | let defaultOptions ?queries () = { queries } 91 | 92 | type invalidateQueryFilter = { refetchType : [ `active | `inactive | `all | `none ] } 93 | 94 | let invalidateQueryFilter ~refetchType = { refetchType } 95 | 96 | type clientRefetchOptions = { throwOnError : bool option } 97 | 98 | let clientRefetchOptions ~throwOnError = { throwOnError } 99 | 100 | type 'queryKey invalidateQueryOptions = { 101 | queryKey : 'queryKey option; 102 | filters : invalidateQueryFilter option; 103 | refetchOptions : clientRefetchOptions option; 104 | } 105 | 106 | let invalidateQueryOptions ?queryKey ?filters ?refetchOptions () = 107 | { queryKey; filters; refetchOptions } 108 | ;; 109 | 110 | type 'queryKey refetchQueriesOptions = { 111 | queryKey : 'queryKey option; 112 | filters : 'queryKey ReactQuery_Types.queryFilter option; 113 | refetchOptions : clientRefetchOptions option; 114 | } 115 | 116 | let refetchQueriesOptions ?queryKey ?filters ?refetchOptions () = 117 | { queryKey; filters; refetchOptions } 118 | ;; 119 | 120 | type 'queryKey cancelQueriesOptions = { 121 | queryKey : 'queryKey option; 122 | filters : 'queryKey ReactQuery_Types.queryFilter option; 123 | } 124 | 125 | let cancelQueriesOptions ?queryKey ?filters () = { queryKey; filters } 126 | 127 | type ('queryData, 'queryError) queryState = { 128 | data : 'queryData option; 129 | dataUpdateCount : int; 130 | dataUpdatedAt : int; 131 | error : 'queryError Js.Nullable.t; 132 | errorUpdateCount : int; 133 | errorUpdatedAt : int; 134 | fetchFailureCount : int; 135 | fetchMeta : fetchMeta; 136 | isFetching : bool; 137 | isInvalidated : bool; 138 | isPaused : bool; 139 | status : ReactQuery_Types.queryStatus; 140 | } 141 | 142 | type ('queryKey, 'queryData, 'queryError, 'pageParam) fetchQueryOptions = { 143 | queryKey : 'queryKey option; 144 | queryFn : 145 | (('queryKey, 'pageParam) ReactQuery_Types.queryFunctionContext -> 146 | 'queryData Js.Promise.t) 147 | option; 148 | retry : 'queryError ReactQuery_Types.retryValue option; 149 | retryOnMount : bool option; 150 | retryDelay : 'queryError ReactQuery_Types.retryDelayValue option; 151 | staleTime : ReactQuery_Types.timeValue option; 152 | queryKeyHashFn : ('queryKey -> string) option; 153 | refetchOnMount : ReactQuery_Types.boolOrAlwaysValue option; 154 | structuralSharing : bool option; 155 | initialData : ('queryData -> 'queryData) option; 156 | initialDataUpdatedAt : (unit -> int) option; 157 | } 158 | 159 | let fetchQueryOptions 160 | ?queryKey 161 | ?queryFn 162 | ?retry 163 | ?retryOnMount 164 | ?retryDelay 165 | ?staleTime 166 | ?queryKeyHashFn 167 | ?refetchOnMount 168 | ?structuralSharing 169 | ?initialData 170 | ?initialDataUpdatedAt 171 | () = 172 | { 173 | queryKey; 174 | queryFn; 175 | retry; 176 | retryOnMount; 177 | retryDelay; 178 | staleTime; 179 | queryKeyHashFn; 180 | refetchOnMount; 181 | structuralSharing; 182 | initialData; 183 | initialDataUpdatedAt; 184 | } 185 | ;; 186 | 187 | type ('queryKey, 'queryData, 'queryError, 'pageParams) queryClient = { 188 | fetchQuery : 189 | ('queryKey, 'queryData, 'queryError, 'pageParams) fetchQueryOptions -> 190 | 'queryData Js.Promise.t; 191 | fetchInfiniteQuery : 192 | ('queryKey, 'queryData, 'queryError, 'pageParams) fetchQueryOptions -> 193 | 'queryData ReactQuery_Types.infiniteData Js.Promise.t; 194 | prefetchQuery : 195 | ('queryKey, 'queryData, 'queryError, 'pageParams) fetchQueryOptions -> 196 | unit Js.Promise.t; 197 | prefetchInfiniteQuery : 198 | ('queryKey, 'queryData, 'queryError, 'pageParams) fetchQueryOptions -> 199 | unit Js.Promise.t; 200 | getQueryData : 'queryKey -> 'queryData option; 201 | setQueryData : 'queryKey -> 'queryData option -> 'queryData; 202 | getQueryState : 203 | 'queryKey -> 204 | 'queryKey ReactQuery_Types.queryFilter -> 205 | ('queryData, 'queryError) queryState; 206 | setQueriesData : 207 | 'queryKey ReactQuery_Types.queryDataKeyOrFilterValue -> 208 | ('queryData option -> 'queryData) -> 209 | unit; 210 | invalidateQueries : 211 | 'queryKey ReactQuery_Types.queryFilter option -> 212 | clientRefetchOptions option -> 213 | unit Js.Promise.t; 214 | refetchQueries : 215 | 'queryKey ReactQuery_Types.queryFilter option -> 216 | clientRefetchOptions option -> 217 | unit Js.Promise.t; 218 | cancelQueries : 'queryKey ReactQuery_Types.queryFilter option -> unit Js.Promise.t; 219 | removeQueries : 'queryKey ReactQuery_Types.queryFilter option -> unit Js.Promise.t; 220 | resetQueries : 221 | 'queryKey ReactQuery_Types.queryFilter option -> 222 | clientRefetchOptions option -> 223 | unit Js.Promise.t; 224 | isFetching : 'queryKey ReactQuery_Types.queryFilter option -> bool; 225 | isMutating : 'queryKey ReactQuery_Types.queryFilter option -> bool; 226 | clear : unit -> unit; 227 | } 228 | 229 | external useQueryClient : 230 | unit -> ('queryKey, 'queryData, 'queryError, 'pageParams) queryClient 231 | = "useQueryClient" 232 | [@@module "@tanstack/react-query"] 233 | 234 | module Provider = struct 235 | external createClient : unit -> queryClientValue = "QueryClient" 236 | [@@new] [@@module "@tanstack/react-query"] 237 | 238 | external make : 239 | client:queryClientValue -> 240 | ?contextSharing:bool -> 241 | children:React.element -> 242 | React.element 243 | = "QueryClientProvider" 244 | [@@module "@tanstack/react-query"] [@@react.component] 245 | end 246 | -------------------------------------------------------------------------------- /src/ReactQuery_DevTools.ml: -------------------------------------------------------------------------------- 1 | external make : ?initialIsOpen:bool -> React.element = "ReactQueryDevtools" 2 | [@@react.component] [@@module "@tanstack/react-query-devtools"] 3 | -------------------------------------------------------------------------------- /src/ReactQuery_Hooks.ml: -------------------------------------------------------------------------------- 1 | type resetErrorBoundary = { reset : unit -> unit } 2 | 3 | external useIsFetching : unit -> bool = "useIsFetching" [@@module "@tanstack/react-query"] 4 | 5 | external useIsFetchingWithKeys : 'queryKey -> bool = "useIsFetching" 6 | [@@module "@tanstack/react-query"] 7 | 8 | external useIsMutating : unit -> bool = "useIsMutating" [@@module "@tanstack/react-query"] 9 | 10 | external useIsMutatingWithKeys : 'queryKey -> bool = "useIsMutating" 11 | [@@module "@tanstack/react-query"] 12 | 13 | external useQueryErrorResetBoundary : 14 | unit -> resetErrorBoundary 15 | = "useQueryErrorResetBoundary" 16 | [@@module "@tanstack/react-query"] 17 | -------------------------------------------------------------------------------- /src/ReactQuery_InfiniteQuery.ml: -------------------------------------------------------------------------------- 1 | type 'queryKey inifiniteQueryFunctionContext = { 2 | queryKey : 'queryKey; 3 | pageParam : int option; 4 | } 5 | 6 | let inifiniteQueryFunctionContext ?pageParam ~queryKey () = { queryKey; pageParam } 7 | 8 | type ('queryKey, 'queryData, 'queryError) infiniteQueryOptions = { 9 | queryKey : 'queryKey option; 10 | queryFn : ('queryKey inifiniteQueryFunctionContext -> 'queryData Js.Promise.t) option; 11 | enabled : bool option; 12 | retry : 'queryError ReactQuery_Types.retryValue option; 13 | retryOnMount : bool option; 14 | retryDelay : 'queryError ReactQuery_Types.retryDelayValue option; 15 | staleTime : ReactQuery_Types.timeValue option; 16 | queryKeyHashFn : ('queryKey -> string) option; 17 | refetchInterval : ReactQuery_Types.refetchIntervalValue option; 18 | refetchIntervalInBackground : bool option; 19 | refetchOnMount : ReactQuery_Types.boolOrAlwaysValue option; 20 | refetchOnWindowFocus : ReactQuery_Types.boolOrAlwaysValue option; 21 | refetchOnReconnect : ReactQuery_Types.boolOrAlwaysValue option; 22 | notifyOnChangeProps : ReactQuery_Types.notifyOnChangePropsValue option; 23 | notifyOnChangePropsExclusions : string array option; 24 | onSuccess : ('queryData -> unit) option; 25 | onError : ('queryError -> unit) option; 26 | onSettled : ('queryData -> 'queryError -> unit) option; 27 | select : ('queryData -> 'queryData) option; 28 | suspense : bool option; 29 | keepPreviousData : bool option; 30 | structuralSharing : bool option; 31 | useErrorBoundary : bool option; 32 | initialData : ('queryData -> 'queryData) option; 33 | initialDataUpdatedAt : (unit -> int) option; 34 | placeholderData : (unit -> 'queryData) option; 35 | getNextPageParam : ('queryData -> int option) option; 36 | getPreviousPageParam : ('queryData -> int option) option; 37 | } 38 | 39 | let infiniteQueryOptions 40 | ?queryKey 41 | ?queryFn 42 | ?enabled 43 | ?retry 44 | ?retryOnMount 45 | ?retryDelay 46 | ?staleTime 47 | ?queryKeyHashFn 48 | ?refetchInterval 49 | ?refetchIntervalInBackground 50 | ?refetchOnMount 51 | ?refetchOnWindowFocus 52 | ?refetchOnReconnect 53 | ?notifyOnChangeProps 54 | ?notifyOnChangePropsExclusions 55 | ?onSuccess 56 | ?onError 57 | ?onSettled 58 | ?select 59 | ?suspense 60 | ?keepPreviousData 61 | ?structuralSharing 62 | ?useErrorBoundary 63 | ?initialData 64 | ?initialDataUpdatedAt 65 | ?placeholderData 66 | ?getNextPageParam 67 | ?getPreviousPageParam 68 | () = 69 | { 70 | queryKey; 71 | queryFn; 72 | enabled; 73 | retry; 74 | retryOnMount; 75 | retryDelay; 76 | staleTime; 77 | queryKeyHashFn; 78 | refetchInterval; 79 | refetchIntervalInBackground; 80 | refetchOnMount; 81 | refetchOnWindowFocus; 82 | refetchOnReconnect; 83 | notifyOnChangeProps; 84 | notifyOnChangePropsExclusions; 85 | onSuccess; 86 | onError; 87 | onSettled; 88 | select; 89 | suspense; 90 | keepPreviousData; 91 | structuralSharing; 92 | useErrorBoundary; 93 | initialData; 94 | initialDataUpdatedAt; 95 | placeholderData; 96 | getNextPageParam; 97 | getPreviousPageParam; 98 | } 99 | ;; 100 | 101 | type ('queryError, 'queryData) infiniteQueryResult = { 102 | status : ReactQuery_Types.queryStatus; 103 | isIdle : bool; 104 | isError : bool; 105 | isFetched : bool; 106 | isFetchedAfterMount : bool; 107 | isFetching : bool; 108 | isLoading : bool; 109 | isLoadingError : bool; 110 | isPlaceholderData : bool; 111 | isPreviousData : bool; 112 | isRefetchError : bool; 113 | isStale : bool; 114 | isSuccess : bool; 115 | dataUpdatedAt : int; 116 | error : 'queryError Js.Nullable.t; 117 | errorUpdatedAt : int; 118 | failureCount : int; 119 | refetch : 120 | ReactQuery_Types.refetchOptions -> 121 | ('queryError, 'queryData) infiniteQueryResult Js.Promise.t; 122 | remove : unit -> unit; 123 | data : 'queryData ReactQuery_Types.infiniteData option; 124 | isFetchingNextPage : bool; 125 | isFetchingPreviousPage : bool; 126 | fetchNextPage : unit -> unit; 127 | hasNextPage : bool; 128 | hasPreviousPage : bool; 129 | } 130 | 131 | external useInfiniteQuery : 132 | ('queryKey, 'queryData, 'queryError) infiniteQueryOptions -> 133 | ('queryError, 'queryData) infiniteQueryResult 134 | = "useInfiniteQuery" 135 | [@@module "@tanstack/react-query"] 136 | -------------------------------------------------------------------------------- /src/ReactQuery_Mutation.ml: -------------------------------------------------------------------------------- 1 | type mutationContext 2 | 3 | type mutationStatus = 4 | [ `loading 5 | | `success 6 | | `error 7 | ] 8 | 9 | type ('mutationVariables, 'mutationData, 'mutationError, 'unknown) mutateParams = { 10 | onSuccess : 11 | ('mutationData -> 12 | 'mutationVariables -> 13 | mutationContext Js.Nullable.t -> 14 | 'unknown Js.Promise.t) 15 | option; 16 | onError : 17 | ('mutationError -> 18 | 'mutationVariables -> 19 | mutationContext Js.Nullable.t -> 20 | 'unknown Js.Promise.t) 21 | option; 22 | onSettled : 23 | ('mutationData -> 24 | 'mutationError -> 25 | 'mutationVariables -> 26 | mutationContext Js.Nullable.t -> 27 | 'unknown Js.Promise.t) 28 | option; 29 | } 30 | 31 | type ('mutationVariables, 'mutationData, 'mutationError, 'unknown) mutationOptions = { 32 | mutationKey : string array; 33 | mutationFn : 'mutationVariables -> 'mutationData Js.Promise.t; 34 | onMutate : ('mutationVariables -> mutationContext Js.Promise.t) option; 35 | onSuccess : 36 | ('mutationData -> 37 | 'mutationVariables -> 38 | mutationContext Js.Nullable.t -> 39 | 'unknown Js.Promise.t) 40 | option; 41 | onError : 42 | ('mutationError -> 43 | 'mutationVariables -> 44 | mutationContext Js.Nullable.t -> 45 | 'unknown Js.Promise.t) 46 | option; 47 | onSettled : 48 | ('mutationData -> 49 | 'mutationError -> 50 | 'mutationVariables -> 51 | mutationContext Js.Nullable.t -> 52 | 'unknown Js.Promise.t) 53 | option; 54 | retry : 'mutationError ReactQuery_Types.retryValue option; 55 | retryDelay : 'mutationError ReactQuery_Types.retryDelayValue option; 56 | useErrorBoundary : bool option; 57 | } 58 | 59 | let mutationOptions 60 | ?onMutate 61 | ?onSuccess 62 | ?onError 63 | ?onSettled 64 | ?retry 65 | ?retryDelay 66 | ?useErrorBoundary 67 | ~mutationKey 68 | ~mutationFn 69 | () = 70 | { 71 | mutationKey; 72 | mutationFn; 73 | onMutate; 74 | onSuccess; 75 | onError; 76 | onSettled; 77 | retry; 78 | retryDelay; 79 | useErrorBoundary; 80 | } 81 | ;; 82 | 83 | type ('mutationVariables, 'mutationData, 'mutationError, 'unknown) mutationResult = { 84 | mutate : 85 | ('mutationVariables -> 86 | ('mutationVariables, 'mutationData, 'mutationError, 'unknown) mutateParams option -> 87 | unit 88 | [@u]); 89 | mutateAsync : 90 | 'mutationVariables -> 91 | ('mutationVariables, 'mutationData, 'mutationError, 'unknown) mutateParams -> 92 | 'mutationData Js.Promise.t; 93 | status : mutationStatus; 94 | isIdle : bool; 95 | isError : bool; 96 | isLoading : bool; 97 | isSuccess : bool; 98 | data : 'mutationData option; 99 | error : 'mutationError Js.Nullable.t; 100 | reset : unit -> unit; 101 | } 102 | 103 | external useMutation : 104 | ('mutationVariables, 'mutationData, 'mutationError, 'unknown) mutationOptions -> 105 | ('mutationVariables, 'mutationData, 'mutationError, 'unknown) mutationResult 106 | = "useMutation" 107 | [@@module "@tanstack/react-query"] 108 | -------------------------------------------------------------------------------- /src/ReactQuery_Query.ml: -------------------------------------------------------------------------------- 1 | type ('queryKey, 'queryData, 'queryError, 'pageParam) queryOptions = { 2 | queryKey : 'queryKey array option; 3 | queryFn : 4 | (('queryKey array, 'pageParam) ReactQuery_Types.queryFunctionContext -> 5 | 'queryData Js.Promise.t) 6 | option; 7 | enabled : bool option; 8 | retry : 'queryError ReactQuery_Types.retryValue option; 9 | retryOnMount : bool option; 10 | retryDelay : 'queryError ReactQuery_Types.retryDelayValue option; 11 | staleTime : ReactQuery_Types.timeValue option; 12 | queryKeyHashFn : ('queryKey array -> string) option; 13 | refetchInterval : ReactQuery_Types.refetchIntervalValue option; 14 | refetchIntervalInBackground : bool option; 15 | refetchOnMount : ReactQuery_Types.boolOrAlwaysValue option; 16 | refetchOnWindowFocus : ReactQuery_Types.boolOrAlwaysValue option; 17 | refetchOnReconnect : ReactQuery_Types.boolOrAlwaysValue option; 18 | notifyOnChangeProps : ReactQuery_Types.notifyOnChangePropsValue option; 19 | notifyOnChangePropsExclusions : string array option; 20 | onSuccess : ('queryData -> unit) option; 21 | onError : ('queryError -> unit) option; 22 | onSettled : ('queryData -> 'queryError -> unit) option; 23 | select : ('queryData -> 'queryData) option; 24 | suspense : bool option; 25 | keepPreviousData : bool option; 26 | structuralSharing : bool option; 27 | useErrorBoundary : bool option; 28 | initialData : ('queryData -> 'queryData) option; 29 | initialDataUpdatedAt : (unit -> int) option; 30 | placeholderData : (unit -> 'queryData) option; 31 | } 32 | 33 | let queryOptions 34 | ?queryKey 35 | ?queryFn 36 | ?enabled 37 | ?retry 38 | ?retryOnMount 39 | ?retryDelay 40 | ?staleTime 41 | ?queryKeyHashFn 42 | ?refetchInterval 43 | ?refetchIntervalInBackground 44 | ?refetchOnMount 45 | ?refetchOnWindowFocus 46 | ?refetchOnReconnect 47 | ?notifyOnChangeProps 48 | ?notifyOnChangePropsExclusions 49 | ?onSuccess 50 | ?onError 51 | ?onSettled 52 | ?select 53 | ?suspense 54 | ?keepPreviousData 55 | ?structuralSharing 56 | ?useErrorBoundary 57 | ?initialData 58 | ?initialDataUpdatedAt 59 | ?placeholderData 60 | () = 61 | { 62 | queryKey; 63 | queryFn; 64 | enabled; 65 | retry; 66 | retryOnMount; 67 | retryDelay; 68 | staleTime; 69 | queryKeyHashFn; 70 | refetchInterval; 71 | refetchIntervalInBackground; 72 | refetchOnMount; 73 | refetchOnWindowFocus; 74 | refetchOnReconnect; 75 | notifyOnChangeProps; 76 | notifyOnChangePropsExclusions; 77 | onSuccess; 78 | onError; 79 | onSettled; 80 | select; 81 | suspense; 82 | keepPreviousData; 83 | structuralSharing; 84 | useErrorBoundary; 85 | initialData; 86 | initialDataUpdatedAt; 87 | placeholderData; 88 | } 89 | ;; 90 | 91 | type ('queryError, 'queryData) queryResult = { 92 | status : ReactQuery_Types.queryStatus; 93 | isIdle : bool; 94 | isError : bool; 95 | isFetched : bool; 96 | isFetchedAfterMount : bool; 97 | isFetching : bool; 98 | isLoading : bool; 99 | isLoadingError : bool; 100 | isPlaceholderData : bool; 101 | isPreviousData : bool; 102 | isRefetchError : bool; 103 | isStale : bool; 104 | isSuccess : bool; 105 | data : 'queryData option; 106 | dataUpdatedAt : int; 107 | error : 'queryError Js.Nullable.t; 108 | errorUpdatedAt : int; 109 | failureCount : int; 110 | refetch : 111 | ReactQuery_Types.refetchOptions -> ('queryError, 'queryData) queryResult Js.Promise.t; 112 | remove : unit -> unit; 113 | } 114 | 115 | external useQuery : 116 | ('queryKey, 'queryData, 'queryError, 'pageParam) queryOptions -> 117 | ('queryError, 'queryData) queryResult 118 | = "useQuery" 119 | [@@module "@tanstack/react-query"] 120 | 121 | external useQueries : 122 | ('queryKey, 'queryData, 'queryError, 'pageParam) queryOptions array -> 123 | ('queryError, 'queryData) queryResult array 124 | = "useQueries" 125 | [@@module "@tanstack/react-query"] 126 | -------------------------------------------------------------------------------- /src/ReactQuery_Types.ml: -------------------------------------------------------------------------------- 1 | type query 2 | type timeValue 3 | type boolOrAlwaysValue 4 | type refetchIntervalValue 5 | type notifyOnChangePropsValue 6 | type 'queryError retryValue 7 | type 'queryError retryDelayValue 8 | type 'queryKey queryDataKeyOrFilterValue 9 | type placeholderDataValue 10 | 11 | type ('queryKey, 'pageParam) queryFunctionContext = { 12 | queryKey : 'queryKey; 13 | pageParam : 'pageParam; 14 | } 15 | 16 | let queryFunctionContext ~queryKey ~pageParam = { queryKey; pageParam } 17 | 18 | type 'error retryParam = 19 | [ `bool of bool 20 | | `number of int 21 | | `fn of int -> 'error -> bool 22 | ] 23 | 24 | type 'error retryDelayParam = 25 | [ `number of int 26 | | `fn of int -> 'error -> int 27 | ] 28 | 29 | type time = 30 | [ `number of int 31 | | `infinity 32 | ] 33 | 34 | type refetchInterval = 35 | [ `bool of bool 36 | | `number of int 37 | ] 38 | 39 | type boolOrAlways = 40 | [ `bool of bool 41 | | `always 42 | ] 43 | 44 | type notifyOnChangeProps = 45 | [ `array of string array 46 | | `all 47 | ] 48 | 49 | type 'queryData infiniteData = { 50 | pages : 'queryData array; 51 | pageParams : int array; 52 | } 53 | 54 | let infiniteData ~pages ~pageParams = { pages; pageParams } 55 | 56 | type queryStatus = 57 | [ `loading 58 | | `success 59 | | `error 60 | | `initialData 61 | ] 62 | 63 | type ('queryData, 'queryResult) placeholderData = 64 | [ `data of 'queryData 65 | | `fn of unit -> 'queryResult option [@as "function"] 66 | ] 67 | 68 | type 'queryKey queryFilter = { 69 | exact : bool option; 70 | type_ : [ `active | `inactive | `all ] option; [@as "type"] 71 | stale : bool option; 72 | fetching : bool option; 73 | predicate : (query -> bool) option; 74 | queryKey : 'queryKey option; 75 | } 76 | 77 | let queryFilter ?exact ?type_ ?stale ?fetching ?predicate ?queryKey () = 78 | { exact; type_; stale; fetching; predicate; queryKey } 79 | ;; 80 | 81 | type 'queryKey queryDataKeyOrFilter = 82 | [ `keys of 'queryKey 83 | | `filters of 'queryKey queryFilter 84 | ] 85 | 86 | type refetchOptions = { 87 | throwOnError : bool; 88 | cancelRefetch : bool; 89 | } 90 | 91 | let refetchOptions ~throwOnError ~cancelRefetch = { throwOnError; cancelRefetch } 92 | -------------------------------------------------------------------------------- /src/ReactQuery_Utils.ml: -------------------------------------------------------------------------------- 1 | let retry : 'error ReactQuery_Types.retryParam -> 'error ReactQuery_Types.retryValue = 2 | function 3 | | `bool value -> Obj.magic value 4 | | `number value -> Obj.magic value 5 | | `fn value -> Obj.magic value 6 | ;; 7 | 8 | let retryDelay : 9 | 'error ReactQuery_Types.retryDelayParam -> 'error ReactQuery_Types.retryDelayValue = 10 | function 11 | | `number value -> Obj.magic value 12 | | `fn value -> Obj.magic value 13 | ;; 14 | 15 | let time : ReactQuery_Types.time -> ReactQuery_Types.timeValue = function 16 | | `number value -> Obj.magic value 17 | | `infinity -> Obj.magic infinity 18 | ;; 19 | 20 | let refetchInterval = function 21 | | `bool value -> Obj.magic value 22 | | `number value -> Obj.magic value 23 | ;; 24 | 25 | let boolOrAlways = function 26 | | `bool value -> Obj.magic value 27 | | `always -> Obj.magic `always 28 | ;; 29 | 30 | let notifyOnChangeProps = function 31 | | `array value -> Obj.magic value 32 | | `tracked -> Obj.magic `tracked 33 | ;; 34 | 35 | let setQueryData : 36 | 'queryKey ReactQuery_Types.queryDataKeyOrFilter -> 37 | 'queryKey ReactQuery_Types.queryDataKeyOrFilter = function 38 | | `keys value -> Obj.magic value 39 | | `filters value -> Obj.magic value 40 | ;; 41 | 42 | let placeholderData : 43 | ('queryData, 'queryResult) ReactQuery_Types.placeholderData -> 44 | ReactQuery_Types.placeholderDataValue = function 45 | | `data data -> Obj.magic data 46 | | ((`fn value) [@as "function"]) -> Obj.magic value 47 | ;; 48 | 49 | let refetchOnMount = boolOrAlways 50 | let refetchOnWindowFocus = boolOrAlways 51 | let refetchOnReconnect = boolOrAlways 52 | -------------------------------------------------------------------------------- /src/dune: -------------------------------------------------------------------------------- 1 | (library 2 | (name ReactQuery) 3 | (public_name melange-react-query) 4 | (libraries reason-react) 5 | (preprocess 6 | (pps melange.ppx reason-react-ppx)) 7 | (modes melange)) 8 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | "@tanstack/query-core@4.36.1": 6 | version "4.36.1" 7 | resolved "https://registry.yarnpkg.com/@tanstack/query-core/-/query-core-4.36.1.tgz#79f8c1a539d47c83104210be2388813a7af2e524" 8 | integrity sha512-DJSilV5+ytBP1FbFcEJovv4rnnm/CokuVvrBEtW/Va9DvuJ3HksbXUJEpI0aV1KtuL4ZoO9AVE6PyNLzF7tLeA== 9 | 10 | "@tanstack/react-query@^4.2.1": 11 | version "4.36.1" 12 | resolved "https://registry.yarnpkg.com/@tanstack/react-query/-/react-query-4.36.1.tgz#acb589fab4085060e2e78013164868c9c785e5d2" 13 | integrity sha512-y7ySVHFyyQblPl3J3eQBWpXZkliroki3ARnBKsdJchlgt7yJLRDUcf4B8soufgiYt3pEQIkBWBx1N9/ZPIeUWw== 14 | dependencies: 15 | "@tanstack/query-core" "4.36.1" 16 | use-sync-external-store "^1.2.0" 17 | 18 | "js-tokens@^3.0.0 || ^4.0.0": 19 | version "4.0.0" 20 | resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" 21 | integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== 22 | 23 | loose-envify@^1.1.0: 24 | version "1.4.0" 25 | resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" 26 | integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== 27 | dependencies: 28 | js-tokens "^3.0.0 || ^4.0.0" 29 | 30 | react-dom@^18.2.0: 31 | version "18.2.0" 32 | resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.2.0.tgz#22aaf38708db2674ed9ada224ca4aa708d821e3d" 33 | integrity sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g== 34 | dependencies: 35 | loose-envify "^1.1.0" 36 | scheduler "^0.23.0" 37 | 38 | react@^18.2.0: 39 | version "18.2.0" 40 | resolved "https://registry.yarnpkg.com/react/-/react-18.2.0.tgz#555bd98592883255fa00de14f1151a917b5d77d5" 41 | integrity sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ== 42 | dependencies: 43 | loose-envify "^1.1.0" 44 | 45 | scheduler@^0.23.0: 46 | version "0.23.0" 47 | resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.23.0.tgz#ba8041afc3d30eb206a487b6b384002e4e61fdfe" 48 | integrity sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw== 49 | dependencies: 50 | loose-envify "^1.1.0" 51 | 52 | use-sync-external-store@^1.2.0: 53 | version "1.2.0" 54 | resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz#7dbefd6ef3fe4e767a0cf5d7287aacfb5846928a" 55 | integrity sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA== 56 | --------------------------------------------------------------------------------