feat: search

This commit is contained in:
Jarrod Flesch
2025-02-26 15:26:55 -05:00
parent 91f7deb278
commit 1d6e0941e7
26 changed files with 675 additions and 295 deletions

View File

@@ -3,9 +3,9 @@ import path from 'path'
const filename = fileURLToPath(import.meta.url)
const dirname = path.dirname(filename)
import { buildConfigWithDefaults } from '../buildConfigWithDefaults.js'
import { devUser } from '../credentials.js'
import { Media } from './collections/Media/index.js'
import { Posts } from './collections/Posts/index.js'
import { seed } from './seed/index.js'
export default buildConfigWithDefaults({
admin: {
@@ -14,94 +14,13 @@ export default buildConfigWithDefaults({
},
},
collections: [Posts, Media],
onInit: async (payload) => {
await payload.create({
collection: 'users',
data: {
email: devUser.email,
password: devUser.password,
},
})
await payload.create({
collection: '_folders',
data: {
name: 'Root',
isRoot: true,
},
})
const memesFolder = await payload.create({
collection: '_folders',
data: {
name: 'Memes',
},
})
const nateMemesFolder = await payload.create({
collection: '_folders',
data: {
name: 'Nate Memes',
_parentFolder: memesFolder.id,
},
})
await payload.create({
collection: '_folders',
data: {
name: 'Sacred Nate Memes',
_parentFolder: nateMemesFolder.id,
},
})
await payload.create({
collection: 'posts',
data: {
title: 'Nate Shambles',
_parentFolder: nateMemesFolder.id,
},
})
await payload.create({
collection: 'posts',
data: {
title: 'The Den',
_parentFolder: nateMemesFolder.id,
},
})
await payload.create({
collection: 'posts',
data: {
title: 'Marekteer',
_parentFolder: nateMemesFolder.id,
},
})
await payload.create({
collection: 'posts',
data: {
title: 'Nate+James',
_parentFolder: nateMemesFolder.id,
},
})
await payload.create({
collection: '_folders',
data: {
name: 'Social',
},
})
await payload.create({
collection: '_folders',
data: {
name: 'Slack Emojis',
},
})
await payload.create({
collection: '_folders',
data: {
name: 'This is a really long folder name',
},
})
await payload.create({
collection: 'posts',
data: {
title: 'Post 1',
},
})
},
globals: [
{
slug: 'global',
fields: [],
},
],
onInit: seed,
typescript: {
outputFile: path.resolve(dirname, 'payload-types.ts'),
},

View File

@@ -1,4 +1,4 @@
import type { Payload, Where } from 'payload'
import type { Payload } from 'payload'
import path from 'path'
import { fileURLToPath } from 'url'
@@ -34,7 +34,7 @@ describe('folders', () => {
},
})
await payload.delete({
collection: 'folders',
collection: '_folders',
depth: 0,
where: {
id: {
@@ -47,21 +47,21 @@ describe('folders', () => {
describe('folder > subfolder querying', () => {
it('should only create 1 root folder', async () => {
await payload.create({
collection: 'folders',
collection: '_folders',
data: {
name: 'Folder 1',
},
})
await payload.create({
collection: 'folders',
collection: '_folders',
data: {
name: 'Folder 2',
},
})
const rootSubfoldersQuery = await payload.find({
collection: 'folders',
collection: '_folders',
where: {
isRoot: {
equals: true,
@@ -70,26 +70,26 @@ describe('folders', () => {
})
expect(rootSubfoldersQuery.docs).toHaveLength(1)
expect(rootSubfoldersQuery.docs[0].parentFolder).toBe(undefined)
expect(rootSubfoldersQuery.docs[0]._parentFolder).toBe(undefined)
})
it('should populate subfolders for root', async () => {
await payload.create({
collection: 'folders',
collection: '_folders',
data: {
name: 'Folder 1',
},
})
await payload.create({
collection: 'folders',
collection: '_folders',
data: {
name: 'Folder 2',
},
})
const rootSubfoldersQuery = await payload.find({
collection: 'folders',
collection: '_folders',
where: {
isRoot: {
equals: true,
@@ -97,12 +97,12 @@ describe('folders', () => {
},
})
expect(rootSubfoldersQuery.docs[0].documentsAndFolders.docs.length).toBe(2)
expect(rootSubfoldersQuery.docs[0].documentsAndFolders.docs).toHaveLength(2)
})
it('should populate subfolders for folder by ID', async () => {
const parentFolder = await payload.create({
collection: 'folders',
collection: '_folders',
data: {
name: 'Parent Folder',
},
@@ -110,7 +110,7 @@ describe('folders', () => {
const folderIDFromParams = parentFolder.id
await payload.create({
collection: 'folders',
collection: '_folders',
data: {
name: 'Nested 1',
parentFolder: folderIDFromParams,
@@ -118,7 +118,7 @@ describe('folders', () => {
})
await payload.create({
collection: 'folders',
collection: '_folders',
data: {
name: 'Nested 2',
parentFolder: folderIDFromParams,
@@ -126,18 +126,18 @@ describe('folders', () => {
})
const parentFolderQuery = await payload.findByID({
collection: 'folders',
collection: '_folders',
id: folderIDFromParams,
})
expect(parentFolderQuery.documentsAndFolders.docs.length).toBe(2)
expect(parentFolderQuery.documentsAndFolders.docs).toHaveLength(2)
})
})
describe('folder > file querying', () => {
it.skip('should populate files for folder by ID [POLYMORPHIC NOT IMPLEMENTED]', async () => {
const parentFolder = await payload.create({
collection: 'folders',
collection: '_folders',
data: {
name: 'Parent Folder',
},
@@ -148,7 +148,7 @@ describe('folders', () => {
collection: 'posts',
data: {
title: 'Post 1',
parentFolder: folderIDFromParams,
_parentFolder: folderIDFromParams,
},
})
@@ -156,21 +156,21 @@ describe('folders', () => {
collection: 'posts',
data: {
title: 'Post 2',
parentFolder: folderIDFromParams,
_parentFolder: folderIDFromParams,
},
})
const parentFolderQuery = await payload.findByID({
collection: 'folders',
collection: '_folders',
id: folderIDFromParams,
})
expect(parentFolderQuery.documentsAndFolders.docs.length).toBe(2)
expect(parentFolderQuery.documentsAndFolders.docs).toHaveLength(2)
})
it('should populate files for folder [ISOMORPHIC WORKAROUND]', async () => {
const parentFolder = await payload.create({
collection: 'folders',
collection: '_folders',
data: {
name: 'Parent Folder',
},
@@ -181,7 +181,7 @@ describe('folders', () => {
collection: 'posts',
data: {
title: 'Post 1',
parentFolder: folderIDFromParams,
_parentFolder: folderIDFromParams,
},
})
@@ -189,20 +189,20 @@ describe('folders', () => {
collection: 'posts',
data: {
title: 'Post 2',
parentFolder: folderIDFromParams,
_parentFolder: folderIDFromParams,
},
})
const postsByParentQuery = await payload.find({
collection: 'posts',
where: {
parentFolder: {
_parentFolder: {
equals: folderIDFromParams,
},
},
})
expect(postsByParentQuery.docs.length).toBe(2)
expect(postsByParentQuery.docs).toHaveLength(2)
})
})
})

View File

@@ -6,10 +6,65 @@
* and re-run `payload generate:types` to regenerate this file.
*/
/**
* Supported timezones in IANA format.
*
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "supportedTimezones".
*/
export type SupportedTimezones =
| 'Pacific/Midway'
| 'Pacific/Niue'
| 'Pacific/Honolulu'
| 'Pacific/Rarotonga'
| 'America/Anchorage'
| 'Pacific/Gambier'
| 'America/Los_Angeles'
| 'America/Tijuana'
| 'America/Denver'
| 'America/Phoenix'
| 'America/Chicago'
| 'America/Guatemala'
| 'America/New_York'
| 'America/Bogota'
| 'America/Caracas'
| 'America/Santiago'
| 'America/Buenos_Aires'
| 'America/Sao_Paulo'
| 'Atlantic/South_Georgia'
| 'Atlantic/Azores'
| 'Atlantic/Cape_Verde'
| 'Europe/London'
| 'Europe/Berlin'
| 'Africa/Lagos'
| 'Europe/Athens'
| 'Africa/Cairo'
| 'Europe/Moscow'
| 'Asia/Riyadh'
| 'Asia/Dubai'
| 'Asia/Baku'
| 'Asia/Karachi'
| 'Asia/Tashkent'
| 'Asia/Calcutta'
| 'Asia/Dhaka'
| 'Asia/Almaty'
| 'Asia/Jakarta'
| 'Asia/Bangkok'
| 'Asia/Shanghai'
| 'Asia/Singapore'
| 'Asia/Tokyo'
| 'Asia/Seoul'
| 'Australia/Sydney'
| 'Pacific/Guam'
| 'Pacific/Noumea'
| 'Pacific/Auckland'
| 'Pacific/Fiji';
export interface Config {
auth: {
users: UserAuthOperations;
};
blocks: {};
collections: {
posts: Post;
media: Media;
@@ -21,7 +76,7 @@ export interface Config {
};
collectionsJoins: {
_folders: {
documentsAndFolders: '_folders';
documentsAndFolders: '_folders' | 'posts' | 'media';
};
};
collectionsSelect: {
@@ -36,8 +91,12 @@ export interface Config {
db: {
defaultIDType: string;
};
globals: {};
globalsSelect: {};
globals: {
global: Global;
};
globalsSelect: {
global: GlobalSelect<false> | GlobalSelect<true>;
};
locale: null;
user: User & {
collection: 'users';
@@ -74,6 +133,7 @@ export interface Post {
title?: string | null;
heroImage?: (string | null) | Media;
_parentFolder?: (string | null) | FolderInterface;
_folderSearch?: string | null;
updatedAt: string;
createdAt: string;
}
@@ -83,6 +143,8 @@ export interface Post {
*/
export interface Media {
id: string;
_parentFolder?: (string | null) | FolderInterface;
_folderSearch?: string | null;
updatedAt: string;
createdAt: string;
url?: string | null;
@@ -105,9 +167,25 @@ export interface FolderInterface {
_parentFolder?: (string | null) | FolderInterface;
isRoot?: boolean | null;
documentsAndFolders?: {
docs?: (string | FolderInterface)[] | null;
docs?:
| (
| {
relationTo?: '_folders';
value: string | FolderInterface;
}
| {
relationTo?: 'posts';
value: string | Post;
}
| {
relationTo?: 'media';
value: string | Media;
}
)[]
| null;
hasNextPage?: boolean | null;
} | null;
_folderSearch?: string | null;
updatedAt: string;
createdAt: string;
}
@@ -201,6 +279,7 @@ export interface PostsSelect<T extends boolean = true> {
title?: T;
heroImage?: T;
_parentFolder?: T;
_folderSearch?: T;
updatedAt?: T;
createdAt?: T;
}
@@ -209,6 +288,8 @@ export interface PostsSelect<T extends boolean = true> {
* via the `definition` "media_select".
*/
export interface MediaSelect<T extends boolean = true> {
_parentFolder?: T;
_folderSearch?: T;
updatedAt?: T;
createdAt?: T;
url?: T;
@@ -245,6 +326,7 @@ export interface _FoldersSelect<T extends boolean = true> {
_parentFolder?: T;
isRoot?: T;
documentsAndFolders?: T;
_folderSearch?: T;
updatedAt?: T;
createdAt?: T;
}
@@ -280,6 +362,24 @@ export interface PayloadMigrationsSelect<T extends boolean = true> {
updatedAt?: T;
createdAt?: T;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "global".
*/
export interface Global {
id: string;
updatedAt?: string | null;
createdAt?: string | null;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "global_select".
*/
export interface GlobalSelect<T extends boolean = true> {
updatedAt?: T;
createdAt?: T;
globalType?: T;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "auth".

View File

@@ -0,0 +1,105 @@
import type { FolderInterface, Post } from 'folder-view/payload-types.js'
import type { Config, Payload } from 'payload'
import { devUser } from '../../credentials.js'
async function createPost(
payload: Payload,
{ title, _parentFolder }: Pick<Post, '_parentFolder' | 'title'>,
): Promise<Post> {
return payload.create({
collection: 'posts',
data: {
title,
_parentFolder,
},
})
}
async function createFolder(
payload: Payload,
{
name,
_parentFolder,
isRoot = false,
}: Pick<FolderInterface, '_parentFolder' | 'isRoot' | 'name'>,
): Promise<FolderInterface> {
return payload.create({
collection: '_folders',
data: {
name,
_parentFolder,
isRoot,
},
})
}
export const seed: Config['onInit'] = async (payload) => {
await payload.create({
collection: 'users',
data: {
email: devUser.email,
password: devUser.password,
},
})
await createFolder(payload, {
name: 'Root',
isRoot: true,
})
const teamFolder = await createFolder(payload, {
name: 'Team',
})
const [designersFolder, engineersFolder, marketingFolder, salesFolder] = await Promise.all(
['Designers', 'Engineers', 'Marketing', 'Sales'].map((name) =>
createFolder(payload, {
name,
_parentFolder: teamFolder.id,
}),
),
)
const marketers = ['Nate']
const designers = ['Sarah', 'Tylan']
const sales = ['Sean', 'Garrentt', 'Evan']
const engineers = [
'Jarrod',
'James',
'Jacob',
'Alessio',
'Patrik',
'Paul',
'Dan',
'Elliot',
'Sasha',
'Kendell',
'Jessica',
'Germán',
]
await Promise.all([
...sales.map((title) =>
createPost(payload, {
title,
_parentFolder: salesFolder?.id,
}),
),
...marketers.map((title) =>
createPost(payload, {
title,
_parentFolder: marketingFolder?.id,
}),
),
...engineers.map((title) =>
createPost(payload, {
title,
_parentFolder: engineersFolder?.id,
}),
),
...designers.map((title) =>
createPost(payload, {
title,
_parentFolder: designersFolder?.id,
}),
),
])
}