diff --git a/README.md b/README.md index b866ccb..2582931 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,7 @@ npm install fastify-orama ## Usage This plugin adds the `orama` decorator to your Fastify application. +The decorator exposes all the methods that [the Orama class exposes](https://docs.oramasearch.com/usage/create). The `options` object is passed directly to the `Orama.create` constructor, so it supports [all the options that Orama supports](https://docs.oramasearch.com/usage/create). @@ -56,9 +57,9 @@ This plugin supports data persistence out of the box. You need to pass the `persistence` option to the plugin registration! This plugin uses [`@oramasearch/plugin-data-persistence`](https://docs.oramasearch.com/plugins/plugin-data-persistence) -under the hood to allow users to `load` or `save` database instances. +under the hood to allow users to `load` or `persist` database instances. -Turning on the `persistence` option will add the `fastify.orama.save()` method to your Fastify application. +Turning on the `persistence` option will add the `fastify.orama.persist()` method to your Fastify application. You must call this method to save the database instance to the persistence layer, otherwise your data will be lost. ### PersistenceInFile @@ -103,8 +104,8 @@ app.post('/quotes', async function (req, reply) { return { success: true } }) -app.addHook('onClose', async function save (app) { - const path = await app.orama.save() +app.addHook('onClose', async function persist (app) { + const path = await app.orama.persist() app.log.info(`Database saved to ${path}`) }) @@ -137,7 +138,7 @@ await appOne.orama.insert({ author: 'Mateo Nunez' }) -const inMemoryDb = await appOne.orama.save() +const inMemoryDb = await appOne.orama.persist() // Close the Fastify application await appOne.close() @@ -169,7 +170,7 @@ const customPersistance = { persist: async function persist (db) { // Persist the database instance to the persistence layer - // Whatever this method returns will be passed to the `app.orama.save()` method + // Whatever this method returns will be passed to the `app.orama.persist()` method } await fastify.register(fastifyOrama, { @@ -178,6 +179,29 @@ await fastify.register(fastifyOrama, { }) ``` +## Orama Internals + +Do you need to access the [Orama internals utilities](https://docs.oramasearch.com/internals/utilities)? +No problem! + +```js +import { fastifyOrama, oramaInternals } from 'fastify-orama' + +const app = Fastify() + +// The database must exists to load it in your Fastify application +app.register(fastifyOrama, { + schema: { + quote: "string", + author: "string" + } +}) + +app.get('/genId', async function handler (req, reply) { + return { newId: await oramaInternals.uniqueId() } +}) +``` + ## License fastifyOrama is licensed under the [MIT](LICENSE) license. diff --git a/index.d.ts b/index.d.ts index 4b9684e..834c7a7 100644 --- a/index.d.ts +++ b/index.d.ts @@ -35,7 +35,7 @@ declare module 'fastify' { orama: { insert: (document: Document) => Promise, search: (params: SearchParams) => Promise, - save?: () => Promise, + persist?: () => Promise, } } } diff --git a/index.js b/index.js index ff456c2..206ced7 100644 --- a/index.js +++ b/index.js @@ -1,9 +1,15 @@ import fp from 'fastify-plugin' -import { create, insert, search } from '@orama/orama' // todo we are limiting the api to the server side +import * as Orama from '@orama/orama' import PersistenceInMemory from './lib/persistence/in-memory.js' import PersistenceInFile from './lib/persistence/in-file.js' +const SKIP_METHODS = [ + 'create' +] + +const oramaInternals = Orama.internals + async function fastifyOrama (fastify, options) { if (fastify.orama) { throw new Error('fastify-orama is already registered') @@ -17,15 +23,20 @@ async function fastifyOrama (fastify, options) { let db const oramaApi = { - insert: (...args) => insert(db, ...args), - search: (...args) => search(db, ...args), - save: undefined + persist: undefined // custom + } + + const oramaProxyKeys = Object.keys(Orama) + .filter((key) => typeof Orama[key] === 'function' && !SKIP_METHODS.includes(key)) + + for (const key of oramaProxyKeys) { + oramaApi[key] = (...args) => Orama[key](db, ...args) } if (persistence) { db = await persistence.restore() - oramaApi.save = /* async */ function save () { + oramaApi.persist = /* async */ function persist () { return persistence.persist(db) } } @@ -35,7 +46,7 @@ async function fastifyOrama (fastify, options) { throw new Error('You must provide a schema to create a new database') } - db = await create(oramaOptions) + db = await Orama.create(oramaOptions) } fastify.decorate('orama', oramaApi) @@ -49,5 +60,6 @@ export default fp(fastifyOrama, { export { fastifyOrama, PersistenceInMemory, - PersistenceInFile + PersistenceInFile, + oramaInternals } diff --git a/test/fastify-orama.test.js b/test/index.test.js similarity index 97% rename from test/fastify-orama.test.js rename to test/index.test.js index ebc8e1f..50bc6d2 100644 --- a/test/fastify-orama.test.js +++ b/test/index.test.js @@ -15,7 +15,7 @@ it('Should register correctly fastifyOrama plugin', async () => { }) ok(fastify.orama) - ok(fastify.orama.save === undefined) + ok(fastify.orama.persist === undefined) }) it('Should insert and retrieve data using Orama', async () => { diff --git a/test/orama-proxy.test.js b/test/orama-proxy.test.js new file mode 100644 index 0000000..83fe080 --- /dev/null +++ b/test/orama-proxy.test.js @@ -0,0 +1,109 @@ +'use strict' + +import { it } from 'node:test' +import { ok, strictEqual } from 'node:assert' +import Fastify from 'fastify' +import { fastifyOrama, oramaInternals } from '../index.js' + +it('Should expose all the Orama APIs', async () => { + const fastify = Fastify() + + await fastify.register(fastifyOrama, { + id: 'my-orama-instance', + schema: { + title: 'string', + director: 'string', + plot: 'string', + year: 'number', + isFavorite: 'boolean' + } + }) + + const harryPotterId = await fastify.orama.insert({ + title: 'Harry Potter and the Philosopher\'s Stone', + director: 'Chris Columbus', + plot: 'Harry Potter, an eleven-year-old orphan, discovers that he is a wizard and is invited to study at Hogwarts. Even as he escapes a dreary life and enters a world of magic, he finds trouble awaiting him.', + year: 2001, + isFavorite: false + }) + ok(harryPotterId, 'the id is returned') + + const docs = [ + { + title: 'The prestige', + director: 'Christopher Nolan', + plot: 'Two friends and fellow magicians become bitter enemies after a sudden tragedy. As they devote themselves to this rivalry, they make sacrifices that bring them fame but with terrible consequences.', + year: 2006, + isFavorite: true + }, + { + title: 'Big Fish', + director: 'Tim Burton', + plot: 'Will Bloom returns home to care for his dying father, who had a penchant for telling unbelievable stories. After he passes away, Will tries to find out if his tales were really true.', + year: 2004, + isFavorite: true + } + ] + + const docIds = await fastify.orama.insertMultiple(docs, 500) + ok(docIds.length === 2, 'the ids are returned') + + const thePrestige = await fastify.orama.getByID(docIds[0]) + strictEqual(thePrestige.title, 'The prestige') + + const docNumber = await fastify.orama.count() + strictEqual(docNumber, 3) + + const del = await fastify.orama.remove(harryPotterId) + ok(del, 'the document was deleted') + + const docNumberUpdated = await fastify.orama.count() + strictEqual(docNumberUpdated, 2) + + const delMultiple = await fastify.orama.removeMultiple(docIds, 500) + strictEqual(delMultiple, 2, 'the documents were deleted') + + const docEmpty = await fastify.orama.count() + strictEqual(docEmpty, 0) +}) + +it('Should not expose some Orama APIs', async () => { + const fastify = Fastify() + + await fastify.register(fastifyOrama, { + id: 'my-orama-instance', + schema: { + title: 'string', + director: 'string', + plot: 'string', + year: 'number', + isFavorite: 'boolean' + } + }) + + ok(fastify.orama.create === undefined) +}) + +it('Should not expose Orama internals', async () => { + const fastify = Fastify() + + fastify.register(fastifyOrama, { + id: 'my-orama-instance', + schema: { + title: 'string', + director: 'string', + plot: 'string', + year: 'number', + isFavorite: 'boolean' + } + }) + + fastify.get('/genId', async function handler () { + return { newId: await oramaInternals.uniqueId() } + }) + + const response = await fastify.inject('/genId') + strictEqual(response.statusCode, 200) + ok(response.json().newId, 'the id is returned') + ok(typeof response.json().newId === 'string', 'the id is a string') +}) diff --git a/test/fastify-orama-persistence.test.js b/test/persistence.test.js similarity index 97% rename from test/fastify-orama-persistence.test.js rename to test/persistence.test.js index 823d06a..50043f3 100644 --- a/test/fastify-orama-persistence.test.js +++ b/test/persistence.test.js @@ -85,7 +85,7 @@ describe('PersistenceInFile', () => { author: 'Mateo Nunez' }) - const path = await fastify.orama.save() + const path = await fastify.orama.persist() strictEqual(path, opts.filePath) { @@ -156,7 +156,7 @@ describe('PersistenceInMemory', () => { author: 'Mateo Nunez' }) - const inMemoryDb = await fastifyOne.orama.save() + const inMemoryDb = await fastifyOne.orama.persist() { const results = await fastifyOne.orama.search({ term: 'Mateo Nunez' })