mixmaxhq / mongo-cursor-pagination

Cursor-based pagination for Mongo
https://www.mixmax.com/careers
MIT License
229 stars 72 forks source link

Mongoose and typescript #366

Open akshay-nm opened 3 days ago

akshay-nm commented 3 days ago

I am trying to set things up with mongoose. I have a bunch of discriminators also. I would like to have types support.

Property 'paginate' does not exist on type 'Model<TItemDelivery, {}, {}, {}, Document<unknown, {}, TItemDelivery> & TItemDelivery & Required<{ _id: ObjectId; }> & { ...; }, any>'.ts

This is the error I am greeted with when trying to use the package. How to fix? Is there a guide on how to set things up for mongoose in typescript?

akshay-nm commented 3 days ago

I tried setting up a custom.d.ts as suggested in https://github.com/mixmaxhq/mongo-cursor-pagination/issues/332#issuecomment-1402187988 but this only resolves the declaration file missing warning, does not fix the error.

akshay-nm commented 2 days ago

At the moment I am doing this:

import MongooseDelete, {
    SoftDeleteModel,
    SoftDeleteDocument,
} from "mongoose-delete";
import MongoPaging from "mongo-cursor-pagination";

export interface TUserSession extends Timestamps, SoftDeleteDocument {...}
const schema = new Schema<TUserSession>(
    {  ...  },
    { timestamps: true }
);

schema.plugin(MongooseDelete);
schema.plugin(MongoPaging.mongoosePlugin);

export const UserSession = model<TUserSession>(
    "UserSession",
    schema
) as unknown as PaginateModel<SoftDeleteModel<TUserSession>>;

Is there a way to lose the unknown?

akshay-nm commented 2 days ago

This is what my custom.d.ts looks like:

import { SoftDeleteModel } from "mongoose-delete";

declare module "mongo-cursor-pagination" {
    type PaginatedPluginFn = (schema: any, options: any) => void;
    const mongoosePlugin: PaginatedPluginFn;
    export { mongoosePlugin };
}

declare module "mongoose" {
    type ModelKeys<T> = Exclude<keyof T, keyof Omit<Document, "_id">>;

    interface PaginateResult<T> {
        results: T[];
        next?: string;
        previous?: string;
        hasNext?: boolean;
        hasPrevious?: boolean;
    }

    interface PaginateModel<
        T extends Omit<mongoose.Document, "delete">,
        QueryHelpers = {},
        TInstanceMethods = {},
        TVirtuals = {},
        THydratedDocumentType = mongoose.HydratedDocument<
            T,
            TVirtuals & TInstanceMethods,
            QueryHelpers
        >,
        TSchema = any
    > extends SoftDeleteModel<
            T,
            QueryHelpers,
            TInstanceMethods,
            TVirtuals,
            THydratedDocumentType,
            TSchema
        > {
        /*
          @param {Object} params
          -query {Object} The find query.
          -limit {Number} The page size. Must be between 1 and `config.MAX_LIMIT`.
          -fields {Object} Fields to query in the Mongo object format, e.g. {_id: 1, timestamp :1}.
              The default is to query all fields.
          -paginatedField {String} The field name to query the range for. The field must be:
              1. Orderable. We must sort by this value. If duplicate values for paginatedField field
                  exist, the results will be secondarily ordered by the _id.
              2. Indexed. For large collections, this should be indexed for query performance.
              3. Immutable. If the value changes between paged queries, it could appear twice.
              4. Consistent. All values (except undefined and null values) must be of the same type.
              The default is to use the Mongo built-in '_id' field, which satisfies the above criteria.
              The only reason to NOT use the Mongo _id field is if you chose to implement your own ids.
          -sortAscending {Boolean} True to sort using paginatedField ascending (default is false - descending).
          -sortCaseInsensitive {boolean} Whether to ignore case when sorting, in which case `paginatedField`
              must be a string property.
          -next {String} The value to start querying the page.
          -previous {String} The value to start querying previous page.
      */
        paginate(param: {
            query?: FilterQuery<T>;
            limit?: number;
            fields?: Record<ModelKeys<T>, 0 | 1>;
            paginatedField?: ModelKeys<T>;
            sortAscending?: boolean;
            sortCaseInsensitive?: boolean;
            next?: string;
            previous?: string;
        }): Promise<PaginateResult<T>>;
    }
}