You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用idb包编写通用的按索引获取记录函数(结合const as const避免硬编码)

如何使用idb包编写通用的按索引获取记录函数(结合const as const避免硬编码)

嘿,你已经用const object as const来规避硬编码字符串了,这步真的很明智!既保证了代码的可维护性,又能让TypeScript帮我们做类型检查。接下来我就带你一步步封装一个通用的按索引获取idb记录的函数,彻底和硬编码说拜拜。

首先,先把你给出的代码补全并梳理清楚,确保我们的常量和数据库Schema完全对应:

import { Injectable } from '@angular/core';
import { openDB, DBSchema, IDBPDatabase, IDBKeyRange } from 'idb';

// 用as const把字符串锁定为字面量类型,彻底杜绝硬编码
const ObjectStoreName = {
  SummaryData: 'SummaryData',
  TestData: 'TestData',
} as const;

const ObjectStoreIndex = {
  ByTimestamp: 'ByTimestamp',
  BySizeAndName: 'BySizeAndName',
} as const;

// 定义SummaryData对应的数据结构
interface SummaryFileCache {
  key: string;
  timestamp: number;
  size: number;
  name: string;
}

// 定义数据库完整Schema,关联对象仓库、数据结构与索引
interface MyDBSchema extends DBSchema {
  [ObjectStoreName.SummaryData]: {
    key: string;
    value: SummaryFileCache;
    indexes: {
      [ObjectStoreIndex.ByTimestamp]: number; // 单字段索引对应类型
      [ObjectStoreIndex.BySizeAndName]: [number, string]; // 复合索引对应类型
    };
  };
  [ObjectStoreName.TestData]: {
    key: string;
    value: { id: string; category: string; count: number };
    indexes: {
      [ObjectStoreIndex.ByTimestamp]: number;
    };
  };
}

接下来我们在Angular服务里封装数据库操作,核心就是那个通用的按索引查询函数:

@Injectable({ providedIn: 'root' })
export class DbService {
  private dbPromise: Promise<IDBPDatabase<MyDBSchema>>;

  constructor() {
    // 初始化数据库,创建对象仓库与索引
    this.dbPromise = openDB<MyDBSchema>('MyDatabase', 1, {
      upgrade(db) {
        // 创建SummaryData仓库及其索引
        if (!db.objectStoreNames.contains(ObjectStoreName.SummaryData)) {
          const summaryStore = db.createObjectStore(ObjectStoreName.SummaryData, { keyPath: 'key' });
          summaryStore.createIndex(ObjectStoreIndex.ByTimestamp, 'timestamp');
          summaryStore.createIndex(ObjectStoreIndex.BySizeAndName, ['size', 'name']);
        }
        // 创建TestData仓库及其索引
        if (!db.objectStoreNames.contains(ObjectStoreName.TestData)) {
          const testStore = db.createObjectStore(ObjectStoreName.TestData, { keyPath: 'id' });
          testStore.createIndex(ObjectStoreIndex.ByTimestamp, 'timestamp');
        }
      },
    });
  }

  /**
   * 通用按索引获取记录的函数
   * @param storeName 目标对象仓库(只能传预定义的ObjectStoreName值)
   * @param indexName 目标索引(只能传对应仓库存在的索引,来自ObjectStoreIndex)
   * @param query 查询条件:可以是具体值,也可以是IDBKeyRange(比如范围查询)
   * @param count 传true返回匹配数量,默认false返回所有匹配记录
   */
  async getRecordsByIndex<StoreName extends keyof MyDBSchema>(
    storeName: StoreName,
    indexName: keyof MyDBSchema[StoreName]['indexes'],
    query: IDBKeyRange | IDBValidKey,
    count = false
  ): Promise<Array<MyDBSchema[StoreName]['value']> | number> {
    const db = await this.dbPromise;
    const tx = db.transaction(storeName, 'readonly');
    const store = tx.objectStore(storeName);
    // 这里的as string是适配idb底层类型要求,我们已经通过泛型确保了indexName的合法性
    const index = store.index(indexName as string);

    if (count) {
      return index.count(query);
    }

    return index.getAll(query);
  }
}

现在来看看怎么用这个函数,完全不用写任何硬编码字符串,TypeScript还会自动帮我们做类型提示:

// 示例1:获取SummaryData中2024年1月1日之后的所有记录
async getRecentSummaryRecords() {
  const startTimestamp = new Date('2024-01-01').getTime();
  // 用IDBKeyRange实现范围查询
  const timeRange = IDBKeyRange.lowerBound(startTimestamp);
  // 只能传预定义的常量,写错会直接在编译阶段报错
  const records = await this.dbService.getRecordsByIndex(
    ObjectStoreName.SummaryData,
    ObjectStoreIndex.ByTimestamp,
    timeRange
  );
  console.log('近期汇总记录:', records);
}

// 示例2:获取TestData中时间戳等于指定值的记录数量
async getTestRecordCount(timestamp: number) {
  const count = await this.dbService.getRecordsByIndex(
    ObjectStoreName.TestData,
    ObjectStoreIndex.ByTimestamp,
    timestamp,
    true
  );
  console.log(`匹配的测试记录数:${count}`);
}

最后说下这个方案的核心优势:

  • 彻底告别硬编码:所有仓库名和索引名都来自预定义常量,再也不会出现拼写错误或者后续修改名称时漏改的情况;
  • 类型安全拉满:TypeScript会根据你传入的仓库名自动推断返回数据类型,传错索引名会直接编译报错;
  • 高度复用:这个通用函数能处理所有仓库的索引查询需求,不用为每个仓库写重复代码。

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.08 13:34:38