@@ -23,11 +23,11 @@ return function View() {
2323```
2424~~~
2525
26- ## Fetching Data
26+ ## Query Hooks
2727
2828Datacore provides several methods for querying for data, including by the full query language and by path explicitly.
2929
30- #### ` dc.useCurrentFile() `
30+ ### ` dc.useCurrentFile() `
3131
3232Loads the metadata for the file that the view is in - this will usually be ` MarkdownPage ` , but can also be a ` CanvasPage ` .
3333Using this hook will automatically refresh the view whenever the current file changes.
@@ -48,7 +48,7 @@ should update via the `debounce` property.
4848const file = dc .useCurrentFile ({ debounce: 10000 });
4949```
5050
51- #### ` dc.useCurrentPath() `
51+ ### ` dc.useCurrentPath() `
5252
5353Loads the path of the file that the view is in - this will usually be ` MarkdownPage ` , but can also be a ` CanvasPage ` .
5454Using this hook will automatically refresh the view whenever the current file changes.
@@ -68,7 +68,7 @@ Like `useCurrentFile`, `dc.useCurrentPath` accepts an optional settings argument
6868const path = dc .useCurrentPath ({ debounce: 10000 });
6969```
7070
71- #### ` dc.useQuery() `
71+ ### ` dc.useQuery() `
7272
7373Query for a list of results using the [ query language] ( /data/query ) . This will return a vanilla javascript list containing
7474all of the results that match the query, which can be a wide range of different data types. This hook will cause the view
@@ -94,8 +94,7 @@ return function View() {
9494}
9595```
9696
97-
98- #### ` dc.useFullQuery() `
97+ ### ` dc.useFullQuery() `
9998
10099Variant of ` dc.useQuery ` which returns a full search result object, which mainly provides a bit of useful extra metadata about how the
101100search performed. Specifically, it returns the following data:
@@ -127,7 +126,7 @@ return function View() {
127126}
128127```
129128
130- #### ` dc.useIndexUpdates() `
129+ ### ` dc.useIndexUpdates() `
131130
132131A minimal query which just returns the current ` revision ` of the datacore index. The index ` revision ` is a monotonically increasing number
133132which is incremented every time something in your vault changes. This call is mainly useful if you are making heavy usage of direct
@@ -136,8 +135,306 @@ changes in your vault.
136135
137136``` jsx
138137return function View () {
138+ // Revision will update on every index update.
139+ const revision = dc .useIndexUpdates ();
140+
141+ // Run some complex query that will be re-run on every revision update.
142+ const complexQuery = dc .useMemo (() => {
143+ const thing = dc .query (/* ... */ );
144+ // ...
145+ }, [revision]);
146+ }
147+ ```
148+
149+ Like the other hooks, ` dc.useIndexUpdates ` accepts an optional settings parameter, which allows you to set a debounce:
150+
151+ ``` jsx
152+ // Only update at most once every ten seconds.
153+ const revision = dc .useIndexUpdates ({ debounce: 10000 });
154+ ```
155+
156+ ## Common React Hooks
157+
158+ Datacore forwards the most common React hooks through it's API to make them available. The full list, with brief explanations of each, is:
159+
160+ - ` dc.useState ` : Create a React state variable that can be read and updated.
161+ - ` dc.useReducer ` : Create a React reducer which accepts messages to update internal state.
162+ - ` dc.useMemo ` : Memoize a value so it only updates when a dependency array changes.
163+ - ` dc.useCallback ` : Memoize a function so it only is re-created when a dependency array changes.
164+ - ` dc.useEffect ` : Run a specific 'side-effect' whenever a dependency array changes.
165+ - ` dc.createContext ` : Create a react context which allows passing state down many layers without prop drilling.
166+ - ` dc.useContext ` : Use a previously created context.
167+ - ` dc.useRef ` : A state-like variable that allows directly storing a value without causing React re-renders.
168+
169+ Datacore also provides a few other useful hooks for specifically interacting with datacore utilities:
170+
171+ ### ` dc.useArray() `
172+
173+ Accepts a regular array, wraps it in a data array, executes a function on the data array, and then converts back to a normal array.
174+ This is primarily useful for when you want to take advantage of [ Data Array] ( data-array ) utilities while otherwise using vanilla
175+ javascript arrays for compatibility with preact/react.
176+
177+ ``` jsx
178+ return function View () {
179+ const pages = dc .useQuery (" @page and #book" );
180+ const grouped = dc .useArray (pages, array => array .groupBy (book => book .value (" genre" )));
181+
182+ return < dc .List rows= {grouped} renderer= {book => book .$link } / >
183+ }
184+ ```
185+
186+ ` dc.useArray ` also accepts a dependency array if you depend on state other than the array itself:
187+
188+ ``` jsx
189+ const [searchTerm , setSearchTerm ] = dc .useState (" " );
190+ const pages = dc .useQuery (" @page and #book" );
191+
192+ const filteredPages = dc .useArray (
193+ pages,
194+ array => array .filter (book => book .$title .includes (searchTerm)),
195+ [searchTerm]);
196+ ```
197+
198+ ## Direct Queries
199+
200+ The datacore API also provides several methods for directly querying the index outside of a hook. These can be called from anywhere, but note that,
201+ because they are not hooks, they will _ not_ cause your view to update if the query would update. To have your queries re-run every time the
202+ index changes, combine it with ` dc.useIndexUpdates ` , which will trigger a re-render on every vault change:
139203
204+ ``` jsx
205+ return function View () {
206+ // Revision will update on every index update.
207+ const revision = dc .useIndexUpdates ();
208+
209+ // Run some complex query that will be re-run on every revision update.
210+ const complexQuery = dc .useMemo (() => {
211+ const thing = dc .query (/* ... */ );
212+ // ...
213+ }, [revision]);
140214}
141215```
142216
143- Like the other hooks, ` dc.useIndexUpdates ` accepts an optional second parameter of configuration.
217+ ### ` dc.query() `
218+
219+ Execute a [ query] ( /data/query ) against the datacore index, returning a list of all matched [ results] ( /data/index ) . Will raise an exception
220+ if the query is malformed.
221+
222+ ``` jsx
223+ dc .query (" @page" ) => // list of all pages
224+ dc .query (" @page and #book and rating > 7" ) => // all pages tagged book with a rating higher than 7.
225+ ```
226+
227+ ### ` dc.tryQuery() `
228+
229+ Equivalent to ` dc.query ` , but returns a datacore ` Result ` instead of raising an exception.
230+
231+ ``` jsx
232+ dc .tryQuery (" @page" ) => { successful: true , value: [/* list of pages */ ] }
233+ dc .tryQuery (" fakefunction(@page)" ) => { successful: false , error: " malformed query..." }
234+ ```
235+
236+ ### ` dc.fullquery() `
237+
238+ Equivalent to ` dc.query ` , but returns several additional pieces of metadata about how long the query took to execute:
239+
240+ ``` jsx
241+ dc .fullquery (" @page" ) => {
242+ // Parsed query representation.
243+ query: { type: " type" , type: " page" },
244+ // Actual results, like you would get from `dc.query`.
245+ results: [/* list of pages */ ],
246+ // Query runtime in seconds, accurate to the millisecond.
247+ duration: 0.01 ,
248+ // Index revision the query was executed against.
249+ revision: 317 ,
250+ }
251+ ```
252+
253+ ### ` dc.tryFullQuery() `
254+
255+ Equivalent to ` dc.fullquery ` , but returns a datacore ` Result ` instead of raising an exception on an invalid query.
256+
257+ ``` jsx
258+ dc .tryFullQuery (" @page" ) => {
259+ successful: true ,
260+ value: {
261+ // Parsed query representation.
262+ query: { type: " type" , type: " page" },
263+ // Actual results, like you would get from `dc.query`.
264+ results: [/* list of pages */ ],
265+ // Query runtime in seconds, accurate to the millisecond.
266+ duration: 0.01 ,
267+ // Index revision the query was executed against.
268+ revision: 317 ,
269+ }
270+ }
271+
272+ dc .tryFullQuery (" malformed(@page)" ) => {
273+ successful: false ,
274+ error: " malformed query ..." ,
275+ }
276+ ```
277+
278+ ## Links
279+
280+ Utilities for creating datacore ` Link ` types and normalizing paths.
281+
282+ ### ` dc.resolvePath() `
283+
284+ Resolves a local or absolute path to an absolute path, optionally from a given source path.
285+
286+ ``` jsx
287+ // Can resolve by file name.
288+ dc .resolvePath (" Test" ) = " location/To/Test.md"
289+ // Can resolve from an alternative source path, in case there are multiple `Test` files.
290+ dc .resolvePath (" Test" , " utils/Index.md" ) = " utils/Test.md"
291+ // If it cannot find the file, returns the input path unchanged.
292+ dc .resolvePath (" noexist" ) = " noexist"
293+ ```
294+
295+ ### ` dc.fileLink() `
296+
297+ Create a datacore ` Link ` from a path to a file. The path can be local or absolute (though it is generally
298+ recommended to use absolute paths everywhere to avoid ambigious links). Datacore will render ` Link ` objects
299+ automatically as Obsidian links, and some APIs may require ` Link ` objects.
300+
301+ ``` jsx
302+ dc .fileLink (" Test.md" ) = // Link object representing [[Test]].
303+ ```
304+
305+ ### ` dc.headerLink() `
306+
307+ Create a datacore ` Link ` pointing to a header in a file.
308+
309+ ``` jsx
310+ dc .headerLink (" Terraria.md" , " Review" ) = // equivalent to [[Terraria#Review]].
311+ ```
312+
313+ ### ` dc.blockLink() `
314+
315+ Create a datacore ` Link ` pointing to a specific block in a file. Note that blocks can only be linked to if
316+ they have a block ID - generally visible by looking for ` ^blockId ` notation at the end of the block.
317+
318+ ``` jsx
319+ dc .blockLink (" Daily Thoughts.md" , " 38ha12d" ) = // equivalent to [[Daily Thoughts#^38ha12d]]
320+ ```
321+
322+ ### ` dc.parseLink() `
323+
324+ Parses a full link into a datacore ` Link ` . Throws an error if the syntax is malformed.
325+
326+ ``` jsx
327+ dc .parseLink (" [[Test]]" ) = // link representing [[Test]].
328+ dc .parseLink (" [malformed]" ) = // throws an exception
329+ ```
330+
331+ ### ` dc.tryParseLink() `
332+
333+ Returns a datacore ` Result ` containing the result of trying to parse a string link.
334+
335+ ``` jsx
336+ dc .tryParseLink (" [[Test]]" ) = // { successful: true, value: [[Test]] }
337+ dc .tryParseLink (" [malformed]" ) = // { successful: false, error: "malformed input..." }
338+ ```
339+
340+ ## Expressions
341+
342+ Methods for evaluating arbitrary datacore expressions, and returning their results.
343+
344+ ### ` dc.evaluate() `
345+
346+ Evaluates a datacore [ expression] ( /expressions ) , returning what it evaluates to. If the expression cannot be parsed
347+ or is invalid, will raise an exception. ` dc.evaluate ` accepts one, two, or three arguments:
348+
349+ ``` jsx
350+ // Single argument version takes only the expression.
351+ dc .evaluate (" 1 + 2" ) = 3
352+
353+ // Two argument version allows you to provide variables.
354+ dc .evaluate (" x + y" , { x: 1 , y: 2 }) = 3
355+
356+ // Three argument version allows you to specify a source path to resolve
357+ // links from, if you don't want to use the current file.
358+ dc .evaluate (" [[Test]].value" , {}, " path/to/other/file.md" ) = // the value of property 'value' in [[Test]]
359+ ```
360+
361+ ### ` dc.tryEvaluate() `
362+
363+ Equivalent to ` dc.evaluate() ` , but returns a datacore ` Result ` type instead of just the value.
364+
365+ ``` jsx
366+ dc .tryEvaluate (" 1 + 2" ) = { value: 3 , successful: true }
367+ dc .tryEvaluate (" fakefunction(3)" ) = { successful: false , error: " unrecognized function..." }
368+ ```
369+
370+ ## Type Coercion / Parsing
371+
372+ Parses
373+
374+ ### ` dc.coerce.string() `
375+
376+ Converts any other type to a string.
377+
378+ ``` jsx
379+ dc .coerce .string (16 ) = " 16"
380+ dc .coerce .string (true ) = " true"
381+ ```
382+
383+ ### ` dc.coerce.boolean() `
384+
385+ Parses ` true ` and ` false ` strings into booleans; returns undefined for most other types.
386+
387+ ``` jsx
388+ dc .coerce .boolean (true ) = true
389+ dc .coerce .boolean (" true" ) = true
390+ dc .coerce .boolean (" blah" ) = undefined
391+ ```
392+
393+ ### ` dc.coerce.number() `
394+
395+ Parses strings into numbers; returns undefined for most other types.
396+
397+ ``` jsx
398+ dc .coerce .number (15 ) = 15
399+ dc .coerce .number (" 49.2" ) = 49.2
400+ dc .coerce .number (" oof" ) = undefined
401+ ```
402+
403+ ### ` dc.coerce.date() `
404+
405+ Parses strings into dates; returns undefined for most other types.
406+
407+ ``` jsx
408+ dc .coerce .date (" 2025-05-10" ) = // <DateTime representing 2025-05-10>
409+ dc .coerce .date (" 2025-05-10T11:12:13" ) = // <DateTime representing 2025-05-10 at 11:12 (and 13 seconds)>
410+ dc .coerce .date (" random text" ) = undefined
411+ ```
412+
413+ ### ` dc.coerce.duration() `
414+
415+ Parses strings into durations; returns undefined for most other types
416+
417+ ``` jsx
418+ dc .coerce .duration (" 14 hours" ) = // <Duration representing 14 hours>
419+ dc .coerce .duration (" 30m" ) = // <Duration representing 30 minutes>
420+ dc .coerce .duration (" other text" ) = undefined
421+ ```
422+
423+ ### ` dc.coerce.link() `
424+
425+ Parses strings into links; returns undefined for most other types.
426+
427+ ``` jsx
428+ dc .coerce .link (" [[Test]]" ) = // Link to 'Test'
429+ dc .coerce .link (" ![[Embed|Display]]" ) = // Embedded link to 'Embed' with display 'Display'.
430+ dc .coerce .link (" oof" ) = undefined
431+ ```
432+
433+ ### ` dc.coerce.array() `
434+
435+ If the input is an array, returns that array unchanged; otherwise, wraps the value in an array.
436+
437+ ``` jsx
438+ dc .coerce .array ([1 , 2 ]) = [1 , 2 ]
439+ dc .coerce .array (1 ) = [1 ]
440+ ```
0 commit comments