chore(agent): configure AI agents and tools
Add configuration for BMad, Claude, OpenCode, and other AI agent tools and workflows.
This commit is contained in:
358
.agent/skills/payload-cms/references/queries.md
Normal file
358
.agent/skills/payload-cms/references/queries.md
Normal file
@@ -0,0 +1,358 @@
|
||||
# Queries Reference
|
||||
|
||||
## Local API
|
||||
|
||||
### Find Multiple
|
||||
|
||||
```ts
|
||||
const result = await payload.find({
|
||||
collection: 'posts',
|
||||
where: {
|
||||
status: { equals: 'published' },
|
||||
},
|
||||
limit: 10,
|
||||
page: 1,
|
||||
sort: '-createdAt',
|
||||
depth: 2,
|
||||
})
|
||||
|
||||
// Result structure
|
||||
{
|
||||
docs: Post[],
|
||||
totalDocs: number,
|
||||
limit: number,
|
||||
totalPages: number,
|
||||
page: number,
|
||||
pagingCounter: number,
|
||||
hasPrevPage: boolean,
|
||||
hasNextPage: boolean,
|
||||
prevPage: number | null,
|
||||
nextPage: number | null,
|
||||
}
|
||||
```
|
||||
|
||||
### Find By ID
|
||||
|
||||
```ts
|
||||
const post = await payload.findByID({
|
||||
collection: 'posts',
|
||||
id: '123',
|
||||
depth: 2,
|
||||
})
|
||||
```
|
||||
|
||||
### Create
|
||||
|
||||
```ts
|
||||
const newPost = await payload.create({
|
||||
collection: 'posts',
|
||||
data: {
|
||||
title: 'New Post',
|
||||
content: '...',
|
||||
author: userId,
|
||||
},
|
||||
user: req.user, // For access control
|
||||
})
|
||||
```
|
||||
|
||||
### Update
|
||||
|
||||
```ts
|
||||
const updated = await payload.update({
|
||||
collection: 'posts',
|
||||
id: '123',
|
||||
data: {
|
||||
title: 'Updated Title',
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
### Delete
|
||||
|
||||
```ts
|
||||
const deleted = await payload.delete({
|
||||
collection: 'posts',
|
||||
id: '123',
|
||||
})
|
||||
```
|
||||
|
||||
## Query Operators
|
||||
|
||||
### Comparison
|
||||
|
||||
```ts
|
||||
where: {
|
||||
price: { equals: 100 },
|
||||
price: { not_equals: 100 },
|
||||
price: { greater_than: 100 },
|
||||
price: { greater_than_equal: 100 },
|
||||
price: { less_than: 100 },
|
||||
price: { less_than_equal: 100 },
|
||||
}
|
||||
```
|
||||
|
||||
### String Operations
|
||||
|
||||
```ts
|
||||
where: {
|
||||
title: { like: 'Hello' }, // Case-insensitive contains
|
||||
title: { contains: 'world' }, // Case-sensitive contains
|
||||
email: { exists: true }, // Field has value
|
||||
}
|
||||
```
|
||||
|
||||
### Array Operations
|
||||
|
||||
```ts
|
||||
where: {
|
||||
tags: { in: ['tech', 'design'] }, // Value in array
|
||||
tags: { not_in: ['spam'] }, // Value not in array
|
||||
tags: { all: ['featured', 'popular'] }, // Has all values
|
||||
}
|
||||
```
|
||||
|
||||
### AND/OR Logic
|
||||
|
||||
```ts
|
||||
where: {
|
||||
and: [
|
||||
{ status: { equals: 'published' } },
|
||||
{ author: { equals: userId } },
|
||||
],
|
||||
}
|
||||
|
||||
where: {
|
||||
or: [
|
||||
{ status: { equals: 'published' } },
|
||||
{ author: { equals: userId } },
|
||||
],
|
||||
}
|
||||
|
||||
// Nested
|
||||
where: {
|
||||
and: [
|
||||
{ status: { equals: 'published' } },
|
||||
{
|
||||
or: [
|
||||
{ featured: { equals: true } },
|
||||
{ 'author.roles': { in: ['admin'] } },
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
||||
```
|
||||
|
||||
### Nested Properties
|
||||
|
||||
Query through relationships:
|
||||
|
||||
```ts
|
||||
where: {
|
||||
'author.name': { contains: 'John' },
|
||||
'category.slug': { equals: 'tech' },
|
||||
}
|
||||
```
|
||||
|
||||
### Geospatial Queries
|
||||
|
||||
```ts
|
||||
where: {
|
||||
location: {
|
||||
near: [-73.935242, 40.730610, 10000], // [lng, lat, maxDistanceMeters]
|
||||
},
|
||||
}
|
||||
|
||||
where: {
|
||||
location: {
|
||||
within: {
|
||||
type: 'Polygon',
|
||||
coordinates: [[[-74, 40], [-73, 40], [-73, 41], [-74, 41], [-74, 40]]],
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
## Field Selection
|
||||
|
||||
Only fetch specific fields:
|
||||
|
||||
```ts
|
||||
const posts = await payload.find({
|
||||
collection: 'posts',
|
||||
select: {
|
||||
title: true,
|
||||
slug: true,
|
||||
author: true, // Will be populated based on depth
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
## Depth (Relationship Population)
|
||||
|
||||
```ts
|
||||
// depth: 0 - IDs only
|
||||
{ author: '123' }
|
||||
|
||||
// depth: 1 - First level populated
|
||||
{ author: { id: '123', name: 'John' } }
|
||||
|
||||
// depth: 2 (default) - Nested relationships populated
|
||||
{ author: { id: '123', name: 'John', avatar: { url: '...' } } }
|
||||
```
|
||||
|
||||
## Pagination
|
||||
|
||||
```ts
|
||||
// Page-based
|
||||
await payload.find({
|
||||
collection: 'posts',
|
||||
page: 2,
|
||||
limit: 20,
|
||||
})
|
||||
|
||||
// Cursor-based (more efficient for large datasets)
|
||||
await payload.find({
|
||||
collection: 'posts',
|
||||
where: {
|
||||
createdAt: { greater_than: lastCursor },
|
||||
},
|
||||
limit: 20,
|
||||
sort: 'createdAt',
|
||||
})
|
||||
```
|
||||
|
||||
## Sorting
|
||||
|
||||
```ts
|
||||
// Single field
|
||||
sort: 'createdAt' // Ascending
|
||||
sort: '-createdAt' // Descending
|
||||
|
||||
// Multiple fields
|
||||
sort: ['-featured', '-createdAt']
|
||||
```
|
||||
|
||||
## Access Control in Local API
|
||||
|
||||
**CRITICAL: Local API bypasses access control by default!**
|
||||
|
||||
```ts
|
||||
// ❌ INSECURE: Access control bypassed
|
||||
await payload.find({
|
||||
collection: 'posts',
|
||||
user: someUser, // User is ignored!
|
||||
})
|
||||
|
||||
// ✅ SECURE: Access control enforced
|
||||
await payload.find({
|
||||
collection: 'posts',
|
||||
user: someUser,
|
||||
overrideAccess: false, // REQUIRED
|
||||
})
|
||||
```
|
||||
|
||||
## REST API
|
||||
|
||||
### Endpoints
|
||||
|
||||
```
|
||||
GET /api/{collection} # Find
|
||||
GET /api/{collection}/{id} # Find by ID
|
||||
POST /api/{collection} # Create
|
||||
PATCH /api/{collection}/{id} # Update
|
||||
DELETE /api/{collection}/{id} # Delete
|
||||
```
|
||||
|
||||
### Query String
|
||||
|
||||
```
|
||||
GET /api/posts?where[status][equals]=published&limit=10&sort=-createdAt&depth=2
|
||||
```
|
||||
|
||||
### Nested Queries
|
||||
|
||||
```
|
||||
GET /api/posts?where[author.name][contains]=John
|
||||
```
|
||||
|
||||
### Complex Queries
|
||||
|
||||
```
|
||||
GET /api/posts?where[or][0][status][equals]=published&where[or][1][author][equals]=123
|
||||
```
|
||||
|
||||
## GraphQL API
|
||||
|
||||
### Query
|
||||
|
||||
```graphql
|
||||
query {
|
||||
Posts(
|
||||
where: { status: { equals: published } }
|
||||
limit: 10
|
||||
sort: "-createdAt"
|
||||
) {
|
||||
docs {
|
||||
id
|
||||
title
|
||||
author {
|
||||
name
|
||||
}
|
||||
}
|
||||
totalDocs
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Mutation
|
||||
|
||||
```graphql
|
||||
mutation {
|
||||
createPost(data: { title: "New Post", status: draft }) {
|
||||
id
|
||||
title
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Draft Queries
|
||||
|
||||
```ts
|
||||
// Published only (default)
|
||||
await payload.find({ collection: 'posts' })
|
||||
|
||||
// Include drafts
|
||||
await payload.find({
|
||||
collection: 'posts',
|
||||
draft: true,
|
||||
})
|
||||
```
|
||||
|
||||
## Count Only
|
||||
|
||||
```ts
|
||||
const count = await payload.count({
|
||||
collection: 'posts',
|
||||
where: { status: { equals: 'published' } },
|
||||
})
|
||||
// Returns: { totalDocs: number }
|
||||
```
|
||||
|
||||
## Distinct Values
|
||||
|
||||
```ts
|
||||
const categories = await payload.find({
|
||||
collection: 'posts',
|
||||
select: { category: true },
|
||||
// Then dedupe in code
|
||||
})
|
||||
```
|
||||
|
||||
## Performance Tips
|
||||
|
||||
1. **Use indexes** - Add `index: true` to frequently queried fields
|
||||
2. **Limit depth** - Lower depth = faster queries
|
||||
3. **Select specific fields** - Don't fetch what you don't need
|
||||
4. **Use pagination** - Never fetch all documents
|
||||
5. **Avoid nested OR queries** - Can be slow on large collections
|
||||
6. **Use count for totals** - Faster than fetching all docs
|
||||
Reference in New Issue
Block a user