【问题标题】:How to extend mongoose Query class with Typescript?如何使用 Typescript 扩展猫鼬查询类?
【发布时间】:2021-07-01 13:37:59
【问题描述】:

我正在尝试使用 Mongoose、Redis 和 Typescript 实现缓存。我的cache.ts 文件:

import mongoose, { model, Query } from "mongoose";
import redis from "redis";
//import { CacheOptions } from "../../types/mongoose";
type CacheOptions = { key?: string };
const client = redis.createClient();

const getCache = function (
    hashKey: string,
    key: string
): Promise<string | null> {
    return new Promise((res, rej) => {
        client.hget(hashKey, key, (err, val) => {
            if (err) rej(err);
            else res(val);
        });
    });
};

const exec = mongoose.Query.prototype.exec;

mongoose.Query.prototype.cache = function (options: CacheOptions = {}) {
    this.useCache = true;
    this.hashKey = JSON.stringify(options.key || "");

    return this; //make cache() chainable
};

mongoose.Query.prototype.exec = async function () {
    if (!this.useCache) {
        //NO CACHE
        return exec.apply(this);
    }
    const key = JSON.stringify({
        ...this.getQuery(),
        collection: this.model.collection.name,
    });

    const cacheValue = await getCache(this.hashKey, key);

    if (cacheValue) {
        console.log("DATA FROM CACHE");
        const doc = JSON.parse(cacheValue);

        //convert plain object to mongoose object
        return Array.isArray(doc)
            ? doc.map((d) => new this.model(d))
            : new this.model(doc);
    }

    const result = await exec.apply(this);

    client.hset(this.hashKey, key, JSON.stringify(result));
    return result;
};

/**
 *
 * @param hashKey hashkey to remove
 */
const clearHash = (hashKey: string) => {
    client.del(JSON.stringify(hashKey));
};

export { clearHash };

这是我在 types 文件夹下的类型声明文件:mongoose.d.ts

declare module "mongoose" {
    export interface Query<
        ResultType,
        DocType extends Document,
        THelpers = {}
    > {
        cache(): Query<T>;
        useCache: boolean;
        hashKey: string;
        model: Model<T>;
    }
}

VsCode IntelliSense 不会给出任何警告或错误。当我运行代码时,出现以下错误:

    TSError: ⨯ Unable to compile TypeScript:
src/services/product/product.controller.ts:92:67 - error TS2551: Property 'cache' does not exist on type 'Query<IProduct | null, IProduct, {}>'. Did you mean 'catch'?

92  const foundProduct = await Product.findOne({ slug }, { __v: 0 }).cache();

我不确定我是否正确定义了类型,但 TypeScript 似乎没有看到我的声明或其他内容。如果您有任何建议,我将不胜感激。

【问题讨论】:

    标签: node.js typescript mongoose caching redis


    【解决方案1】:

    另一种选择是您可以通过添加 cache: any 来覆盖 index.d.ts 中的 Query 类

    【讨论】:

      【解决方案2】:

      这是我解决此问题的方法。在同一个 cache.ts 文件中执行此操作,

      declare module 'mongoose' {
          interface DocumentQuery<
              T,
              DocType extends import('mongoose').Document,
              QueryHelpers = {}
          > {
              mongooseCollection: {
                  name: any;
              };
              cache(): DocumentQuery<T[], Document> & QueryHelpers;
              useCache: boolean;
              hashKey: string;
          }
      
          interface Query<ResultType, DocType, THelpers = {}, RawDocType = DocType>
              extends DocumentQuery<any, any> {}
      }
          
      

      那么,

      mongoose.Query.prototype.cache = function (options: Options = {}) {
          this.__cache = true;
          this.__hashKey = JSON.stringify(options.key || '');
      
          // To make it chain-able with the queries
          // Ex: Blog
          // .find()
          // .cache()
          // .limit(10)
          return this;
      };
      

      因为我不确定DocumentQuery&lt;any, any&gt; {} 部分是否完全正确,所以我没有在单独的mongoose.d.ts 文件上创建它。 但是这段代码肯定会起作用。

      【讨论】:

        猜你喜欢
        • 2019-10-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-02-03
        • 2017-07-20
        • 1970-01-01
        • 2020-06-02
        • 2019-09-29
        相关资源
        最近更新 更多