import { RouterOptions, Router, Request, Response, NextFunction } from 'express';
import { JSONSchemaType } from 'ajv';
export { ValidationError } from 'ajv';
import { Db, ObjectId } from 'mongodb';

interface DateFields$1 {
    added?: string;
    lastModified?: string;
    deleted?: string;
}
type DbResolver = () => Db;
interface MongoRestRouterOptions extends RouterOptions {
    db?: Db | DbResolver | string;
    /** A list of methods to provide. Provide all if unset. */
    methods?: ('GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE')[];
    sort?: object;
    noGetSearch?: boolean;
    noPostBulk?: boolean;
    resultsField?: string;
    noArchive?: boolean;
    noManagedDates?: boolean;
    dateFields?: DateFields$1;
}
/**
 * A function to expose a Mongo Collection as a REST API.
 * - GET '/' - returns an object with `count` and results of search in a field named the same as the collection.
 * - GET '/:id'
 * - POST '/' - return either `insertedId` or a list of ids as `insertedIds`, if an array is posted
 * - PUT '/:id'
 * - PATCH '/:id' - expects a JSON Patch definition
 * - DELETE '/:id'
 *
 * @param {string} collection name of collection
 * @param {JSONSchemaType} schema a JSON Schema definition
 * @param {(Db|DbResolver)} options.db Mongo database. Uses req.locals.db if unset.
 * @param {('GET'|'POST'|'PUT'|'PATCH'|'DELETE')[]} options.methods List of methods to provide. Provides all if unset.
 * @param {object} options.sort the sorting to unless overridden by query parameters
 * @param {boolean} options.noGetSearch Do not provide the GET '/' route for searching.
 * @param {boolean} options.noPostBulk Do not allow an array to be provided to the POST method.
 * @param {string} options.resultsField Use this instead of the collection name as the search results field.
 * @param {boolean} options.noArchive Don't set the deleted property upon first DELETE. Remove immediately.
 * @param {boolean} options.noManagedDates Don't set date tracking fields: added, lastModified, or deleted.
 * @param {string} options.dateFields.added Use this instead of 'added' for tracking POST operations.
 * @param {string} options.dateFields.lastModified Use this instead of 'lastModified' for tracking last PUT and PATCH operations.
 * @param {string} options.dateFields.deleted Use this instead of 'deleted' for tracking DELETE operations.
 *
 * @returns {Router} an express router that exposes the collection via a REST API.
 *
 * @example
 * const BookSchema = {type: "object", properties { title: { type: "string", ...}}}
 * const booksAPI = MongRestRouter('books', BookSchema)
 * const app = express()
 * app.use('/api/v1/books', booksAPI)
 */
declare const MongoRestRouter: <T extends object>(collection: string, schema: JSONSchemaType<T>, options?: MongoRestRouterOptions) => Router;

interface HasId {
    [key: string]: any;
    _id: ObjectId;
}
/**
 * Applies a PATCH request to an Mongo document.
 *
 * @param origObject An object with an `_id` field to verify the patch doesn't modify it
 * @param req An express Request object with a query and body
 * @returns the patch result
 * @throws ValidationError if the body is not a JSONPatch object, or the _id value is modified.
 */
declare const applyPatchRequest: (origObject: HasId, req: Request) => HasId;

interface DateFields {
    added?: string;
    lastModified?: string;
    deleted?: string;
}
interface Options {
    dateFields?: DateFields;
}
declare const getValidate: <T extends object>(schema: JSONSchemaType<T>, options?: Options) => {
    validate: (payload: unknown, options?: {
        allowManagedDates: boolean;
    }) => T;
    validateBulk: (payload: unknown) => (T[]);
};

/** Handles sending a 400 Bad Request response when catching a validation error. */
declare const handleValidateError: (e: unknown, res: Response) => Response<any, Record<string, any>>;

/**
 * Middleware to add db instance to the Request. Uses env var MONGO_URL to define connection.
 *
 * @example
 * app.get('/api/v1/users', async (req:Request, res:Response) => {
 *   res.send(await req.locals.db.collection('users').find({}).toArray())
 * })
 */
declare const withDb: (db?: Db | (() => Db) | string) => (req: Request, res: Response, next?: NextFunction) => void;

export { MongoRestRouter, type MongoRestRouterOptions, applyPatchRequest, getValidate, handleValidateError, withDb };
