Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rename getEntry to getEntryBySlug #5893

Merged
merged 6 commits into from
Jan 19, 2023
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions .changeset/neat-eagles-trade.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
---
'astro': major
---

Move getEntry to getEntryBySlug

This change moves `getEntry` to `getEntryBySlug` and accepts a slug rather than an id.

In order to improve support in `[id].astro` routes, particularly in SSR where you do not know what the id of a collection is. Using `getEntryBySlug` instead allows you to map the `[id]` param in your route to the entry. You can use it like this:

```astro
---
import { getEntryBySlug } from 'astro:content';

const entry = await getEntryBySlug('docs', Astro.params.id);

if(!entry) {
return new Response(null, {
status: 404
});
}
---
<!-- You have an entry! Use it! -->
```
24 changes: 17 additions & 7 deletions packages/astro/src/content/internal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,18 +69,28 @@ export function createGetCollection({
};
}

export function createGetEntry({
collectionToEntryMap,
export function createGetEntryBySlug({
getCollection,
collectionToRenderEntryMap,
}: {
collectionToEntryMap: CollectionToEntryMap;
getCollection: ReturnType<typeof createGetCollection>;
collectionToRenderEntryMap: CollectionToEntryMap;
}) {
return async function getEntry(collection: string, entryId: string) {
const lazyImport = collectionToEntryMap[collection]?.[entryId];
if (!lazyImport) throw new Error(`Failed to import ${JSON.stringify(entryId)}.`);
return async function getEntryBySlug(collection: string, slug: string) {
const entries = await getCollection(collection);
matthewp marked this conversation as resolved.
Show resolved Hide resolved
let candidate: typeof entries[number] | undefined = undefined;
for(let entry of entries) {
if(entry.slug === slug) {
candidate = entry;
break;
}
}

if(typeof candidate === 'undefined') {
return undefined;
}

const entry = await lazyImport();
const entry = candidate;
return {
id: entry.id,
slug: entry.slug,
Expand Down
16 changes: 10 additions & 6 deletions packages/astro/src/content/template/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,17 +30,21 @@ declare module 'astro:content' {
input: BaseCollectionConfig<S>
): BaseCollectionConfig<S>;

export function getEntry<C extends keyof typeof entryMap, E extends keyof (typeof entryMap)[C]>(
type EntryMapKeys = keyof typeof entryMap;
type AllValuesOf<T> = T extends any ? T[keyof T] : never;
type ValidEntrySlug<C extends EntryMapKeys> = AllValuesOf<typeof entryMap[C]>['slug'];

export function getEntryBySlug<C extends keyof typeof entryMap, E extends ValidEntrySlug<C> | (string & {})>(
collection: C,
entryKey: E
): Promise<(typeof entryMap)[C][E] & Render>;
// Note that this has to accept a regular string too, for SSR
entrySlug: E
): E extends ValidEntrySlug<C> ? Promise<CollectionEntry<C>> : Promise<CollectionEntry<C> | undefined>;
export function getCollection<
C extends keyof typeof entryMap,
E extends keyof (typeof entryMap)[C]
>(
collection: C,
filter?: (data: (typeof entryMap)[C][E]) => boolean
): Promise<((typeof entryMap)[C][E] & Render)[]>;
filter?: (data: CollectionEntry<C>) => boolean
): Promise<CollectionEntry<C>[]>;

type InferEntrySchema<C extends keyof typeof entryMap> = import('astro/zod').infer<
Required<ContentConfig['collections'][C]>['schema']
Expand Down
6 changes: 3 additions & 3 deletions packages/astro/src/content/template/virtual-mod.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import {
createCollectionToGlobResultMap,
createGetCollection,
createGetEntry,
createGetEntryBySlug,
} from 'astro/content/internal';

export { z } from 'astro/zod';
Expand Down Expand Up @@ -34,7 +34,7 @@ export const getCollection = createGetCollection({
collectionToRenderEntryMap,
});

export const getEntry = createGetEntry({
collectionToEntryMap,
export const getEntryBySlug = createGetEntryBySlug({
getCollection,
collectionToRenderEntryMap,
});
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { z, defineCollection } from 'astro:content';

const withSlugConfig = defineCollection({
slug({ id, data }) {
console.log({id, data})
return `${data.prefix}-${id}`;
},
schema: z.object({
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { getEntry } from 'astro:content';
import { getEntryBySlug } from 'astro:content';
import * as devalue from 'devalue';
import { stripRenderFn } from '../utils.js';

export async function get() {
const columbiaWithoutConfig = stripRenderFn(await getEntry('without-config', 'columbia.md'));
const oneWithSchemaConfig = stripRenderFn(await getEntry('with-schema-config', 'one.md'));
const twoWithSlugConfig = stripRenderFn(await getEntry('with-slug-config', 'two.md'));
const postWithUnionSchema = stripRenderFn(await getEntry('with-union-schema', 'post.md'));
const columbiaWithoutConfig = stripRenderFn(await getEntryBySlug('without-config', 'columbia'));
const oneWithSchemaConfig = stripRenderFn(await getEntryBySlug('with-schema-config', 'one'));
const twoWithSlugConfig = stripRenderFn(await getEntryBySlug('with-slug-config', 'interesting-two.md'));
const postWithUnionSchema = stripRenderFn(await getEntryBySlug('with-union-schema', 'post'));

return {
body: devalue.stringify({columbiaWithoutConfig, oneWithSchemaConfig, twoWithSlugConfig, postWithUnionSchema}),
Expand Down