174 lines
4.5 KiB
Markdown
174 lines
4.5 KiB
Markdown
---
|
|
gitea: none
|
|
include_toc: true
|
|
---
|
|
|
|
# Queries
|
|
|
|
The `Query` class is the main way to fetch records. Inject it via the Laravel container.
|
|
|
|
```php
|
|
public function __construct(private Query $query) {}
|
|
```
|
|
|
|
## Return Formats
|
|
|
|
Queries return results in two formats:
|
|
|
|
**Graph** — via `->run()`. Returns a `Graph` object with `records` and `edges` collections. Useful for network-style data.
|
|
|
|
**Tree** — via `->tree()`. Returns a flat `Collection` of records where each record has `_children` and `_parents` arrays populated based on the requested depth. This is the most common format.
|
|
|
|
## Chaining Methods
|
|
|
|
All methods return `$this` and can be chained:
|
|
|
|
| Method | Description |
|
|
|---|---|
|
|
| `->filter(array)` | Add an AND filter |
|
|
| `->orFilter(array)` | Add an OR filter (grouped) |
|
|
| `->limit(int)` | Max number of root records to return |
|
|
| `->skip(int)` | Offset for pagination |
|
|
| `->sort(string)` | Sort by field. Prefix with `-` for descending e.g. `"-_sys.updatedAt"` |
|
|
| `->status(array)` | Filter by status array e.g. `["published", "draft"]` |
|
|
| `->onlyPublished()` | Shorthand for `->status(["published"])` |
|
|
| `->childrenDepth(int)` | How many levels of children to load |
|
|
| `->childrenLimit(int)` | Max children per record |
|
|
| `->childrenFields(array)` | Only follow specific relationship fields |
|
|
| `->parentsDepth(int)` | How many levels of parents to load |
|
|
| `->parentsLimit(int)` | Max parents per record |
|
|
| `->parentFields(array)` | Only follow specific relationship fields |
|
|
| `->notLinked(string)` | Return only records with no parents |
|
|
| `->run()` | Execute and return a `Graph` |
|
|
| `->tree()` | Execute and return a `Collection` (tree format) |
|
|
| `->runWithCount()` | Execute and return a `Graph` with a `total` count |
|
|
|
|
|
|
## Filters
|
|
|
|
Filter keys use the format `field_operator`. When no operator suffix is given, `eq` is assumed.
|
|
|
|
```php
|
|
$query->filter(["field_operator" => "value"]);
|
|
|
|
// No operator = eq
|
|
$query->filter(["schema" => "blogPosts"]);
|
|
|
|
// With operator
|
|
$query->filter(["_sys.updatedAt_gte" => "2024-01-01"]);
|
|
```
|
|
|
|
### Operator Reference
|
|
|
|
| Operator | Description |
|
|
|---|---|
|
|
| _(none)_ or `eq` | Equals (string) |
|
|
| `ne` | Not equals (string) |
|
|
| `eqnum` | Equals (numeric) |
|
|
| `neqnum` | Not equals (numeric) |
|
|
| `eqtrue` | Equals `true` |
|
|
| `eqfalse` | Equals `false` |
|
|
| `netrue` | Not equals `true` |
|
|
| `nefalse` | Not equals `false` |
|
|
| `regex` | Regular expression match |
|
|
| `in` | Value is in array (strings) |
|
|
| `nin` | Value is not in array (strings) |
|
|
| `innum` | Value is in array (numeric) |
|
|
| `ninnum` | Value is not in array (numeric) |
|
|
| `lt` | Less than |
|
|
| `lte` | Less than or equal |
|
|
| `gt` | Greater than |
|
|
| `gte` | Greater than or equal |
|
|
| `null` | Field is null |
|
|
| `nnull` | Field is not null |
|
|
| `exists` | Field key exists |
|
|
| `nexists` | Field key does not exist |
|
|
| `filter` | Raw filter passthrough |
|
|
|
|
### OR Filters
|
|
|
|
```php
|
|
$query
|
|
->filter(["schema" => "blogPosts"])
|
|
->orFilter(["title_regex" => "search", "slug_regex" => "search"]);
|
|
```
|
|
|
|
Each `orFilter` call groups its arguments with OR between them. Multiple `orFilter` / `filter` calls are AND-ed together.
|
|
|
|
### Cross-Schema (Children) Filters
|
|
|
|
You can filter records by properties of their related records using the `children.` prefix:
|
|
|
|
```php
|
|
$query->filter([
|
|
"schema" => "blogPosts",
|
|
"children.categories.data.slug" => "sports",
|
|
]);
|
|
```
|
|
|
|
This returns `blogPosts` that have a child in `categories` where `slug` equals `sports`.
|
|
|
|
|
|
## Nested Data Fields
|
|
|
|
Use dot notation to filter on JSON data fields and system fields:
|
|
|
|
```php
|
|
// Filter on a data field
|
|
$query->filter(["data.status_eq" => "draft"]);
|
|
|
|
// Filter on a system field
|
|
$query->filter(["_sys.updatedAt_gte" => "2024-01-01"]);
|
|
```
|
|
|
|
|
|
## Examples
|
|
|
|
**Get published blog posts, newest first:**
|
|
|
|
```php
|
|
$posts = $query
|
|
->filter(["schema" => "blogPosts"])
|
|
->onlyPublished()
|
|
->sort("-_sys.updatedAt")
|
|
->limit(10)
|
|
->tree();
|
|
```
|
|
|
|
**Get posts from a specific category with children loaded:**
|
|
|
|
```php
|
|
$posts = $query
|
|
->filter([
|
|
"schema" => "blogPosts",
|
|
"children.categories.data.slug" => "sports",
|
|
])
|
|
->childrenDepth(1)
|
|
->childrenFields(["categories"])
|
|
->limit(10)
|
|
->tree();
|
|
```
|
|
|
|
**Paginate records:**
|
|
|
|
```php
|
|
$graph = $query
|
|
->filter(["schema" => "blogPosts"])
|
|
->limit(20)
|
|
->skip(40)
|
|
->runWithCount();
|
|
|
|
$posts = $graph->tree();
|
|
$total = $graph->total;
|
|
```
|
|
|
|
**Search across fields:**
|
|
|
|
```php
|
|
$results = $query
|
|
->filter(["schema" => "blogPosts"])
|
|
->orFilter(["title_regex" => $term, "slug_regex" => $term])
|
|
->limit(10)
|
|
->tree();
|
|
```
|