Skip to content

Commit 3e74e92

Browse files
authored
Merge pull request #13 from inaiat/refactor/use_only_fn_to_collection_model_and_indexes/omurilo
refact: use only asCollecion and send collection name, schema and indexes
2 parents 330612d + e97f012 commit 3e74e92

File tree

8 files changed

+226
-136
lines changed

8 files changed

+226
-136
lines changed

README.md

+7-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
# fastify-papr
2+
23
![Statements](https://img.shields.io/badge/statements-98.75%25-brightgreen.svg?style=flat) ![Branches](https://img.shields.io/badge/branches-85%25-yellow.svg?style=flat) ![Functions](https://img.shields.io/badge/functions-100%25-brightgreen.svg?style=flat) ![Lines](https://img.shields.io/badge/lines-98.75%25-brightgreen.svg?style=flat)
34

45
A fastify Papr plugin integration.
@@ -10,9 +11,10 @@ yarn add @inaiat/fastify-papr @fastify/mongodb
1011
```
1112

1213
Next, set up the plugin:
14+
1315
```ts
1416
import fastifyMongodb from '@fastify/mongodb'
15-
import fastifyPaprPlugin, { asModel, FastifyPaprOptions } from ' @inaiat/fastify-papr'
17+
import fastifyPaprPlugin, { asCollection, FastifyPaprOptions } from ' @inaiat/fastify-papr'
1618
import fp from 'fastify-plugin'
1719
import { Model, schema, types } from 'papr'
1820

@@ -21,6 +23,8 @@ const userSchema = schema({
2123
phone: types.string({ required: true, minLength: 8, maxLength: 20 }),
2224
})
2325

26+
const userIndexes = [{ key: { name: 1 } }]
27+
2428
declare module 'fastify' {
2529
interface PaprModels {
2630
user: Model<typeof userSchema[0], Partial<typeof userSchema[1]>>
@@ -35,14 +39,15 @@ export default fp<FastifyPaprOptions>(
3539

3640
await fastify.register(fastifyPaprPlugin, {
3741
db: fastify.mongo.client.db('test'),
38-
models: { user: asModel('user', userSchema) },
42+
models: { user: asCollection('user', userSchema, userIndexes) },
3943
})
4044
},
4145
{ name: 'papr' },
4246
)
4347
```
4448

4549
How to use:
50+
4651
```ts
4752
import { FastifyPluginAsync } from 'fastify'
4853
import { Static, Type } from '@sinclair/typebox'

package-lock.json

+97-97
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@inaiat/fastify-papr",
3-
"version": "4.0.1",
3+
"version": "4.1.0",
44
"description": "Fastify Papr Plugin Integration",
55
"type": "module",
66
"engines": {
@@ -56,7 +56,7 @@
5656
},
5757
"devDependencies": {
5858
"@swc/cli": "^0.1.62",
59-
"@swc/core": "^1.3.50",
59+
"@swc/core": "^1.3.51",
6060
"@swc/helpers": "^0.5.0",
6161
"@types/node": "^18.15.11",
6262
"@types/semver": "^7.3.13",
@@ -70,8 +70,8 @@
7070
"typescript": "^5.0.4",
7171
"xo": "^0.54.1",
7272
"eslint-plugin-unused-imports": "^2.0.0",
73-
"eslint-plugin-functional": "5.0.7",
74-
"eslint-plugin-prettier": "4.2.1"
73+
"eslint-plugin-functional": "^5.0.8",
74+
"eslint-plugin-prettier": "^4.2.1"
7575
},
7676
"files": [
7777
"dist"
@@ -163,4 +163,4 @@
163163
}
164164
},
165165
"author": "[email protected]"
166-
}
166+
}

src/index.ts

+28-11
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,42 @@
11
import fp from 'fastify-plugin'
2-
import type {BaseSchema, Model, SchemaOptions} from 'papr'
2+
import type { BaseSchema, Model, SchemaOptions } from 'papr'
33
import { IndexDescription } from 'mongodb'
4-
import type {FastifyPaprOptions, PaprModels} from './types.js'
5-
import {paprHelper} from './papr-helper.js'
4+
import type { FastifyPaprOptions, PaprModelItem, PaprModels } from './types.js'
5+
import { paprHelper } from './papr-helper.js'
66

7-
export const asModel = <TSchema extends BaseSchema>(
7+
export const asCollection = <TSchema extends BaseSchema>(
88
collectionName: string,
99
// eslint-disable-next-line functional/prefer-immutable-types
1010
collectionSchema: [TSchema, SchemaOptions<Partial<TSchema>>],
11-
) => ({
11+
// eslint-disable-next-line functional/prefer-immutable-types
12+
collectionIndexes?: IndexDescription[],
13+
): PaprModelItem => ({
1214
collectionName,
1315
collectionSchema,
16+
collectionIndexes,
1417
})
1518

16-
export const asIndexes = (collectionName: string, collectionIndexes: readonly IndexDescription[]) => ({collectionName, collectionIndexes})
19+
/**
20+
* @deprecated Since version 4.0. Will be deleted in version 5.0. Use {@link asCollection} instead.
21+
*/
22+
export const asModel = <TSchema extends BaseSchema>(
23+
collectionName: string,
24+
// eslint-disable-next-line functional/prefer-immutable-types
25+
collectionSchema: [TSchema, SchemaOptions<Partial<TSchema>>],
26+
): PaprModelItem => ({
27+
collectionName,
28+
collectionSchema,
29+
})
1730

1831
const fastifyPaprPlugin = fp<FastifyPaprOptions>(
1932
async (mutable_fastify, options) => {
20-
const helper = paprHelper(mutable_fastify, options.db, options.disableSchemaReconciliation)
21-
const models = await helper.register(options.models, options.indexes)
22-
const {name} = options
33+
const helper = paprHelper(
34+
mutable_fastify,
35+
options.db,
36+
options.disableSchemaReconciliation,
37+
)
38+
const models = await helper.register(options.models)
39+
const { name } = options
2340
if (name) {
2441
if (!mutable_fastify.papr) {
2542
mutable_fastify.decorate('papr', models)
@@ -36,10 +53,10 @@ const fastifyPaprPlugin = fp<FastifyPaprOptions>(
3653
mutable_fastify.decorate('papr', models)
3754
}
3855
},
39-
{fastify: '4.x', name: 'fastify-papr-plugin'},
56+
{ fastify: '4.x', name: 'fastify-papr-plugin' },
4057
)
4158

4259
export default fastifyPaprPlugin
43-
export {fastifyPaprPlugin}
60+
export { fastifyPaprPlugin }
4461
export * from './types.js'
4562
export * from './simple-doc-failed-validation.js'

src/papr-helper.ts

+11-12
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import type {FastifyInstance} from 'fastify'
22
import type {Db, IndexDescription} from 'mongodb'
33
import Papr, {type Model, BaseSchema, SchemaOptions} from 'papr'
4-
import {type PaprModels, ModelRegistrationPair, IndexesRegistrationPair} from './types.js'
4+
import {type PaprModels, ModelRegistrationPair} from './types.js'
55

66
export const paprHelper = (fastify: Readonly<FastifyInstance>, db: Db, disableSchemaReconciliation = false) => {
77
const papr = new Papr()
@@ -24,18 +24,17 @@ export const paprHelper = (fastify: Readonly<FastifyInstance>, db: Db, disableSc
2424
const registerIndexes = async (collectionName: string, indexes: readonly IndexDescription[]) => db.collection(collectionName).createIndexes(indexes as IndexDescription[])
2525

2626
return {
27-
async register(schemas: ModelRegistrationPair<PaprModels>, indexes: readonly IndexesRegistrationPair[] = []): Promise<PaprModels> {
28-
indexes.map(async ({ collectionIndexes, collectionName}) => {
29-
const index = await registerIndexes(collectionName, collectionIndexes)
30-
fastify.log.info(`Indexes to ${collectionName} created`)
31-
return index
32-
})
33-
27+
async register(models: ModelRegistrationPair<PaprModels>): Promise<PaprModels> {
3428
return Object.fromEntries(await Promise.all(
35-
Object.entries(schemas).map(async ([modelName, modelObject]) => {
36-
const model = await registerModel(modelObject.collectionName, modelObject.collectionSchema)
37-
fastify.log.info(`Model ${modelName} decorated`)
38-
return [modelName, model] as [string, Model<BaseSchema, SchemaOptions<Partial<BaseSchema>>>]
29+
Object.entries(models).map(async ([name, paprModel]) => {
30+
const model = await registerModel(paprModel.collectionName, paprModel.collectionSchema)
31+
fastify.log.info(`Model ${name} decorated`)
32+
if (paprModel.collectionIndexes) {
33+
const index = await registerIndexes(paprModel.collectionName, paprModel.collectionIndexes)
34+
fastify.log.info(`Indexes for ${paprModel.collectionName} => ${index.join(', ')} created.`)
35+
}
36+
37+
return [name, model] as [string, Model<BaseSchema, SchemaOptions<Partial<BaseSchema>>>]
3938
}),
4039
))
4140
},

src/types.ts

+10-8
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
1-
import type {Model} from 'papr'
1+
import type {BaseSchema, Model, SchemaOptions} from 'papr'
22
import type {Db, IndexDescription} from 'mongodb'
3-
import type {asModel} from './index.js'
43

5-
export type PaprModelItem = ReturnType<typeof asModel>
4+
export type PaprModelItem = {
5+
collectionName: string
6+
collectionSchema: [BaseSchema, SchemaOptions<Partial<BaseSchema>>]
7+
collectionIndexes?: IndexDescription[]
8+
}
69

710
export type ModelRegistrationPair<T> = {
811
[U in keyof T]: PaprModelItem
@@ -18,11 +21,10 @@ export type PaprModels = Record<string, Model<any, any>>
1821
export type FastifyPaprNestedObject = Record<string, PaprModels>
1922

2023
export type FastifyPaprOptions = {
21-
name?: string;
22-
db: Db;
23-
models: ModelRegistrationPair<PaprModels>;
24-
disableSchemaReconciliation?: boolean;
25-
indexes?: readonly IndexesRegistrationPair[];
24+
name?: string
25+
db: Db
26+
models: ModelRegistrationPair<PaprModels>
27+
disableSchemaReconciliation?: boolean
2628
}
2729

2830
declare module 'fastify' {

tests/helpers/server.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import {MongoMemoryServer} from 'mongodb-memory-server'
55
import {MongoClient} from 'mongodb'
66

77
export const getTestServer = () => {
8-
const server = fastify()
8+
const server = fastify({ logger: true})
99

1010
server.setErrorHandler((error, request, reply) => {
1111
console.error(error)

tests/index.test.ts

+67
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import type {Model} from 'papr'
2+
import {schema, types} from 'papr'
3+
import { MongoServerError } from 'mongodb'
4+
import fastifyPaprPlugin, { asCollection} from '../src/index.js'
5+
import {getConfiguredTestServer, test} from './helpers/server.js'
6+
7+
export const userSchema = schema({
8+
name: types.string({required: true, maxLength: 20}),
9+
phone: types.string({required: true, minimum: 14}),
10+
age: types.number({required: true, minimum: 18, maximum: 200}),
11+
})
12+
13+
declare module 'fastify' {
14+
interface PaprModels {
15+
user: Model<typeof userSchema[0], typeof userSchema[1]>;
16+
}
17+
}
18+
19+
test('Test if index exists and works', async t => {
20+
const {server: fastify} = getConfiguredTestServer()
21+
22+
const db = t.context.client.db()
23+
24+
await fastify.register(fastifyPaprPlugin, {
25+
db,
26+
models: {
27+
user: asCollection('user', userSchema, [{key: {name: -1}}, {key: {age: 1}}]),
28+
},
29+
})
30+
31+
await fastify.papr.user.insertOne({name: 'Elizeu Drummond', age: 35, phone: '552124561234'})
32+
await fastify.papr.user.insertOne({name: 'Luiz Pareto', age: 70, phone: '552124561234'})
33+
await fastify.papr.user.insertOne({name: 'José Augusto', age: 25, phone: '552124561234'})
34+
35+
const r = db.collection('user').find().hint({age: 1})
36+
37+
const e = await r.explain()
38+
39+
t.is(e.ok, 1)
40+
t.is((await fastify.papr.user.find({})).length, 3)
41+
})
42+
43+
test('Missing index should fail', async t => {
44+
const {server: fastify} = getConfiguredTestServer()
45+
46+
const db = t.context.client.db()
47+
48+
await fastify.register(fastifyPaprPlugin, {
49+
db,
50+
models: {
51+
user: asCollection('user', userSchema),
52+
},
53+
})
54+
55+
await fastify.papr.user.insertOne({name: 'Elizeu Drummond', age: 35, phone: '552124561234'})
56+
await fastify.papr.user.insertOne({name: 'Luiz Pareto', age: 70, phone: '552124561234'})
57+
await fastify.papr.user.insertOne({name: 'José Augusto', age: 25, phone: '552124561234'})
58+
59+
const r = db.collection('user').find().hint({name: -1})
60+
61+
const error = await t.throwsAsync(async () => r.explain(), {
62+
instanceOf: MongoServerError,
63+
})
64+
65+
t.is(error?.code, 2)
66+
})
67+

0 commit comments

Comments
 (0)