Skip to main content

Codeblock API

Datacore views are built around the datacore codeblock (also known as "local") API, which is available in any datacore codeblock as dc. The codeblock API provides access to a large number of useful utility functions and components with which you can build our more complicated views.

Datacore codeblocks are built on React, so the basic structure of any codeblock will generally look like:

```datacorejsx
// Return a react functional component which renders your view.
return function View() {
// Call functions on the datacore API, 'dc'.
const data = dc.useQuery("#book");

// And then return a view, possibly using more datacore API calls.
return <dc.List rows={data} renderer={book => book.$link} />;
}
```

Query Hooks

Datacore provides several methods for querying for data, including by the full query language and by path explicitly.

dc.useCurrentFile()

Loads the metadata for the file that the view is in - this will usually be MarkdownPage, but can also be a CanvasPage. Using this hook will automatically refresh the view whenever the current file changes.

return function View() {
const file = dc.useCurrentFile();

return <p>Hello, {file.$name}!</p>;
}

dc.useCurrentFile accepts an optional settings argument, which currently allows you to configure how often the view should update via the debounce property.

// Only update the view at most once per 10 seconds (1000ms).
const file = dc.useCurrentFile({ debounce: 10000 });

dc.useCurrentPath()

Loads the path of the file that the view is in - this will usually be MarkdownPage, but can also be a CanvasPage. Using this hook will automatically refresh the view whenever the current file changes.

return function View() {
const path = dc.useCurrentPath();

return <p>The file is at {path}!</p>;
}

Like useCurrentFile, dc.useCurrentPath accepts an optional settings argument which can configure a debounce:

// Only update the view at most once per 10 seconds (1000ms).
const path = dc.useCurrentPath({ debounce: 10000 });

dc.useQuery()

Query for a list of results using the query language. This will return a vanilla javascript list containing all of the results that match the query, which can be a wide range of different data types. This hook will cause the view to update whenever the query returns new results.

return function View() {
const books = dc.useQuery("#book and @page");

return <dc.List rows={books} renderer={book => book.$link} />;
}

dc.useQuery accepts an optional second argument containing configuration; currently, the only configuration option is debounce, which allows you to control how fast the view is allowed to update to reflect new results:

return function View() {
// Only allow the view to update every 10000ms (aka, 10 seconds).
const books = dc.useQuery("#book and @page", { debounce: 10000 });

return <dc.List rows={books} renderer={book => book.$link} />;
}

dc.useFullQuery()

Variant of dc.useQuery which returns a full search result object, which mainly provides a bit of useful extra metadata about how the search performed. Specifically, it returns the following data:

export interface SearchResult<O> {
/** The query used to search. */
query: IndexQuery;
/** All of the returned results. */
results: O[];
/** The amount of time in seconds that the search took. */
duration: number;
/** The maximum revision of any document in the result, which is useful for diffing. */
revision: number;
}

dc.useFullQuery can otherwise be used identically to dc.useQuery:

return function View() {
// Only allow the view to update every 10000ms (aka, 10 seconds).
const bookResult = dc.useFullQuery("#book and @page", { debounce: 10000 });

return <dc.Stack>
<p>The search took {bookResult.duration.toFixed(2)}s to run.</p>
<dc.List rows={bookResult.results} renderer={book => book.$link} />
</dc.Stack>;
}

dc.useIndexUpdates()

A minimal query which just returns the current revision of the datacore index. The index revision is a monotonically increasing number which is incremented every time something in your vault changes. This call is mainly useful if you are making heavy usage of direct dc.query calls (which don't cause the view to refresh on their own), as it will cause the view to re-render every time something changes in your vault.

return function View() {
// Revision will update on every index update.
const revision = dc.useIndexUpdates();

// Run some complex query that will be re-run on every revision update.
const complexQuery = dc.useMemo(() => {
const thing = dc.query(/* ... */);
// ...
}, [revision]);
}

Like the other hooks, dc.useIndexUpdates accepts an optional settings parameter, which allows you to set a debounce:

// Only update at most once every ten seconds.
const revision = dc.useIndexUpdates({ debounce: 10000 });

Common React Hooks

Datacore forwards the most common React hooks through it's API to make them available. The full list, with brief explanations of each, is:

  • dc.useState: Create a React state variable that can be read and updated.
  • dc.useReducer: Create a React reducer which accepts messages to update internal state.
  • dc.useMemo: Memoize a value so it only updates when a dependency array changes.
  • dc.useCallback: Memoize a function so it only is re-created when a dependency array changes.
  • dc.useEffect: Run a specific 'side-effect' whenever a dependency array changes.
  • dc.createContext: Create a react context which allows passing state down many layers without prop drilling.
  • dc.useContext: Use a previously created context.
  • dc.useRef: A state-like variable that allows directly storing a value without causing React re-renders.

Datacore also provides a few other useful hooks for specifically interacting with datacore utilities:

dc.useArray()

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. This is primarily useful for when you want to take advantage of Data Array utilities while otherwise using vanilla javascript arrays for compatibility with preact/react.

return function View() {
const pages = dc.useQuery("@page and #book");
const grouped = dc.useArray(pages, array => array.groupBy(book => book.value("genre")));

return <dc.List rows={grouped} renderer={book => book.$link} />
}

dc.useArray also accepts a dependency array if you depend on state other than the array itself:

const [searchTerm, setSearchTerm] = dc.useState("");
const pages = dc.useQuery("@page and #book");

const filteredPages = dc.useArray(
pages,
array => array.filter(book => book.$title.includes(searchTerm)),
[searchTerm]);

Direct Queries

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, 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 index changes, combine it with dc.useIndexUpdates, which will trigger a re-render on every vault change:

return function View() {
// Revision will update on every index update.
const revision = dc.useIndexUpdates();

// Run some complex query that will be re-run on every revision update.
const complexQuery = dc.useMemo(() => {
const thing = dc.query(/* ... */);
// ...
}, [revision]);
}

dc.query()

Execute a query against the datacore index, returning a list of all matched results. Will raise an exception if the query is malformed.

dc.query("@page") => // list of all pages
dc.query("@page and #book and rating > 7") => // all pages tagged book with a rating higher than 7.

dc.tryQuery()

Equivalent to dc.query, but returns a datacore Result instead of raising an exception.

dc.tryQuery("@page") => { successful: true, value: [/* list of pages */] }
dc.tryQuery("fakefunction(@page)") => { successful: false, error: "malformed query..." }

dc.fullquery()

Equivalent to dc.query, but returns several additional pieces of metadata about how long the query took to execute:

dc.fullquery("@page") => {
// Parsed query representation.
query: { type: "type", type: "page" },
// Actual results, like you would get from `dc.query`.
results: [/* list of pages */],
// Query runtime in seconds, accurate to the millisecond.
duration: 0.01,
// Index revision the query was executed against.
revision: 317,
}

dc.tryFullQuery()

Equivalent to dc.fullquery, but returns a datacore Result instead of raising an exception on an invalid query.

dc.tryFullQuery("@page") => {
successful: true,
value: {
// Parsed query representation.
query: { type: "type", type: "page" },
// Actual results, like you would get from `dc.query`.
results: [/* list of pages */],
// Query runtime in seconds, accurate to the millisecond.
duration: 0.01,
// Index revision the query was executed against.
revision: 317,
}
}

dc.tryFullQuery("malformed(@page)") => {
successful: false,
error: "malformed query ...",
}

Utilities for creating datacore Link types and normalizing paths.

dc.resolvePath()

Resolves a local or absolute path to an absolute path, optionally from a given source path.

// Can resolve by file name.
dc.resolvePath("Test") = "location/To/Test.md"
// Can resolve from an alternative source path, in case there are multiple `Test` files.
dc.resolvePath("Test", "utils/Index.md") = "utils/Test.md"
// If it cannot find the file, returns the input path unchanged.
dc.resolvePath("noexist") = "noexist"

Create a datacore Link from a path to a file. The path can be local or absolute (though it is generally recommended to use absolute paths everywhere to avoid ambigious links). Datacore will render Link objects automatically as Obsidian links, and some APIs may require Link objects.

dc.fileLink("Test.md") = // Link object representing [[Test]].

Create a datacore Link pointing to a header in a file.

dc.headerLink("Terraria.md", "Review") = // equivalent to [[Terraria#Review]].

Create a datacore Link pointing to a specific block in a file. Note that blocks can only be linked to if they have a block ID - generally visible by looking for ^blockId notation at the end of the block.

dc.blockLink("Daily Thoughts.md", "38ha12d") = // equivalent to [[Daily Thoughts#^38ha12d]]

Parses a full link into a datacore Link. Throws an error if the syntax is malformed.

dc.parseLink("[[Test]]") = // link representing [[Test]].
dc.parseLink("[malformed]") = // throws an exception

Returns a datacore Result containing the result of trying to parse a string link.

dc.tryParseLink("[[Test]]") = // { successful: true, value: [[Test]] }
dc.tryParseLink("[malformed]") = // { successful: false, error: "malformed input..." }

Expressions

Methods for evaluating arbitrary datacore expressions, and returning their results.

dc.evaluate()

Evaluates a datacore expression, returning what it evaluates to. If the expression cannot be parsed or is invalid, will raise an exception. dc.evaluate accepts one, two, or three arguments:

// Single argument version takes only the expression.
dc.evaluate("1 + 2") = 3

// Two argument version allows you to provide variables.
dc.evaluate("x + y", { x: 1, y: 2 }) = 3

// Three argument version allows you to specify a source path to resolve
// links from, if you don't want to use the current file.
dc.evaluate("[[Test]].value", {}, "path/to/other/file.md") = // the value of property 'value' in [[Test]]

dc.tryEvaluate()

Equivalent to dc.evaluate(), but returns a datacore Result type instead of just the value.

dc.tryEvaluate("1 + 2") = { value: 3, successful: true }
dc.tryEvaluate("fakefunction(3)") = { successful: false, error: "unrecognized function..." }

Type Coercion / Parsing

Parses

dc.coerce.string()

Converts any other type to a string.

dc.coerce.string(16) = "16"
dc.coerce.string(true) = "true"

dc.coerce.boolean()

Parses true and false strings into booleans; returns undefined for most other types.

dc.coerce.boolean(true) = true
dc.coerce.boolean("true") = true
dc.coerce.boolean("blah") = undefined

dc.coerce.number()

Parses strings into numbers; returns undefined for most other types.

dc.coerce.number(15) = 15
dc.coerce.number("49.2") = 49.2
dc.coerce.number("oof") = undefined

dc.coerce.date()

Parses strings into dates; returns undefined for most other types.

dc.coerce.date("2025-05-10") = // <DateTime representing 2025-05-10>
dc.coerce.date("2025-05-10T11:12:13") = // <DateTime representing 2025-05-10 at 11:12 (and 13 seconds)>
dc.coerce.date("random text") = undefined

dc.coerce.duration()

Parses strings into durations; returns undefined for most other types

dc.coerce.duration("14 hours") = // <Duration representing 14 hours>
dc.coerce.duration("30m") = // <Duration representing 30 minutes>
dc.coerce.duration("other text") = undefined

Parses strings into links; returns undefined for most other types.

dc.coerce.link("[[Test]]") = // Link to 'Test'
dc.coerce.link("![[Embed|Display]]") = // Embedded link to 'Embed' with display 'Display'.
dc.coerce.link("oof") = undefined

dc.coerce.array()

If the input is an array, returns that array unchanged; otherwise, wraps the value in an array.

dc.coerce.array([1, 2]) = [1, 2]
dc.coerce.array(1) = [1]