Skip to content

Commit

Permalink
[feature][s]:support queries by frontmatter fields
Browse files Browse the repository at this point in the history
  • Loading branch information
olayway committed Oct 12, 2023
1 parent b79d9f8 commit 52ff842
Show file tree
Hide file tree
Showing 6 changed files with 85 additions and 1 deletion.
5 changes: 5 additions & 0 deletions .changeset/five-melons-pull.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"mddb": minor
---

Support for querying files by frontmatter field values (exact matches only).
2 changes: 2 additions & 0 deletions __mocks__/content/blog/blog1.mdx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
---
title: My Test Mdx Blog 1
author: John Doe
draft: true
---

# My Test Mdx Blog 1
Expand Down
1 change: 1 addition & 0 deletions __mocks__/content/blog/blog2.mdx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
---
title: My Test Mdx Blog 2
type: blog
author: John Doe
tags:
- economy
---
Expand Down
2 changes: 2 additions & 0 deletions __mocks__/content/blog/blog3.mdx
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
---
title: My Test Mdx Blog 2
type: blog
author: Jan Kowalski
draft: true
tags:
- politics
- economy
Expand Down
45 changes: 45 additions & 0 deletions src/lib/markdowndb.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,51 @@ describe("MarkdownDB - default config", () => {
});
});

test("can query by a frontmatter field", async () => {
const dbFiles = await mddb.getFiles({
frontmatter: { author: "John Doe" },
});
const dbFilesPaths = dbFiles.map((f) => f.file_path);

const expectedPaths = [
`${pathToContentFixture}/blog/blog1.mdx`,
`${pathToContentFixture}/blog/blog2.mdx`,
];

expect(dbFilesPaths).toHaveLength(expectedPaths.length);
dbFilesPaths.forEach((p) => {
expect(expectedPaths).toContain(p);
});
});

test("can query by multiple frontmatter fields", async () => {
const dbFiles = await mddb.getFiles({
frontmatter: { author: "John Doe", draft: true },
});
const dbFilesPaths = dbFiles.map((f) => f.file_path);

const expectedPaths = [`${pathToContentFixture}/blog/blog1.mdx`];

expect(dbFilesPaths).toHaveLength(expectedPaths.length);
dbFilesPaths.forEach((p) => {
expect(expectedPaths).toContain(p);
});
});

test("can get records with non-existing field for `false` queries", async () => {
const dbFiles = await mddb.getFiles({
frontmatter: { author: "John Doe", draft: false },
});
const dbFilesPaths = dbFiles.map((f) => f.file_path);

const expectedPaths = [`${pathToContentFixture}/blog/blog2.mdx`];

expect(dbFilesPaths).toHaveLength(expectedPaths.length);
dbFilesPaths.forEach((p) => {
expect(expectedPaths).toContain(p);
});
});

test("can query by tags AND filetypes AND extensions", async () => {
const dbFiles = await mddb.getFiles({
tags: ["culture"],
Expand Down
31 changes: 30 additions & 1 deletion src/lib/markdowndb.ts
Original file line number Diff line number Diff line change
Expand Up @@ -238,8 +238,9 @@ export class MarkdownDB {
filetypes?: string[];
tags?: string[];
extensions?: string[];
frontmatter?: Record<string, string | number | boolean>;
}): Promise<MddbFile[]> {
const { filetypes, tags, extensions, folder } = query || {};
const { filetypes, tags, extensions, folder, frontmatter } = query || {};

const files = await this.db
// TODO join only if tags are specified ?
Expand All @@ -260,6 +261,34 @@ export class MarkdownDB {
if (filetypes) {
builder.whereIn("filetype", filetypes);
}

if (frontmatter) {
Object.entries(frontmatter).forEach(([key, value]) => {
if (typeof value === "string" || typeof value === "number") {
builder.whereRaw(`json_extract(metadata, '$.${key}') = ?`, [
value,
]);
} else if (typeof value === "boolean") {
if (value) {
builder.whereRaw(`json_extract(metadata, '$.${key}') = ?`, [
true,
]);
} else {
builder.where(function () {
this.whereRaw(`json_extract(metadata, '$.${key}') = ?`, [
false,
]).orWhereRaw(`json_extract(metadata, '$.${key}') IS NULL`);
});
}
}
// To check if the provided value exists in an array inside the JSON
else {
builder.whereRaw(`json_extract(metadata, '$.${key}') LIKE ?`, [
`%${value}%`,
]);
}
});
}
})
.select("files.*")
.from("files")
Expand Down

0 comments on commit 52ff842

Please sign in to comment.