@harperfast/template-react-ts-ssr-studio 1.13.4 → 1.13.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agents/skills/harper-best-practices/AGENTS.md +687 -453
- package/.agents/skills/harper-best-practices/SKILL.md +24 -21
- package/.agents/skills/harper-best-practices/rules/adding-tables-with-schemas.md +2 -0
- package/.agents/skills/harper-best-practices/rules/automatic-apis.md +2 -0
- package/.agents/skills/harper-best-practices/rules/caching.md +2 -0
- package/.agents/skills/harper-best-practices/rules/checking-authentication.md +2 -0
- package/.agents/skills/harper-best-practices/rules/custom-resources.md +2 -0
- package/.agents/skills/harper-best-practices/rules/defining-relationships.md +102 -40
- package/.agents/skills/harper-best-practices/rules/deploying-from-ci.md +121 -93
- package/.agents/skills/harper-best-practices/rules/deploying-to-harper-fabric.md +149 -103
- package/.agents/skills/harper-best-practices/rules/extending-tables.md +2 -0
- package/.agents/skills/harper-best-practices/rules/handling-binary-data.md +2 -0
- package/.agents/skills/harper-best-practices/rules/load-env.md +2 -0
- package/.agents/skills/harper-best-practices/rules/logging.md +2 -0
- package/.agents/skills/harper-best-practices/rules/programmatic-table-requests.md +124 -91
- package/.agents/skills/harper-best-practices/rules/querying-rest-apis.md +86 -82
- package/.agents/skills/harper-best-practices/rules/real-time-apps.md +2 -0
- package/.agents/skills/harper-best-practices/rules/schema-design-tooling.md +92 -59
- package/.agents/skills/harper-best-practices/rules/serving-web-content.md +2 -0
- package/.agents/skills/harper-best-practices/rules/typescript-type-stripping.md +2 -0
- package/.agents/skills/harper-best-practices/rules/using-blob-datatype.md +2 -0
- package/.agents/skills/harper-best-practices/rules/vector-indexing.md +2 -0
- package/.agents/skills/harper-best-practices/rules.manifest.yaml +44 -0
- package/agent/skills/harper-best-practices/AGENTS.md +687 -453
- package/agent/skills/harper-best-practices/SKILL.md +26 -21
- package/agent/skills/harper-best-practices/rules/adding-tables-with-schemas.md +2 -0
- package/agent/skills/harper-best-practices/rules/automatic-apis.md +2 -0
- package/agent/skills/harper-best-practices/rules/caching.md +2 -0
- package/agent/skills/harper-best-practices/rules/checking-authentication.md +2 -0
- package/agent/skills/harper-best-practices/rules/custom-resources.md +2 -0
- package/agent/skills/harper-best-practices/rules/defining-relationships.md +102 -40
- package/agent/skills/harper-best-practices/rules/deploying-from-ci.md +121 -93
- package/agent/skills/harper-best-practices/rules/deploying-to-harper-fabric.md +149 -103
- package/agent/skills/harper-best-practices/rules/extending-tables.md +2 -0
- package/agent/skills/harper-best-practices/rules/handling-binary-data.md +2 -0
- package/agent/skills/harper-best-practices/rules/load-env.md +2 -0
- package/agent/skills/harper-best-practices/rules/logging.md +2 -0
- package/agent/skills/harper-best-practices/rules/programmatic-table-requests.md +124 -91
- package/agent/skills/harper-best-practices/rules/querying-rest-apis.md +86 -82
- package/agent/skills/harper-best-practices/rules/real-time-apps.md +2 -0
- package/agent/skills/harper-best-practices/rules/schema-design-tooling.md +92 -59
- package/agent/skills/harper-best-practices/rules/serving-web-content.md +2 -0
- package/agent/skills/harper-best-practices/rules/typescript-type-stripping.md +2 -0
- package/agent/skills/harper-best-practices/rules/using-blob-datatype.md +2 -0
- package/agent/skills/harper-best-practices/rules/vector-indexing.md +2 -0
- package/agent/skills/harper-best-practices/rules.manifest.yaml +44 -0
- package/package.json +1 -1
- package/skills-lock.json +1 -1
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: harper-best-practices
|
|
3
|
-
description:
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
and
|
|
3
|
+
description: How to implement a specific Harper feature correctly, with one rule per feature
|
|
4
|
+
(tables and schemas, relationships, automatic REST and WebSocket APIs, extending tables,
|
|
5
|
+
custom resources, caching, real-time, auth, blobs, vector indexes, static and Vite web serving,
|
|
6
|
+
logging, env loading, and deploying to Harper Fabric). Use when building or changing one of
|
|
7
|
+
these features. For deciding which services an app needs, read harper-architecture first.
|
|
7
8
|
license: Apache-2.0
|
|
8
9
|
metadata:
|
|
9
10
|
author: harper
|
|
@@ -12,6 +13,8 @@ metadata:
|
|
|
12
13
|
|
|
13
14
|
# Harper Best Practices
|
|
14
15
|
|
|
16
|
+
> Deciding what to build or which services an app needs? Read the `harper-architecture` skill first. This skill covers how to implement each Harper feature once that decision is made.
|
|
17
|
+
|
|
15
18
|
Guidelines for building scalable, secure, and performant applications on Harper. These practices cover everything from initial schema design to advanced deployment strategies.
|
|
16
19
|
|
|
17
20
|
## When to Use
|
|
@@ -53,37 +56,37 @@ See the concrete examples embedded in each rule subsection below (GraphQL schema
|
|
|
53
56
|
|
|
54
57
|
### 1. Schema & Data Design (HIGH)
|
|
55
58
|
|
|
56
|
-
- `adding-tables-with-schemas` — Guidelines for adding tables to a Harper database using GraphQL schemas.
|
|
59
|
+
- `adding-tables-with-schemas` — Guidelines for adding tables to a Harper database using GraphQL schemas. (instead of: Postgres, MySQL, MongoDB, DynamoDB, Supabase, Firebase)
|
|
57
60
|
- `schema-design-tooling` — Best practices for Harper schema design, including core directives and GraphQL tooling configuration.
|
|
58
|
-
- `defining-relationships` — How to define and use relationships between tables in Harper using GraphQL.
|
|
59
|
-
- `vector-indexing` — How to enable and query vector indexes for similarity search in Harper.
|
|
60
|
-
- `using-blob-datatype` — How to use the Blob data type for efficient binary storage in Harper.
|
|
61
|
-
- `handling-binary-data` — How to store and serve binary data like images or audio in Harper.
|
|
61
|
+
- `defining-relationships` — How to define and use relationships between tables in Harper using GraphQL. (instead of: ORM relations and join tables (Prisma, Drizzle, Sequelize))
|
|
62
|
+
- `vector-indexing` — How to enable and query vector indexes for similarity search in Harper. (instead of: Pinecone, Weaviate, pgvector)
|
|
63
|
+
- `using-blob-datatype` — How to use the Blob data type for efficient binary storage in Harper. (instead of: S3 or GCS buckets for app-managed files)
|
|
64
|
+
- `handling-binary-data` — How to store and serve binary data like images or audio in Harper. (instead of: S3 or GCS buckets for app-managed files)
|
|
62
65
|
|
|
63
66
|
### 2. API & Communication (HIGH)
|
|
64
67
|
|
|
65
|
-
- `automatic-apis` — How to use Harper's automatically generated REST and WebSocket APIs.
|
|
68
|
+
- `automatic-apis` — How to use Harper's automatically generated REST and WebSocket APIs. (instead of: Hand-written CRUD routes (Express, Fastify, Next.js API routes))
|
|
66
69
|
- `querying-rest-apis` — How to use query parameters to filter, sort, and paginate Harper REST APIs.
|
|
67
|
-
- `real-time-apps` — How to build real-time features in Harper using WebSockets and Pub/Sub.
|
|
68
|
-
- `checking-authentication` — How to handle user authentication and sessions in Harper Resources.
|
|
70
|
+
- `real-time-apps` — How to build real-time features in Harper using WebSockets and Pub/Sub. (instead of: Socket.io, `ws`, Pusher, Ably, Redis pub/sub, a separate MQTT broker)
|
|
71
|
+
- `checking-authentication` — How to handle user authentication and sessions in Harper Resources. (instead of: Hand-rolled sessions, `passport`, `jsonwebtoken`, `bcrypt`)
|
|
69
72
|
|
|
70
73
|
### 3. Logic & Extension (MEDIUM)
|
|
71
74
|
|
|
72
|
-
- `custom-resources` — How to define custom REST endpoints with JavaScript or TypeScript in Harper.
|
|
73
|
-
- `extending-tables` — How to add custom logic to automatically generated table resources in Harper.
|
|
74
|
-
- `programmatic-table-requests` — How to interact with Harper tables programmatically using the `tables` object.
|
|
75
|
-
- `typescript-type-stripping` — How to run TypeScript files directly in Harper without a build step.
|
|
76
|
-
- `caching` — How to implement integrated data caching in Harper from external sources.
|
|
75
|
+
- `custom-resources` — How to define custom REST endpoints with JavaScript or TypeScript in Harper. (instead of: Express, Fastify, or Koa route handlers; serverless functions)
|
|
76
|
+
- `extending-tables` — How to add custom logic to automatically generated table resources in Harper. (instead of: Middleware and controllers wrapped around CRUD routes)
|
|
77
|
+
- `programmatic-table-requests` — How to interact with Harper tables programmatically using the `tables` object. (instead of: ORM and query-builder clients (Prisma, Drizzle, Knex))
|
|
78
|
+
- `typescript-type-stripping` — How to run TypeScript files directly in Harper without a build step. (instead of: `tsc` or `ts-node` build steps for server code)
|
|
79
|
+
- `caching` — How to implement integrated data caching in Harper from external sources. (instead of: Redis or Memcached cache-aside layers)
|
|
77
80
|
|
|
78
81
|
### 4. Infrastructure & Ops (MEDIUM)
|
|
79
82
|
|
|
80
|
-
- `deploying-to-harper-fabric` — How to deploy a Harper application to Harper Fabric with the CLI, check that the release was certified, and roll back by activating a previous release's `deployment_id`.
|
|
83
|
+
- `deploying-to-harper-fabric` — How to deploy a Harper application to Harper Fabric with the CLI, check that the release was certified, and roll back by activating a previous release's `deployment_id`. (instead of: Docker Compose stacks; deploying several services separately)
|
|
81
84
|
- `deploying-from-ci` — How to deploy a Harper application from GitHub Actions with OIDC trusted publishing, so CI stores no Harper credential, including the one-command setup with `harper deploy setup=true provider=github-actions`.
|
|
82
85
|
- `creating-a-fabric-account-and-cluster` — How to create a Harper Fabric account, organization, and cluster.
|
|
83
86
|
- `creating-harper-apps` — How to initialize a new Harper application using the CLI.
|
|
84
|
-
- `serving-web-content` — How to serve static files and integrated Vite/React applications in Harper.
|
|
85
|
-
- `logging` — Best practices for logging in Harper, including console capture, the granular logger interface, and programmatic log retrieval.
|
|
86
|
-
- `load-env` — How to load environment variables from .env files into a Harper application using the loadEnv plugin.
|
|
87
|
+
- `serving-web-content` — How to serve static files and integrated Vite/React applications in Harper. (instead of: Nginx, Vercel, or Netlify for the frontend; a separate Vite dev server)
|
|
88
|
+
- `logging` — Best practices for logging in Harper, including console capture, the granular logger interface, and programmatic log retrieval. (instead of: Separate log shippers for app logs (pino or winston transports))
|
|
89
|
+
- `load-env` — How to load environment variables from .env files into a Harper application using the loadEnv plugin. (instead of: `dotenv`)
|
|
87
90
|
- `v5-upgrade` — Breaking changes and recommended updates when migrating a Harper application to v5.
|
|
88
91
|
- `delegating-to-the-built-in-agent` — How to delegate tasks to Harper's built-in agent via the CLI and the agent operations API.
|
|
89
92
|
|
|
@@ -9,6 +9,8 @@ metadata:
|
|
|
9
9
|
|
|
10
10
|
Instructions for the agent to follow when adding tables to a Harper database.
|
|
11
11
|
|
|
12
|
+
**Instead of:** Postgres, MySQL, MongoDB, DynamoDB, Supabase, Firebase. Use this rule rather than adding that service. See `harper-architecture`.
|
|
13
|
+
|
|
12
14
|
## When to Use
|
|
13
15
|
|
|
14
16
|
Use this skill when you need to define new data structures or modify existing ones in a Harper database.
|
|
@@ -20,6 +20,8 @@ metadata:
|
|
|
20
20
|
|
|
21
21
|
Instructions for the agent to follow when using Harper's automatically generated REST and WebSocket APIs for exported tables and resources.
|
|
22
22
|
|
|
23
|
+
**Instead of:** Hand-written CRUD routes (Express, Fastify, Next.js API routes). Use this rule rather than adding that service. See `harper-architecture`.
|
|
24
|
+
|
|
23
25
|
## When to Use
|
|
24
26
|
|
|
25
27
|
Apply this rule when enabling HTTP REST endpoints or WebSocket subscriptions for Harper tables and custom resources. Use it whenever you need to configure the REST plugin, understand the auto-generated endpoint surface, or wire up real-time WebSocket connections. See [querying-rest-apis.md](querying-rest-apis.md) for query syntax and [real-time-apps.md](real-time-apps.md) for real-time patterns.
|
|
@@ -13,6 +13,8 @@ metadata:
|
|
|
13
13
|
|
|
14
14
|
Instructions for the agent to implement integrated data caching from external sources using Harper's cache table directives and `sourcedFrom` API.
|
|
15
15
|
|
|
16
|
+
**Instead of:** Redis or Memcached cache-aside layers. Use this rule rather than adding that service. See `harper-architecture`.
|
|
17
|
+
|
|
16
18
|
## When to Use
|
|
17
19
|
|
|
18
20
|
Apply this rule when an application needs to wrap an external API, microservice, or database with a fast local cache. Use it when you need to define TTL-based cache expiration, connect an upstream data source to a Harper table, or implement on-demand cache invalidation.
|
|
@@ -27,6 +27,8 @@ metadata:
|
|
|
27
27
|
|
|
28
28
|
Instructions for the agent to handle user authentication, sessions, and JWT token issuance in Harper Resources.
|
|
29
29
|
|
|
30
|
+
**Instead of:** Hand-rolled sessions, `passport`, `jsonwebtoken`, `bcrypt`. Use this rule rather than adding that service. See `harper-architecture`.
|
|
31
|
+
|
|
30
32
|
## When to Use
|
|
31
33
|
|
|
32
34
|
Apply this rule when implementing login/logout flows, reading the current authenticated user, issuing or refreshing JWT tokens, or minting scoped tokens from a custom Resource. Use it whenever a Resource must gate behavior on identity or credentials. See [custom-resources.md](custom-resources.md) for the broader Resource authoring model.
|
|
@@ -15,6 +15,8 @@ metadata:
|
|
|
15
15
|
|
|
16
16
|
Instructions for the agent to follow when defining custom REST endpoints with JavaScript or TypeScript in Harper.
|
|
17
17
|
|
|
18
|
+
**Instead of:** Express, Fastify, or Koa route handlers; serverless functions. Use this rule rather than adding that service. See `harper-architecture`.
|
|
19
|
+
|
|
18
20
|
## When to Use
|
|
19
21
|
|
|
20
22
|
Apply this rule when you need to create custom HTTP endpoints, wrap external APIs, or register routes programmatically in a Harper application. Use it any time business logic must live outside a table-backed schema, or when you need fine-grained control over URL shape and path parameters.
|
|
@@ -6,21 +6,23 @@ metadata:
|
|
|
6
6
|
sources:
|
|
7
7
|
- reference/v5/database/schema.md#Relationships
|
|
8
8
|
- reference/v5/rest/querying.md#Relationships and Joins
|
|
9
|
-
sourceCommit:
|
|
10
|
-
inputHash:
|
|
9
|
+
sourceCommit: bea4e62cb7efd809bb67e00cbda01a410c1177b1
|
|
10
|
+
inputHash: 58ffc789fa71ffe6
|
|
11
11
|
---
|
|
12
12
|
|
|
13
13
|
# Defining Relationships Between Tables in Harper
|
|
14
14
|
|
|
15
|
-
Instructions for the agent to
|
|
15
|
+
Instructions for the agent to define and query relationships between Harper tables using the `@relationship` directive in GraphQL schemas.
|
|
16
|
+
|
|
17
|
+
**Instead of:** ORM relations and join tables (Prisma, Drizzle, Sequelize). Use this rule rather than adding that service. See `harper-architecture`.
|
|
16
18
|
|
|
17
19
|
## When to Use
|
|
18
20
|
|
|
19
|
-
Apply this rule when
|
|
21
|
+
Apply this rule when writing Harper schemas that require join queries across tables, or when query results must include related records as nested properties. Use it whenever a foreign key exists in one table that references another, or when modeling one-to-many, many-to-one, or many-to-many associations.
|
|
20
22
|
|
|
21
23
|
## How It Works
|
|
22
24
|
|
|
23
|
-
1. **
|
|
25
|
+
1. **Declare a many-to-one relationship with `from`**: Place `@relationship(from: attribute)` on a field when the foreign key lives in the current table and references the primary key of the target table. The result type is a single object.
|
|
24
26
|
|
|
25
27
|
```graphql
|
|
26
28
|
type RealityShow @table @export {
|
|
@@ -36,17 +38,7 @@ Apply this rule when adding foreign key relationships between schema tables, ena
|
|
|
36
38
|
}
|
|
37
39
|
```
|
|
38
40
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
```graphql
|
|
42
|
-
type RealityShow @table @export {
|
|
43
|
-
id: Long @primaryKey
|
|
44
|
-
networkIds: [Long] @indexed
|
|
45
|
-
networks: [Network] @relationship(from: networkIds)
|
|
46
|
-
}
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
2. **Use `@relationship(to: attribute)` for one-to-many or many-to-many**: Place this on the table whose primary key is referenced by the foreign key in the target table. The `to` parameter names the attribute on the target table that holds the foreign key. The result type **must** be an array.
|
|
41
|
+
2. **Declare a one-to-many relationship with `to`**: Place `@relationship(to: attribute)` on a field when the foreign key lives in the target table and references the primary key of the current table. The result type **must** be an array.
|
|
50
42
|
|
|
51
43
|
```graphql
|
|
52
44
|
type Network @table @export {
|
|
@@ -56,14 +48,14 @@ Apply this rule when adding foreign key relationships between schema tables, ena
|
|
|
56
48
|
}
|
|
57
49
|
```
|
|
58
50
|
|
|
59
|
-
3. **
|
|
51
|
+
3. **Declare a foreign-key-to-foreign-key relationship with `@relationship(from: attribute, to: attribute)`**: Specify both `from` and `to` when neither side uses the primary key. Harper resolves the relationship by searching the target table's `to` attribute for matches using the current record's `from` attribute value. The result type must be an array.
|
|
60
52
|
|
|
61
53
|
```graphql
|
|
62
54
|
type OrderItem @table @export {
|
|
63
55
|
id: Long @primaryKey
|
|
64
56
|
orderId: Long @indexed
|
|
65
57
|
productSku: Long @indexed
|
|
66
|
-
products: [Product] @relationship(from: productSku, to: sku)
|
|
58
|
+
products: [Product] @relationship(from: productSku, to: sku) # matches products by sku, not primary key
|
|
67
59
|
}
|
|
68
60
|
|
|
69
61
|
type Product @table @export {
|
|
@@ -73,14 +65,25 @@ Apply this rule when adding foreign key relationships between schema tables, ena
|
|
|
73
65
|
}
|
|
74
66
|
```
|
|
75
67
|
|
|
76
|
-
4. **
|
|
68
|
+
4. **Declare a many-to-many relationship using an array foreign key with `from`**: When the foreign key field is an array, `@relationship(from: attribute)` establishes a many-to-many relationship. The result type must be an array.
|
|
69
|
+
|
|
70
|
+
```graphql
|
|
71
|
+
type RealityShow @table @export {
|
|
72
|
+
id: Long @primaryKey
|
|
73
|
+
networkIds: [Long] @indexed
|
|
74
|
+
networks: [Network] @relationship(from: networkIds)
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
5. **Query across relationships using dot-syntax**: Filter records by related table attributes using dot-chained attribute names. This behaves as an INNER JOIN — only parents with a qualifying related record are returned.
|
|
77
79
|
|
|
78
80
|
```
|
|
81
|
+
GET /RealityShow?network.name=Bravo
|
|
79
82
|
GET /Product/?brand.name=Microsoft
|
|
80
83
|
GET /Brand/?products.name=Keyboard
|
|
81
84
|
```
|
|
82
85
|
|
|
83
|
-
|
|
86
|
+
6. **Include relationship fields in results using `select()`**: Relationship attributes are not included by default. Use `select()` to project them, optionally with a nested field list using `{}`.
|
|
84
87
|
|
|
85
88
|
```
|
|
86
89
|
GET /Product/?brand.name=Microsoft&select(name,brand)
|
|
@@ -88,24 +91,27 @@ Apply this rule when adding foreign key relationships between schema tables, ena
|
|
|
88
91
|
GET /Product/?name=Keyboard&select(name,brand{name,id})
|
|
89
92
|
```
|
|
90
93
|
|
|
91
|
-
|
|
94
|
+
Selecting a relationship without an outer dot-syntax filter on it behaves as a LEFT JOIN: parents remain even when there are no related records.
|
|
92
95
|
|
|
93
|
-
|
|
96
|
+
7. **Filter and page nested relationship results using `[]` inside `select()`**: Apply conditions, sort, and pagination to each parent's related records by placing them inside square brackets in the `select()` expression.
|
|
94
97
|
|
|
95
|
-
```graphql
|
|
96
|
-
type Product @table @export {
|
|
97
|
-
id: Long @primaryKey
|
|
98
|
-
name: String
|
|
99
|
-
resellerIds: [Long] @indexed
|
|
100
|
-
resellers: [Reseller] @relationship(from: "resellerIds")
|
|
101
|
-
}
|
|
102
98
|
```
|
|
99
|
+
GET /Brand/?select(id,name,products[price=ge=number:30&sort(price)&limit(1)&select(id,name,price)])
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
An outer relationship filter (e.g., `products.price=ge=number:30`) removes parents without a qualifying child **and** narrows the nested candidates. A filter inside `products[...]` only narrows projected children without removing their parent.
|
|
103
103
|
|
|
104
|
-
|
|
104
|
+
| Nested option | Behavior |
|
|
105
|
+
| ------------------ | -------------------------------------------------------------------------- |
|
|
106
|
+
| Conditions | Qualify children; combine with `&` (AND), `\|` (OR), and groups. |
|
|
107
|
+
| `sort(price)` | Order eligible children before pagination. |
|
|
108
|
+
| `limit(end)` | Return at most `end` children per parent. |
|
|
109
|
+
| `limit(start,end)` | Skip `start` eligible children and return at most `end - start`. |
|
|
110
|
+
| `select(id,price)` | Project fields from returned children; omit to return whole child records. |
|
|
105
111
|
|
|
106
112
|
## Examples
|
|
107
113
|
|
|
108
|
-
|
|
114
|
+
### Schema with bidirectional relationships
|
|
109
115
|
|
|
110
116
|
```graphql
|
|
111
117
|
type Product @table @export {
|
|
@@ -122,22 +128,78 @@ type Brand @table @export {
|
|
|
122
128
|
}
|
|
123
129
|
```
|
|
124
130
|
|
|
125
|
-
|
|
131
|
+
### Many-to-many without a junction table
|
|
132
|
+
|
|
133
|
+
```graphql
|
|
134
|
+
type Product @table @export {
|
|
135
|
+
id: Long @primaryKey
|
|
136
|
+
name: String
|
|
137
|
+
resellerIds: [Long] @indexed
|
|
138
|
+
resellers: [Reseller] @relationship(from: "resellerIds")
|
|
139
|
+
}
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
```
|
|
143
|
+
GET /Product/?resellers.name=Cool Shop&select(id,name,resellers{name,id})
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
The array order of `resellerIds` is preserved when resolving the relationship.
|
|
147
|
+
|
|
148
|
+
### Nested filtering and pagination scenarios
|
|
149
|
+
|
|
150
|
+
Schema for the following examples:
|
|
151
|
+
|
|
152
|
+
```graphql
|
|
153
|
+
type Brand @table @export {
|
|
154
|
+
id: Int @primaryKey
|
|
155
|
+
name: String @indexed
|
|
156
|
+
products: [Product] @relationship(to: "brandId")
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
type Product @table @export {
|
|
160
|
+
id: ID @primaryKey
|
|
161
|
+
brandId: Int @indexed
|
|
162
|
+
name: String
|
|
163
|
+
price: Int @indexed
|
|
164
|
+
}
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
**Keep every brand; show its cheapest product costing at least 30** (LEFT JOIN behavior — Budget Basics returns with an empty product list):
|
|
126
168
|
|
|
127
169
|
```
|
|
128
|
-
GET /
|
|
129
|
-
GET /Brand/?products.name=Keyboard
|
|
170
|
+
GET /Brand/?select(id,name,products[price=ge=number:30&sort(price)&limit(1)&select(id,name,price)])
|
|
130
171
|
```
|
|
131
172
|
|
|
132
|
-
**
|
|
173
|
+
**Return only qualifying brands; inherit the outer price filter** (INNER JOIN behavior — Budget Basics is removed):
|
|
133
174
|
|
|
134
175
|
```
|
|
135
|
-
GET /
|
|
176
|
+
GET /Brand/?products.price=ge=number:30&select(id,name,products[sort(price)&limit(1)&select(id,name,price)])
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
**Page through each brand's qualifying products** (offset applies independently per brand):
|
|
180
|
+
|
|
181
|
+
```
|
|
182
|
+
GET /Brand/?products.price=ge=number:30&select(id,name,products[sort(price)&limit(1,2)&select(id,name,price)])
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
**Bound parent pages with stable sorting**:
|
|
186
|
+
|
|
187
|
+
```
|
|
188
|
+
GET /Brand/?products.price=ge=number:30&sort(name,id)&limit(0,20)&select(id,name,products[sort(price,id)&limit(1)&select(id,name,price)])
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
**Combine OR filters with child sorting and pagination**:
|
|
192
|
+
|
|
193
|
+
```
|
|
194
|
+
GET /Brand/?sort(name,id)&limit(0,20)&select(id,name,products[[price=lt=number:30|price=ge=number:60]&sort(-price,id)&limit(1,2)&select(id,name,price)])
|
|
136
195
|
```
|
|
137
196
|
|
|
138
197
|
## Notes
|
|
139
198
|
|
|
140
|
-
-
|
|
141
|
-
-
|
|
142
|
-
-
|
|
143
|
-
-
|
|
199
|
+
- Index all foreign key fields (e.g., `brandId`, `price`) and outer filter fields to support efficient join queries.
|
|
200
|
+
- Use a unique field as the final sort key (e.g., `sort(price,id)`) to ensure deterministic ordering when values are equal.
|
|
201
|
+
- A nested `limit()` bounds children per parent, not the number of parents. Apply a separate outer `limit()` to bound the parent result set.
|
|
202
|
+
- Nested filters require a table-backed relationship. Filters on plain JSON projections or full-text predicates inside a relationship selection return HTTP 400.
|
|
203
|
+
- Invalid `limit()` bounds (negative or fractional values) return HTTP 400. `limit(0)` returns no children without reading them.
|
|
204
|
+
- A condition traversing another relationship qualifies the immediate child only; it does not narrow that child's projected descendants. Place grandchild constraints in the grandchild's own bracket selection.
|
|
205
|
+
- Schemas can define self-referential relationships to enable parent-child hierarchies within a single table.
|