summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Matthew Phillips <matthew@skypack.dev> 2023-01-19 08:34:27 -0500
committerGravatar GitHub <noreply@github.com> 2023-01-19 08:34:27 -0500
commitbe901dc98c4a7f6b5536540aa8f7ba5108e939a0 (patch)
tree70a472215ee49ef4ac63cef2b776818d007df10d
parent4f649014e9323db30d82e36e73f8e9ac1cf13cfa (diff)
downloadastro-be901dc98c4a7f6b5536540aa8f7ba5108e939a0.tar.gz
astro-be901dc98c4a7f6b5536540aa8f7ba5108e939a0.tar.zst
astro-be901dc98c4a7f6b5536540aa8f7ba5108e939a0.zip
Rename getEntry to getEntryBySlug (#5893)
* Rename getEntry to getEntryBySchema * Improve entrySlug types and return undefined * Add changeset * Update packages/astro/src/content/template/types.d.ts Co-authored-by: Ben Holmes <hey@bholmes.dev> * Update the types to accept both raw string and known value * Add comment on the implementation not currently being O(1) Co-authored-by: Ben Holmes <hey@bholmes.dev>
-rw-r--r--.changeset/neat-eagles-trade.md24
-rw-r--r--packages/astro/src/content/internal.ts26
-rw-r--r--packages/astro/src/content/template/types.d.ts16
-rw-r--r--packages/astro/src/content/template/virtual-mod.mjs6
-rw-r--r--packages/astro/test/fixtures/content-collections/src/content/config.ts1
-rw-r--r--packages/astro/test/fixtures/content-collections/src/pages/entries.json.js10
6 files changed, 61 insertions, 22 deletions
diff --git a/.changeset/neat-eagles-trade.md b/.changeset/neat-eagles-trade.md
new file mode 100644
index 000000000..b92353e8e
--- /dev/null
+++ b/.changeset/neat-eagles-trade.md
@@ -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! -->
+```
diff --git a/packages/astro/src/content/internal.ts b/packages/astro/src/content/internal.ts
index d3af7f8f9..550f6665a 100644
--- a/packages/astro/src/content/internal.ts
+++ b/packages/astro/src/content/internal.ts
@@ -69,18 +69,30 @@ 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) {
+ // This is not an optimized lookup. Should look into an O(1) implementation
+ // as it's probably that people will have very large collections.
+ const entries = await getCollection(collection);
+ 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,
diff --git a/packages/astro/src/content/template/types.d.ts b/packages/astro/src/content/template/types.d.ts
index 73d6c21ab..5b4dc874b 100644
--- a/packages/astro/src/content/template/types.d.ts
+++ b/packages/astro/src/content/template/types.d.ts
@@ -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']
diff --git a/packages/astro/src/content/template/virtual-mod.mjs b/packages/astro/src/content/template/virtual-mod.mjs
index 799e780b4..49e01ea02 100644
--- a/packages/astro/src/content/template/virtual-mod.mjs
+++ b/packages/astro/src/content/template/virtual-mod.mjs
@@ -2,7 +2,7 @@
import {
createCollectionToGlobResultMap,
createGetCollection,
- createGetEntry,
+ createGetEntryBySlug,
} from 'astro/content/internal';
export { z } from 'astro/zod';
@@ -34,7 +34,7 @@ export const getCollection = createGetCollection({
collectionToRenderEntryMap,
});
-export const getEntry = createGetEntry({
- collectionToEntryMap,
+export const getEntryBySlug = createGetEntryBySlug({
+ getCollection,
collectionToRenderEntryMap,
});
diff --git a/packages/astro/test/fixtures/content-collections/src/content/config.ts b/packages/astro/test/fixtures/content-collections/src/content/config.ts
index f3b4e921a..dee35967c 100644
--- a/packages/astro/test/fixtures/content-collections/src/content/config.ts
+++ b/packages/astro/test/fixtures/content-collections/src/content/config.ts
@@ -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({
diff --git a/packages/astro/test/fixtures/content-collections/src/pages/entries.json.js b/packages/astro/test/fixtures/content-collections/src/pages/entries.json.js
index 7c9d8f1d4..05fb1187b 100644
--- a/packages/astro/test/fixtures/content-collections/src/pages/entries.json.js
+++ b/packages/astro/test/fixtures/content-collections/src/pages/entries.json.js
@@ -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}),