@cloudcome/utils-uni 1.46.0 → 1.48.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -66,13 +66,25 @@ export type UseCloudMethodOptions<I extends AnyArray, O> = Omit<UseRequestOption
66
66
  /**
67
67
  * 是否显示加载状态
68
68
  * @default false
69
+ * @description 支持布尔值或函数类型。当为函数时,接收请求参数并返回布尔值决定是否显示 loading。
70
+ * @example
71
+ * // 布尔值
72
+ * showLoading: true
73
+ * // 函数:根据参数决定是否显示
74
+ * showLoading: (userId) => userId !== 'anonymous'
69
75
  */
70
- showLoading?: boolean;
76
+ showLoading?: boolean | ((...inputs: I) => boolean);
71
77
  /**
72
78
  * 是否显示错误信息
73
79
  * @default false
80
+ * @description 支持布尔值或函数类型。当为函数时,接收请求参数并返回布尔值决定是否显示错误提示。
81
+ * @example
82
+ * // 布尔值
83
+ * showError: true
84
+ * // 函数:根据错误码决定是否显示
85
+ * showError: (err) => err.errCode !== 404
74
86
  */
75
- showError?: boolean;
87
+ showError?: boolean | ((...inputs: I) => boolean);
76
88
  };
77
89
  /**
78
90
  * 用于调用云对象方法的hook函数类型定义
package/dist/client.cjs CHANGED
@@ -372,7 +372,7 @@ function importCloudObject(objectName, importOptions) {
372
372
  }, {
373
373
  ...options,
374
374
  async onBefore(...inputs) {
375
- if (options?.showLoading) onShowLoading();
375
+ if (typeof options?.showLoading === "function" ? options.showLoading(...inputs) : options?.showLoading) onShowLoading();
376
376
  await importOptions?.onBefore?.();
377
377
  await options?.onBefore?.(...inputs);
378
378
  },
@@ -383,7 +383,7 @@ function importCloudObject(objectName, importOptions) {
383
383
  async onError(err, ...inputs) {
384
384
  await importOptions?.onError?.(err);
385
385
  await options?.onError?.(err, ...inputs);
386
- if (options?.showError) setTimeout(() => {
386
+ if (typeof options?.showError === "function" ? options.showError(...inputs) : options?.showError) setTimeout(() => {
387
387
  onShowError(err);
388
388
  });
389
389
  },
@@ -1 +1 @@
1
- {"version":3,"file":"client.cjs","names":[],"sources":["../src/client/message.ts","../src/client/app.ts","../src/client/async.ts","../src/client/page.ts","../src/client/request.ts","../src/client/ui.ts"],"sourcesContent":["import { promiseDelay } from '@cloudcome/utils-core/promise';\nimport { isString } from '@cloudcome/utils-core/type';\n\n/**\n * 显示 confirm 提示\n * @param text 提示文本\n * @param options 其他选项\n * @returns 提示完成后的 Promise\n */\nexport function uniConfirm(\n text: string,\n options?: Omit<UniNamespace.ShowModalOptions, 'showCancel' | 'success' | 'content' | 'editable'>,\n) {\n const cancelText = options?.cancelText || '取消';\n const confirmText = options?.confirmText || '确认';\n\n if (cancelText.length > 4) console.warn('微信小程序内不支持 cancelText 长度超过 4 个字符');\n if (confirmText.length > 4) console.warn('微信小程序内不支持 confirmText 长度超过 4 个字符');\n\n return new Promise<boolean>((resolve) => {\n // 避免和 hideLoading 同时出现影响弹窗\n setTimeout(() => {\n uni.showModal({\n title: '请确认',\n content: text,\n showCancel: true,\n confirmText,\n cancelText,\n ...options,\n success(result) {\n resolve(result.confirm);\n },\n });\n });\n });\n}\n\n/**\n * 显示 prompt 提示\n * @param text 提示文本\n * @param options 其他选项\n * @returns 提示完成后的 Promise\n */\nexport function uniPrompt(\n text: string,\n options?: Omit<UniNamespace.ShowModalOptions, 'showCancel' | 'success' | 'content' | 'editable'>,\n) {\n const cancelText = options?.cancelText || '取消';\n const confirmText = options?.confirmText || '确认';\n\n if (cancelText.length > 4) console.warn('微信小程序内不支持 cancelText 长度超过 4 个字符');\n if (confirmText.length > 4) console.warn('微信小程序内不支持 confirmText 长度超过 4 个字符');\n\n return new Promise<string>((resolve) => {\n // 避免和 hideLoading 同时出现影响弹窗\n setTimeout(() => {\n uni.showModal({\n title: '请输入',\n content: '',\n placeholderText: text,\n showCancel: true,\n confirmText,\n cancelText,\n editable: true,\n ...options,\n success(result) {\n resolve(result.content || '');\n },\n });\n });\n });\n}\n\n/**\n * 显示 alert 提示\n * @param text 提示文本\n * @param options 其他选项\n * @returns 提示完成后的 Promise\n */\nexport function uniAlert(\n text: string,\n options?: Omit<UniNamespace.ShowModalOptions, 'cancelText' | 'showCancel' | 'success' | 'content'>,\n) {\n const confirmText = options?.confirmText || '好';\n\n if (confirmText.length > 4) console.warn('微信小程序内不支持 confirmText 长度超过 4 个字符');\n\n return new Promise<void>((resolve) => {\n // 避免和 hideLoading 同时出现影响弹窗\n setTimeout(() => {\n uni.showModal({\n title: '提示',\n confirmText,\n cancelText: '',\n ...options,\n content: text,\n showCancel: false,\n success() {\n resolve();\n },\n });\n });\n });\n}\n\n/**\n * 显示 toast 提示\n * @param text 提示文本\n * @param icon 图标\n * @param options 其他选项\n * @returns 提示完成后的 Promise\n */\nexport function uniToast(text: string, icon?: UniNamespace.ShowToastOptions['icon']): Promise<void>;\nexport function uniToast(text: string, options?: UniNamespace.ShowToastOptions): Promise<void>;\nexport function uniToast(\n text: string,\n iconOrOptions?: UniNamespace.ShowToastOptions['icon'] | UniNamespace.ShowToastOptions,\n): Promise<void> {\n const options = {} as UniNamespace.ShowToastOptions;\n\n if (isString(iconOrOptions)) {\n options.icon = iconOrOptions;\n } else {\n Object.assign(options, iconOrOptions);\n }\n\n return new Promise<void>((resolve) => {\n // 避免和 hideLoading 同时出现影响弹窗\n setTimeout(async () => {\n uni.showToast({\n title: text,\n duration: 2900,\n icon: options.icon || 'none',\n mask: false,\n });\n promiseDelay(3000).then(resolve);\n });\n });\n}\n\n/**\n * 显示 loading 提示\n * @param title 提示文本\n */\nexport function uniLoading(title = '') {\n uni.showLoading({\n title,\n mask: true,\n });\n}\n","import type { HookListenerWithDispose } from '@cloudcome/utils-vue/component';\nimport { _runLifeHook } from '@cloudcome/utils-vue/shared';\nimport { onHide, onShow } from '@dcloudio/uni-app';\nimport { ref } from 'vue';\nimport { uniConfirm } from './message';\n\n/**\n * 应用显示状态生命周期钩子函数\n *\n * 该函数用于监听应用从后台进入前台的生命周期事件。\n * 当应用从后台切换到前台时触发 onShow 回调,\n * 当应用从前台切换到后台时触发 onHide 回调。\n *\n * @param appShow - 应用显示状态变化时的回调函数,可以返回一个清理函数\n *\n * @example\n * // 基本用法\n * useAppShow(() => {\n * console.log('应用进入前台');\n *\n * // 可选:返回一个清理函数,在应用进入后台时执行\n * return () => {\n * console.log('应用进入后台');\n * };\n * });\n *\n * @example\n * // 带有异步操作的用法\n * useAppShow(async () => {\n * // 应用进入前台时刷新数据\n * await refreshUserData();\n *\n * // 返回清理函数\n * return () => {\n * // 应用进入后台时保存数据\n * saveUserData();\n * };\n * });\n */\nexport function useAppShow(appShow: HookListenerWithDispose) {\n _runLifeHook(onShow, onHide, appShow);\n}\n\n/**\n * 订阅模板消息\n * @param templateId 模板消息 ID 或 ID 列表\n * @returns Promise<boolean>\n */\nexport async function uniSubscribeNotice(templateId: string | string[]) {\n if (!uni.requestSubscribeMessage) return false;\n\n return new Promise<boolean>((resolve) => {\n const tmplIds = Array.isArray(templateId) ? templateId : [templateId];\n uni.requestSubscribeMessage({\n tmplIds,\n success(_res) {\n // 'accept'表示用户同意订阅该条id对应的模板消息,\n // 'reject'表示用户拒绝订阅该条id对应的模板消息,\n // 'ban'表示已被后台封禁,\n // 'filter'表示该模板因为模板标题同名被后台过滤\n const res = _res as unknown as Record<string, 'accept' | 'reject' | 'ban' | 'filter'>;\n let subscribed = false;\n\n for (const templateId of tmplIds) {\n if (res[templateId] === 'accept') {\n subscribed = true;\n break;\n }\n }\n\n resolve(subscribed);\n },\n fail() {\n resolve(false);\n },\n });\n });\n}\n\n/**\n * 监听应用更新状态\n */\nexport function useAppUpdate() {\n const hasUpdate = ref(false);\n const updateReady = ref(false);\n const updateManager = uni.getUpdateManager?.();\n\n updateManager?.onCheckForUpdate((res) => {\n // 请求完新版本信息的回调\n hasUpdate.value = Boolean(res.hasUpdate);\n });\n\n updateManager?.onUpdateReady(async () => {\n updateReady.value = true;\n\n const confirm = await uniConfirm('新版本已经准备好,是否重启应用?', {\n title: '更新提示',\n confirmText: '重启',\n });\n if (!confirm) return;\n\n updateManager.applyUpdate();\n });\n\n updateManager?.onUpdateFailed(() => {\n // 新的版本下载失败\n });\n\n return { hasUpdate, updateReady };\n}\n","import { errorAssign } from '@cloudcome/utils-core/error';\n\nexport type UniFailErr = UniNamespace.GeneralCallbackResult & {\n errCode?: number;\n errno?: number;\n};\n\nexport type UniPromiseError = Error & {\n errCode: number;\n errNo: number;\n};\n\n/**\n * 包装 uni 异步函数,返回 Promise 并处理错误\n * @param promise uni 异步函数的 Promise\n * @returns Promise<T>\n * @throws UniPromiseError\n */\nexport async function uniPromise<T>(promise: Promise<T>): Promise<T> {\n try {\n const result = await promise;\n return result;\n } catch (err) {\n const res = err as unknown as UniFailErr;\n throw errorAssign(new Error(res.errMsg || '未知错误'), {\n errCode: res.errCode || -1,\n errNo: res.errno || -1,\n });\n }\n}\n\n/**\n * 包装 uni 异步函数,返回 Promise 并处理错误\n * @param runner uni 异步函数的回调\n * @returns Promise<T>\n * @throws UniPromiseError\n */\nexport async function uniCallback<T>(\n runner: (options: { success: (res: T) => void; fail: (err: UniFailErr) => void }) => unknown,\n) {\n return new Promise<T>((resolve, reject) => {\n runner({\n success(res) {\n resolve(res);\n },\n fail(err) {\n reject(\n errorAssign(new Error(err.errMsg || '未知错误'), {\n errCode: err.errCode || -1,\n errNo: err.errno || -1,\n }),\n );\n },\n });\n });\n}\n","import type { AnyObject } from '@cloudcome/utils-core/types';\nimport type { HookListenerWithDispose } from '@cloudcome/utils-vue/component';\nimport { _runLifeHook } from '@cloudcome/utils-vue/shared';\nimport { onLoad, onPageHide, onPageShow, onUnload } from '@dcloudio/uni-app';\nimport { type Reactive, reactive } from 'vue';\n\n/**\n * 用于获取页面参数的 hook 函数\n * @template T - 页面参数对象的类型,继承自 AnyObject\n * @param {function} [onPageLoad] - 页面加载时的回调函数\n * @param {T} onLoad.query - 页面参数对象\n * @returns {T} 响应式的页面参数对象\n * @example\n * // 基本用法\n * const query = usePageQuery();\n *\n * // 带回调的用法\n * const query = usePageQuery((query) => {\n * console.log('页面参数:', query);\n * });\n *\n * // 指定参数类型\n * interface PageParams {\n * id: string;\n * name?: string;\n * }\n * const query = usePageQuery<PageParams>();\n */\nexport function usePageQuery<T extends AnyObject>(onPageLoad?: (query: Reactive<T>) => void) {\n const query = reactive<T>({} as T);\n\n onLoad((_query) => {\n Object.assign(query, _query);\n onPageLoad?.(query);\n });\n\n return query;\n}\n\n/**\n * 用于处理页面加载生命周期的 hook 函数\n *\n * 该函数会在页面加载时执行传入的回调函数,并在页面卸载时执行清理操作(如果提供了清理函数)。\n * 它是 uni-app 中 onLoad 和 onUnload 生命周期的封装。\n *\n * @param {HookListenerWithDispose} load - 页面加载时的回调函数,可以返回一个清理函数\n *\n * @example\n * // 基本用法\n * usePageLoad(() => {\n * console.log('页面已加载');\n * });\n *\n * @example\n * // 带清理函数的用法\n * usePageLoad(() => {\n * console.log('页面已加载');\n *\n * // 返回一个清理函数,在页面卸载时执行\n * return () => {\n * console.log('页面将要卸载');\n * };\n * });\n *\n * @example\n * // 异步用法\n * usePageLoad(async () => {\n * const data = await fetchData();\n * console.log('获取到数据:', data);\n *\n * return () => {\n * console.log('清理资源');\n * };\n * });\n */\nexport function usePageLoad(load: HookListenerWithDispose) {\n _runLifeHook(onLoad, onUnload, load);\n}\n\n/**\n * 用于处理页面显示生命周期的 hook 函数\n *\n * 该函数会在页面显示时执行传入的回调函数,并在页面隐藏时执行清理操作(如果提供了清理函数)。\n * 它是 uni-app 中 onPageShow 和 onPageHide 生命周期的封装。\n *\n * @param {HookListenerWithDispose} pageShow - 页面显示时的回调函数,可以返回一个清理函数\n *\n * @example\n * // 基本用法\n * usePageShow(() => {\n * console.log('页面已显示');\n * });\n *\n * @example\n * // 带清理函数的用法\n * usePageShow(() => {\n * console.log('页面已显示');\n *\n * // 返回一个清理函数,在页面隐藏时执行\n * return () => {\n * console.log('页面将要隐藏');\n * };\n * });\n */\nexport function usePageShow(pageShow: HookListenerWithDispose) {\n _runLifeHook(onPageShow, onPageHide, pageShow);\n}\n","import type { AnyArray, AnyFunction } from '@cloudcome/utils-core/types';\nimport { type UseRequestOptions, type UseRequestOutput, useRequest } from '@cloudcome/utils-vue/request';\nimport type { CloudMethodOutput, UniError } from '@/cloud';\nimport type { ClientDatabaseOutput } from '@/database';\nimport { parseCloudMethodOutput } from '../_helpers';\nimport { uniLoading, uniToast } from './message';\n\nexport type CreateUseCloudObjectOptions = {\n /**\n * 模拟云对象,用于单元测试\n * @private\n */\n // biome-ignore lint/suspicious/noExplicitAny: 单测使用 any\n _mockServer?: any;\n\n /**\n * 回退错误信息\n * @default '请求失败'\n */\n fallbackErrorMessage?: string;\n\n /**\n * 请求开始前的回调函数\n */\n onBefore?: () => unknown;\n\n /**\n * 请求成功后的回调函数\n */\n onSuccess?: () => unknown;\n\n /**\n * 请求失败时的回调函数\n * @param err 错误信息\n */\n onError?: (err: UniError) => unknown;\n\n /**\n * 请求完成后的回调函数(无论成功或失败都会执行)\n */\n onAfter?: () => unknown;\n\n /**\n * 显示加载状态的回调函数,当配置了 showLoading 为 true 时会调用\n */\n onShowLoading?: () => unknown;\n\n /**\n * 隐藏加载状态的回调函数,当配置了 showLoading 为 true 时会调用\n */\n onHideLoading?: () => unknown;\n\n /**\n * 显示错误信息的回调函数,当配置了 showError 为 true 时会调用\n * @param err 错误信息\n */\n onShowError?: (err: UniError) => unknown;\n};\n\n/**\n * 云对象请求函数类型定义\n * @template F 云对象方法函数类型\n * @param input 云对象方法的参数数组\n * @returns 返回云对象方法执行结果的Promise\n */\nexport type CloudObjectRequest = <F extends AnyFunction>(\n ...input: Parameters<F>\n) => Promise<CloudMethodOutput<ReturnType<F>>>;\n\n/**\n * 用于调用云对象方法的配置选项类型定义\n * @template I 输入参数类型数组\n * @template O 输出结果类型\n */\nexport type UseCloudMethodOptions<I extends AnyArray, O> = Omit<UseRequestOptions<I, O>, 'onError'> & {\n /**\n * 请求发生错误时的回调函数\n * @param err 错误信息\n * @param inputs 请求输入参数\n */\n onError?: (err: UniError, ...inputs: I) => unknown;\n\n /**\n * 是否显示加载状态\n * @default false\n */\n showLoading?: boolean;\n\n /**\n * 是否显示错误信息\n * @default false\n */\n showError?: boolean;\n};\n\n/**\n * 用于调用云对象方法的hook函数类型定义\n * @template I 输入参数类型数组\n * @template O 输出结果类型\n */\nexport type UseCloudMethod<Api extends Record<string, AnyFunction>> = {\n <K extends keyof Api, I extends AnyArray, O>(\n method: K,\n caller: (request: Api[K], ...inputs: I) => Promise<CloudMethodOutput<O>>,\n options?: UseCloudMethodOptions<I, O>,\n ): UseRequestOutput<I, O>;\n};\n\n/**\n * 导入云对象并创建一个用于调用云对象的hook\n * @param objectName 云对象名称\n * @param importOptions 配置选项,包含模拟服务器、回退错误信息等\n * @returns 返回一个可用于调用云对象方法的hook函数\n */\nexport function importCloudObject<Api extends Record<string, AnyFunction>>(\n objectName: string,\n importOptions?: CreateUseCloudObjectOptions,\n) {\n const fallbackErrorMessage = importOptions?.fallbackErrorMessage || '请求失败';\n const server =\n importOptions?._mockServer ||\n uniCloud.importObject(objectName, {\n customUI: true,\n });\n const onShowLoading = importOptions?.onShowLoading || (() => uniLoading());\n const onHideLoading = importOptions?.onHideLoading || (() => uni.hideLoading());\n const onShowError = importOptions?.onShowError || ((err) => uniToast(err.message));\n\n /**\n * 用于调用云对象方法的hook函数\n * @template I 输入参数类型\n * @template O 输出结果类型\n * @param method 云对象方法名\n * @param caller 调用云对象的函数\n * @param options 配置选项,包含请求相关的配置\n * @returns 返回一个请求hook,用于处理云对象调用\n */\n const useCloudMethod: UseCloudMethod<Api> = (method, caller, options) => {\n // 使用请求hook处理云对象调用\n return useRequest(\n async (...inputs) => {\n const request = server[method];\n const output = await caller(request, ...inputs);\n return parseCloudMethodOutput(output, fallbackErrorMessage);\n },\n {\n ...options,\n async onBefore(...inputs) {\n if (options?.showLoading) onShowLoading();\n\n await importOptions?.onBefore?.();\n await options?.onBefore?.(...inputs);\n },\n async onSuccess(data, ...inputs) {\n await importOptions?.onSuccess?.();\n await options?.onSuccess?.(data, ...inputs);\n },\n async onError(err, ...inputs) {\n await importOptions?.onError?.(err as UniError);\n await options?.onError?.(err as UniError, ...inputs);\n\n if (options?.showError) {\n // 加延迟是尽量保证在 loading 隐藏后再显示错误信息\n setTimeout(() => {\n onShowError(err as UniError);\n });\n }\n },\n async onAfter(...inputs) {\n if (options?.showLoading) onHideLoading();\n\n await importOptions?.onAfter?.();\n await options?.onAfter?.(...inputs);\n },\n },\n );\n };\n\n return useCloudMethod;\n}\n\nexport type UseDatabaseOptions<I extends AnyArray, O> = UseRequestOptions<I, O> & {\n /**\n * 模拟数据库,用于单元测试\n */\n // biome-ignore lint/suspicious/noExplicitAny: 单测使用 any\n _mockDatabase?: any;\n};\n\n/**\n * 创建一个用于调用云数据库的hook\n * @param caller 调用云数据库的函数,接收数据库实例和输入参数,返回Promise\n * @param options 配置选项\n * @returns 返回一个请求hook,用于处理云数据库调用\n */\nexport function useDatabase<I extends AnyArray, O>(\n caller: (db: UniCloud.Database, ...inputs: I) => Promise<ClientDatabaseOutput<O>>,\n options?: UseDatabaseOptions<I, O>,\n): UseRequestOutput<I, O>;\nexport function useDatabase<I extends AnyArray, O>(\n caller: (db: UniCloud.Database, ...inputs: I) => Promise<ClientDatabaseOutput<O>>,\n options?: UseDatabaseOptions<I, O>,\n): UseRequestOutput<I, O> {\n // 获取数据库实例,优先使用模拟数据库(用于测试),否则使用uniCloud数据库\n const db = options?._mockDatabase || uniCloud.database();\n return useRequest(async (...inputs: I) => {\n const { result } = await caller(db, ...inputs);\n if (!result.errCode) return result;\n throw new Error(result.errMsg || '请求失败');\n }, options);\n}\n","import type { ComponentInternalInstance } from 'vue';\n\nexport type Rect = {\n /**\n * 元素距离屏幕的左坐标,单位:px\n */\n left: number;\n /**\n * 元素距离屏幕的上坐标,单位:px\n */\n top: number;\n /**\n * 元素距离屏幕的宽度,单位:px\n */\n width: number;\n /**\n * 元素距离屏幕的高度,单位:px\n */\n height: number;\n};\n\n/**\n * 查询元素距离屏幕的矩形信息\n * @param instance 组件实例\n * @param selector 选择器\n * @returns 元素距离屏幕的矩形信息\n */\nexport async function querySelectorRects(instance: ComponentInternalInstance, selector: string) {\n return new Promise<Rect[]>((resolve) => {\n uni\n .createSelectorQuery()\n .in(instance.proxy)\n .selectAll(selector)\n .boundingClientRect((_rects) => {\n const rects = _rects as UniApp.NodeInfo[];\n resolve(\n rects.map((rect) => ({\n left: rect.left || 0,\n top: rect.top || 0,\n width: rect.width || 0,\n height: rect.height || 0,\n })),\n );\n })\n .exec();\n });\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"client.cjs","names":[],"sources":["../src/client/message.ts","../src/client/app.ts","../src/client/async.ts","../src/client/page.ts","../src/client/request.ts","../src/client/ui.ts"],"sourcesContent":["import { promiseDelay } from '@cloudcome/utils-core/promise';\nimport { isString } from '@cloudcome/utils-core/type';\n\n/**\n * 显示 confirm 提示\n * @param text 提示文本\n * @param options 其他选项\n * @returns 提示完成后的 Promise\n */\nexport function uniConfirm(\n text: string,\n options?: Omit<UniNamespace.ShowModalOptions, 'showCancel' | 'success' | 'content' | 'editable'>,\n) {\n const cancelText = options?.cancelText || '取消';\n const confirmText = options?.confirmText || '确认';\n\n if (cancelText.length > 4) console.warn('微信小程序内不支持 cancelText 长度超过 4 个字符');\n if (confirmText.length > 4) console.warn('微信小程序内不支持 confirmText 长度超过 4 个字符');\n\n return new Promise<boolean>((resolve) => {\n // 避免和 hideLoading 同时出现影响弹窗\n setTimeout(() => {\n uni.showModal({\n title: '请确认',\n content: text,\n showCancel: true,\n confirmText,\n cancelText,\n ...options,\n success(result) {\n resolve(result.confirm);\n },\n });\n });\n });\n}\n\n/**\n * 显示 prompt 提示\n * @param text 提示文本\n * @param options 其他选项\n * @returns 提示完成后的 Promise\n */\nexport function uniPrompt(\n text: string,\n options?: Omit<UniNamespace.ShowModalOptions, 'showCancel' | 'success' | 'content' | 'editable'>,\n) {\n const cancelText = options?.cancelText || '取消';\n const confirmText = options?.confirmText || '确认';\n\n if (cancelText.length > 4) console.warn('微信小程序内不支持 cancelText 长度超过 4 个字符');\n if (confirmText.length > 4) console.warn('微信小程序内不支持 confirmText 长度超过 4 个字符');\n\n return new Promise<string>((resolve) => {\n // 避免和 hideLoading 同时出现影响弹窗\n setTimeout(() => {\n uni.showModal({\n title: '请输入',\n content: '',\n placeholderText: text,\n showCancel: true,\n confirmText,\n cancelText,\n editable: true,\n ...options,\n success(result) {\n resolve(result.content || '');\n },\n });\n });\n });\n}\n\n/**\n * 显示 alert 提示\n * @param text 提示文本\n * @param options 其他选项\n * @returns 提示完成后的 Promise\n */\nexport function uniAlert(\n text: string,\n options?: Omit<UniNamespace.ShowModalOptions, 'cancelText' | 'showCancel' | 'success' | 'content'>,\n) {\n const confirmText = options?.confirmText || '好';\n\n if (confirmText.length > 4) console.warn('微信小程序内不支持 confirmText 长度超过 4 个字符');\n\n return new Promise<void>((resolve) => {\n // 避免和 hideLoading 同时出现影响弹窗\n setTimeout(() => {\n uni.showModal({\n title: '提示',\n confirmText,\n cancelText: '',\n ...options,\n content: text,\n showCancel: false,\n success() {\n resolve();\n },\n });\n });\n });\n}\n\n/**\n * 显示 toast 提示\n * @param text 提示文本\n * @param icon 图标\n * @param options 其他选项\n * @returns 提示完成后的 Promise\n */\nexport function uniToast(text: string, icon?: UniNamespace.ShowToastOptions['icon']): Promise<void>;\nexport function uniToast(text: string, options?: UniNamespace.ShowToastOptions): Promise<void>;\nexport function uniToast(\n text: string,\n iconOrOptions?: UniNamespace.ShowToastOptions['icon'] | UniNamespace.ShowToastOptions,\n): Promise<void> {\n const options = {} as UniNamespace.ShowToastOptions;\n\n if (isString(iconOrOptions)) {\n options.icon = iconOrOptions;\n } else {\n Object.assign(options, iconOrOptions);\n }\n\n return new Promise<void>((resolve) => {\n // 避免和 hideLoading 同时出现影响弹窗\n setTimeout(async () => {\n uni.showToast({\n title: text,\n duration: 2900,\n icon: options.icon || 'none',\n mask: false,\n });\n promiseDelay(3000).then(resolve);\n });\n });\n}\n\n/**\n * 显示 loading 提示\n * @param title 提示文本\n */\nexport function uniLoading(title = '') {\n uni.showLoading({\n title,\n mask: true,\n });\n}\n","import type { HookListenerWithDispose } from '@cloudcome/utils-vue/component';\nimport { _runLifeHook } from '@cloudcome/utils-vue/shared';\nimport { onHide, onShow } from '@dcloudio/uni-app';\nimport { ref } from 'vue';\nimport { uniConfirm } from './message';\n\n/**\n * 应用显示状态生命周期钩子函数\n *\n * 该函数用于监听应用从后台进入前台的生命周期事件。\n * 当应用从后台切换到前台时触发 onShow 回调,\n * 当应用从前台切换到后台时触发 onHide 回调。\n *\n * @param appShow - 应用显示状态变化时的回调函数,可以返回一个清理函数\n *\n * @example\n * // 基本用法\n * useAppShow(() => {\n * console.log('应用进入前台');\n *\n * // 可选:返回一个清理函数,在应用进入后台时执行\n * return () => {\n * console.log('应用进入后台');\n * };\n * });\n *\n * @example\n * // 带有异步操作的用法\n * useAppShow(async () => {\n * // 应用进入前台时刷新数据\n * await refreshUserData();\n *\n * // 返回清理函数\n * return () => {\n * // 应用进入后台时保存数据\n * saveUserData();\n * };\n * });\n */\nexport function useAppShow(appShow: HookListenerWithDispose) {\n _runLifeHook(onShow, onHide, appShow);\n}\n\n/**\n * 订阅模板消息\n * @param templateId 模板消息 ID 或 ID 列表\n * @returns Promise<boolean>\n */\nexport async function uniSubscribeNotice(templateId: string | string[]) {\n if (!uni.requestSubscribeMessage) return false;\n\n return new Promise<boolean>((resolve) => {\n const tmplIds = Array.isArray(templateId) ? templateId : [templateId];\n uni.requestSubscribeMessage({\n tmplIds,\n success(_res) {\n // 'accept'表示用户同意订阅该条id对应的模板消息,\n // 'reject'表示用户拒绝订阅该条id对应的模板消息,\n // 'ban'表示已被后台封禁,\n // 'filter'表示该模板因为模板标题同名被后台过滤\n const res = _res as unknown as Record<string, 'accept' | 'reject' | 'ban' | 'filter'>;\n let subscribed = false;\n\n for (const templateId of tmplIds) {\n if (res[templateId] === 'accept') {\n subscribed = true;\n break;\n }\n }\n\n resolve(subscribed);\n },\n fail() {\n resolve(false);\n },\n });\n });\n}\n\n/**\n * 监听应用更新状态\n */\nexport function useAppUpdate() {\n const hasUpdate = ref(false);\n const updateReady = ref(false);\n const updateManager = uni.getUpdateManager?.();\n\n updateManager?.onCheckForUpdate((res) => {\n // 请求完新版本信息的回调\n hasUpdate.value = Boolean(res.hasUpdate);\n });\n\n updateManager?.onUpdateReady(async () => {\n updateReady.value = true;\n\n const confirm = await uniConfirm('新版本已经准备好,是否重启应用?', {\n title: '更新提示',\n confirmText: '重启',\n });\n if (!confirm) return;\n\n updateManager.applyUpdate();\n });\n\n updateManager?.onUpdateFailed(() => {\n // 新的版本下载失败\n });\n\n return { hasUpdate, updateReady };\n}\n","import { errorAssign } from '@cloudcome/utils-core/error';\n\nexport type UniFailErr = UniNamespace.GeneralCallbackResult & {\n errCode?: number;\n errno?: number;\n};\n\nexport type UniPromiseError = Error & {\n errCode: number;\n errNo: number;\n};\n\n/**\n * 包装 uni 异步函数,返回 Promise 并处理错误\n * @param promise uni 异步函数的 Promise\n * @returns Promise<T>\n * @throws UniPromiseError\n */\nexport async function uniPromise<T>(promise: Promise<T>): Promise<T> {\n try {\n const result = await promise;\n return result;\n } catch (err) {\n const res = err as unknown as UniFailErr;\n throw errorAssign(new Error(res.errMsg || '未知错误'), {\n errCode: res.errCode || -1,\n errNo: res.errno || -1,\n });\n }\n}\n\n/**\n * 包装 uni 异步函数,返回 Promise 并处理错误\n * @param runner uni 异步函数的回调\n * @returns Promise<T>\n * @throws UniPromiseError\n */\nexport async function uniCallback<T>(\n runner: (options: { success: (res: T) => void; fail: (err: UniFailErr) => void }) => unknown,\n) {\n return new Promise<T>((resolve, reject) => {\n runner({\n success(res) {\n resolve(res);\n },\n fail(err) {\n reject(\n errorAssign(new Error(err.errMsg || '未知错误'), {\n errCode: err.errCode || -1,\n errNo: err.errno || -1,\n }),\n );\n },\n });\n });\n}\n","import type { AnyObject } from '@cloudcome/utils-core/types';\nimport type { HookListenerWithDispose } from '@cloudcome/utils-vue/component';\nimport { _runLifeHook } from '@cloudcome/utils-vue/shared';\nimport { onLoad, onPageHide, onPageShow, onUnload } from '@dcloudio/uni-app';\nimport { type Reactive, reactive } from 'vue';\n\n/**\n * 用于获取页面参数的 hook 函数\n * @template T - 页面参数对象的类型,继承自 AnyObject\n * @param {function} [onPageLoad] - 页面加载时的回调函数\n * @param {T} onLoad.query - 页面参数对象\n * @returns {T} 响应式的页面参数对象\n * @example\n * // 基本用法\n * const query = usePageQuery();\n *\n * // 带回调的用法\n * const query = usePageQuery((query) => {\n * console.log('页面参数:', query);\n * });\n *\n * // 指定参数类型\n * interface PageParams {\n * id: string;\n * name?: string;\n * }\n * const query = usePageQuery<PageParams>();\n */\nexport function usePageQuery<T extends AnyObject>(onPageLoad?: (query: Reactive<T>) => void) {\n const query = reactive<T>({} as T);\n\n onLoad((_query) => {\n Object.assign(query, _query);\n onPageLoad?.(query);\n });\n\n return query;\n}\n\n/**\n * 用于处理页面加载生命周期的 hook 函数\n *\n * 该函数会在页面加载时执行传入的回调函数,并在页面卸载时执行清理操作(如果提供了清理函数)。\n * 它是 uni-app 中 onLoad 和 onUnload 生命周期的封装。\n *\n * @param {HookListenerWithDispose} load - 页面加载时的回调函数,可以返回一个清理函数\n *\n * @example\n * // 基本用法\n * usePageLoad(() => {\n * console.log('页面已加载');\n * });\n *\n * @example\n * // 带清理函数的用法\n * usePageLoad(() => {\n * console.log('页面已加载');\n *\n * // 返回一个清理函数,在页面卸载时执行\n * return () => {\n * console.log('页面将要卸载');\n * };\n * });\n *\n * @example\n * // 异步用法\n * usePageLoad(async () => {\n * const data = await fetchData();\n * console.log('获取到数据:', data);\n *\n * return () => {\n * console.log('清理资源');\n * };\n * });\n */\nexport function usePageLoad(load: HookListenerWithDispose) {\n _runLifeHook(onLoad, onUnload, load);\n}\n\n/**\n * 用于处理页面显示生命周期的 hook 函数\n *\n * 该函数会在页面显示时执行传入的回调函数,并在页面隐藏时执行清理操作(如果提供了清理函数)。\n * 它是 uni-app 中 onPageShow 和 onPageHide 生命周期的封装。\n *\n * @param {HookListenerWithDispose} pageShow - 页面显示时的回调函数,可以返回一个清理函数\n *\n * @example\n * // 基本用法\n * usePageShow(() => {\n * console.log('页面已显示');\n * });\n *\n * @example\n * // 带清理函数的用法\n * usePageShow(() => {\n * console.log('页面已显示');\n *\n * // 返回一个清理函数,在页面隐藏时执行\n * return () => {\n * console.log('页面将要隐藏');\n * };\n * });\n */\nexport function usePageShow(pageShow: HookListenerWithDispose) {\n _runLifeHook(onPageShow, onPageHide, pageShow);\n}\n","import type { AnyArray, AnyFunction } from '@cloudcome/utils-core/types';\nimport { type UseRequestOptions, type UseRequestOutput, useRequest } from '@cloudcome/utils-vue/request';\nimport type { CloudMethodOutput, UniError } from '@/cloud';\nimport type { ClientDatabaseOutput } from '@/database';\nimport { parseCloudMethodOutput } from '../_helpers';\nimport { uniLoading, uniToast } from './message';\n\nexport type CreateUseCloudObjectOptions = {\n /**\n * 模拟云对象,用于单元测试\n * @private\n */\n // biome-ignore lint/suspicious/noExplicitAny: 单测使用 any\n _mockServer?: any;\n\n /**\n * 回退错误信息\n * @default '请求失败'\n */\n fallbackErrorMessage?: string;\n\n /**\n * 请求开始前的回调函数\n */\n onBefore?: () => unknown;\n\n /**\n * 请求成功后的回调函数\n */\n onSuccess?: () => unknown;\n\n /**\n * 请求失败时的回调函数\n * @param err 错误信息\n */\n onError?: (err: UniError) => unknown;\n\n /**\n * 请求完成后的回调函数(无论成功或失败都会执行)\n */\n onAfter?: () => unknown;\n\n /**\n * 显示加载状态的回调函数,当配置了 showLoading 为 true 时会调用\n */\n onShowLoading?: () => unknown;\n\n /**\n * 隐藏加载状态的回调函数,当配置了 showLoading 为 true 时会调用\n */\n onHideLoading?: () => unknown;\n\n /**\n * 显示错误信息的回调函数,当配置了 showError 为 true 时会调用\n * @param err 错误信息\n */\n onShowError?: (err: UniError) => unknown;\n};\n\n/**\n * 云对象请求函数类型定义\n * @template F 云对象方法函数类型\n * @param input 云对象方法的参数数组\n * @returns 返回云对象方法执行结果的Promise\n */\nexport type CloudObjectRequest = <F extends AnyFunction>(\n ...input: Parameters<F>\n) => Promise<CloudMethodOutput<ReturnType<F>>>;\n\n/**\n * 用于调用云对象方法的配置选项类型定义\n * @template I 输入参数类型数组\n * @template O 输出结果类型\n */\nexport type UseCloudMethodOptions<I extends AnyArray, O> = Omit<UseRequestOptions<I, O>, 'onError'> & {\n /**\n * 请求发生错误时的回调函数\n * @param err 错误信息\n * @param inputs 请求输入参数\n */\n onError?: (err: UniError, ...inputs: I) => unknown;\n\n /**\n * 是否显示加载状态\n * @default false\n * @description 支持布尔值或函数类型。当为函数时,接收请求参数并返回布尔值决定是否显示 loading。\n * @example\n * // 布尔值\n * showLoading: true\n * // 函数:根据参数决定是否显示\n * showLoading: (userId) => userId !== 'anonymous'\n */\n showLoading?: boolean | ((...inputs: I) => boolean);\n\n /**\n * 是否显示错误信息\n * @default false\n * @description 支持布尔值或函数类型。当为函数时,接收请求参数并返回布尔值决定是否显示错误提示。\n * @example\n * // 布尔值\n * showError: true\n * // 函数:根据错误码决定是否显示\n * showError: (err) => err.errCode !== 404\n */\n showError?: boolean | ((...inputs: I) => boolean);\n};\n\n/**\n * 用于调用云对象方法的hook函数类型定义\n * @template I 输入参数类型数组\n * @template O 输出结果类型\n */\nexport type UseCloudMethod<Api extends Record<string, AnyFunction>> = {\n <K extends keyof Api, I extends AnyArray, O>(\n method: K,\n caller: (request: Api[K], ...inputs: I) => Promise<CloudMethodOutput<O>>,\n options?: UseCloudMethodOptions<I, O>,\n ): UseRequestOutput<I, O>;\n};\n\n/**\n * 导入云对象并创建一个用于调用云对象的hook\n * @param objectName 云对象名称\n * @param importOptions 配置选项,包含模拟服务器、回退错误信息等\n * @returns 返回一个可用于调用云对象方法的hook函数\n */\nexport function importCloudObject<Api extends Record<string, AnyFunction>>(\n objectName: string,\n importOptions?: CreateUseCloudObjectOptions,\n) {\n const fallbackErrorMessage = importOptions?.fallbackErrorMessage || '请求失败';\n const server =\n importOptions?._mockServer ||\n uniCloud.importObject(objectName, {\n customUI: true,\n });\n const onShowLoading = importOptions?.onShowLoading || (() => uniLoading());\n const onHideLoading = importOptions?.onHideLoading || (() => uni.hideLoading());\n const onShowError = importOptions?.onShowError || ((err) => uniToast(err.message));\n\n /**\n * 用于调用云对象方法的hook函数\n * @template I 输入参数类型\n * @template O 输出结果类型\n * @param method 云对象方法名\n * @param caller 调用云对象的函数\n * @param options 配置选项,包含请求相关的配置\n * @returns 返回一个请求hook,用于处理云对象调用\n */\n const useCloudMethod: UseCloudMethod<Api> = (method, caller, options) => {\n // 使用请求hook处理云对象调用\n return useRequest(\n async (...inputs) => {\n const request = server[method];\n const output = await caller(request, ...inputs);\n return parseCloudMethodOutput(output, fallbackErrorMessage);\n },\n {\n ...options,\n async onBefore(...inputs) {\n const shouldShowLoading =\n typeof options?.showLoading === 'function' ? options.showLoading(...inputs) : options?.showLoading;\n if (shouldShowLoading) onShowLoading();\n\n await importOptions?.onBefore?.();\n await options?.onBefore?.(...inputs);\n },\n async onSuccess(data, ...inputs) {\n await importOptions?.onSuccess?.();\n await options?.onSuccess?.(data, ...inputs);\n },\n async onError(err, ...inputs) {\n await importOptions?.onError?.(err as UniError);\n await options?.onError?.(err as UniError, ...inputs);\n\n const shouldShowError =\n typeof options?.showError === 'function' ? options.showError(...inputs) : options?.showError;\n if (shouldShowError) {\n // 加延迟是尽量保证在 loading 隐藏后再显示错误信息\n setTimeout(() => {\n onShowError(err as UniError);\n });\n }\n },\n async onAfter(...inputs) {\n if (options?.showLoading) onHideLoading();\n\n await importOptions?.onAfter?.();\n await options?.onAfter?.(...inputs);\n },\n },\n );\n };\n\n return useCloudMethod;\n}\n\nexport type UseDatabaseOptions<I extends AnyArray, O> = UseRequestOptions<I, O> & {\n /**\n * 模拟数据库,用于单元测试\n */\n // biome-ignore lint/suspicious/noExplicitAny: 单测使用 any\n _mockDatabase?: any;\n};\n\n/**\n * 创建一个用于调用云数据库的hook\n * @param caller 调用云数据库的函数,接收数据库实例和输入参数,返回Promise\n * @param options 配置选项\n * @returns 返回一个请求hook,用于处理云数据库调用\n */\nexport function useDatabase<I extends AnyArray, O>(\n caller: (db: UniCloud.Database, ...inputs: I) => Promise<ClientDatabaseOutput<O>>,\n options?: UseDatabaseOptions<I, O>,\n): UseRequestOutput<I, O>;\nexport function useDatabase<I extends AnyArray, O>(\n caller: (db: UniCloud.Database, ...inputs: I) => Promise<ClientDatabaseOutput<O>>,\n options?: UseDatabaseOptions<I, O>,\n): UseRequestOutput<I, O> {\n // 获取数据库实例,优先使用模拟数据库(用于测试),否则使用uniCloud数据库\n const db = options?._mockDatabase || uniCloud.database();\n return useRequest(async (...inputs: I) => {\n const { result } = await caller(db, ...inputs);\n if (!result.errCode) return result;\n throw new Error(result.errMsg || '请求失败');\n }, options);\n}\n","import type { ComponentInternalInstance } from 'vue';\n\nexport type Rect = {\n /**\n * 元素距离屏幕的左坐标,单位:px\n */\n left: number;\n /**\n * 元素距离屏幕的上坐标,单位:px\n */\n top: number;\n /**\n * 元素距离屏幕的宽度,单位:px\n */\n width: number;\n /**\n * 元素距离屏幕的高度,单位:px\n */\n height: number;\n};\n\n/**\n * 查询元素距离屏幕的矩形信息\n * @param instance 组件实例\n * @param selector 选择器\n * @returns 元素距离屏幕的矩形信息\n */\nexport async function querySelectorRects(instance: ComponentInternalInstance, selector: string) {\n return new Promise<Rect[]>((resolve) => {\n uni\n .createSelectorQuery()\n .in(instance.proxy)\n .selectAll(selector)\n .boundingClientRect((_rects) => {\n const rects = _rects as UniApp.NodeInfo[];\n resolve(\n rects.map((rect) => ({\n left: rect.left || 0,\n top: rect.top || 0,\n width: rect.width || 0,\n height: rect.height || 0,\n })),\n );\n })\n .exec();\n });\n}\n"],"mappings":"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"}
package/dist/client.mjs CHANGED
@@ -371,7 +371,7 @@ function importCloudObject(objectName, importOptions) {
371
371
  }, {
372
372
  ...options,
373
373
  async onBefore(...inputs) {
374
- if (options?.showLoading) onShowLoading();
374
+ if (typeof options?.showLoading === "function" ? options.showLoading(...inputs) : options?.showLoading) onShowLoading();
375
375
  await importOptions?.onBefore?.();
376
376
  await options?.onBefore?.(...inputs);
377
377
  },
@@ -382,7 +382,7 @@ function importCloudObject(objectName, importOptions) {
382
382
  async onError(err, ...inputs) {
383
383
  await importOptions?.onError?.(err);
384
384
  await options?.onError?.(err, ...inputs);
385
- if (options?.showError) setTimeout(() => {
385
+ if (typeof options?.showError === "function" ? options.showError(...inputs) : options?.showError) setTimeout(() => {
386
386
  onShowError(err);
387
387
  });
388
388
  },
@@ -1 +1 @@
1
- {"version":3,"file":"client.mjs","names":[],"sources":["../src/client/message.ts","../src/client/app.ts","../src/client/async.ts","../src/client/page.ts","../src/client/request.ts","../src/client/ui.ts"],"sourcesContent":["import { promiseDelay } from '@cloudcome/utils-core/promise';\nimport { isString } from '@cloudcome/utils-core/type';\n\n/**\n * 显示 confirm 提示\n * @param text 提示文本\n * @param options 其他选项\n * @returns 提示完成后的 Promise\n */\nexport function uniConfirm(\n text: string,\n options?: Omit<UniNamespace.ShowModalOptions, 'showCancel' | 'success' | 'content' | 'editable'>,\n) {\n const cancelText = options?.cancelText || '取消';\n const confirmText = options?.confirmText || '确认';\n\n if (cancelText.length > 4) console.warn('微信小程序内不支持 cancelText 长度超过 4 个字符');\n if (confirmText.length > 4) console.warn('微信小程序内不支持 confirmText 长度超过 4 个字符');\n\n return new Promise<boolean>((resolve) => {\n // 避免和 hideLoading 同时出现影响弹窗\n setTimeout(() => {\n uni.showModal({\n title: '请确认',\n content: text,\n showCancel: true,\n confirmText,\n cancelText,\n ...options,\n success(result) {\n resolve(result.confirm);\n },\n });\n });\n });\n}\n\n/**\n * 显示 prompt 提示\n * @param text 提示文本\n * @param options 其他选项\n * @returns 提示完成后的 Promise\n */\nexport function uniPrompt(\n text: string,\n options?: Omit<UniNamespace.ShowModalOptions, 'showCancel' | 'success' | 'content' | 'editable'>,\n) {\n const cancelText = options?.cancelText || '取消';\n const confirmText = options?.confirmText || '确认';\n\n if (cancelText.length > 4) console.warn('微信小程序内不支持 cancelText 长度超过 4 个字符');\n if (confirmText.length > 4) console.warn('微信小程序内不支持 confirmText 长度超过 4 个字符');\n\n return new Promise<string>((resolve) => {\n // 避免和 hideLoading 同时出现影响弹窗\n setTimeout(() => {\n uni.showModal({\n title: '请输入',\n content: '',\n placeholderText: text,\n showCancel: true,\n confirmText,\n cancelText,\n editable: true,\n ...options,\n success(result) {\n resolve(result.content || '');\n },\n });\n });\n });\n}\n\n/**\n * 显示 alert 提示\n * @param text 提示文本\n * @param options 其他选项\n * @returns 提示完成后的 Promise\n */\nexport function uniAlert(\n text: string,\n options?: Omit<UniNamespace.ShowModalOptions, 'cancelText' | 'showCancel' | 'success' | 'content'>,\n) {\n const confirmText = options?.confirmText || '好';\n\n if (confirmText.length > 4) console.warn('微信小程序内不支持 confirmText 长度超过 4 个字符');\n\n return new Promise<void>((resolve) => {\n // 避免和 hideLoading 同时出现影响弹窗\n setTimeout(() => {\n uni.showModal({\n title: '提示',\n confirmText,\n cancelText: '',\n ...options,\n content: text,\n showCancel: false,\n success() {\n resolve();\n },\n });\n });\n });\n}\n\n/**\n * 显示 toast 提示\n * @param text 提示文本\n * @param icon 图标\n * @param options 其他选项\n * @returns 提示完成后的 Promise\n */\nexport function uniToast(text: string, icon?: UniNamespace.ShowToastOptions['icon']): Promise<void>;\nexport function uniToast(text: string, options?: UniNamespace.ShowToastOptions): Promise<void>;\nexport function uniToast(\n text: string,\n iconOrOptions?: UniNamespace.ShowToastOptions['icon'] | UniNamespace.ShowToastOptions,\n): Promise<void> {\n const options = {} as UniNamespace.ShowToastOptions;\n\n if (isString(iconOrOptions)) {\n options.icon = iconOrOptions;\n } else {\n Object.assign(options, iconOrOptions);\n }\n\n return new Promise<void>((resolve) => {\n // 避免和 hideLoading 同时出现影响弹窗\n setTimeout(async () => {\n uni.showToast({\n title: text,\n duration: 2900,\n icon: options.icon || 'none',\n mask: false,\n });\n promiseDelay(3000).then(resolve);\n });\n });\n}\n\n/**\n * 显示 loading 提示\n * @param title 提示文本\n */\nexport function uniLoading(title = '') {\n uni.showLoading({\n title,\n mask: true,\n });\n}\n","import type { HookListenerWithDispose } from '@cloudcome/utils-vue/component';\nimport { _runLifeHook } from '@cloudcome/utils-vue/shared';\nimport { onHide, onShow } from '@dcloudio/uni-app';\nimport { ref } from 'vue';\nimport { uniConfirm } from './message';\n\n/**\n * 应用显示状态生命周期钩子函数\n *\n * 该函数用于监听应用从后台进入前台的生命周期事件。\n * 当应用从后台切换到前台时触发 onShow 回调,\n * 当应用从前台切换到后台时触发 onHide 回调。\n *\n * @param appShow - 应用显示状态变化时的回调函数,可以返回一个清理函数\n *\n * @example\n * // 基本用法\n * useAppShow(() => {\n * console.log('应用进入前台');\n *\n * // 可选:返回一个清理函数,在应用进入后台时执行\n * return () => {\n * console.log('应用进入后台');\n * };\n * });\n *\n * @example\n * // 带有异步操作的用法\n * useAppShow(async () => {\n * // 应用进入前台时刷新数据\n * await refreshUserData();\n *\n * // 返回清理函数\n * return () => {\n * // 应用进入后台时保存数据\n * saveUserData();\n * };\n * });\n */\nexport function useAppShow(appShow: HookListenerWithDispose) {\n _runLifeHook(onShow, onHide, appShow);\n}\n\n/**\n * 订阅模板消息\n * @param templateId 模板消息 ID 或 ID 列表\n * @returns Promise<boolean>\n */\nexport async function uniSubscribeNotice(templateId: string | string[]) {\n if (!uni.requestSubscribeMessage) return false;\n\n return new Promise<boolean>((resolve) => {\n const tmplIds = Array.isArray(templateId) ? templateId : [templateId];\n uni.requestSubscribeMessage({\n tmplIds,\n success(_res) {\n // 'accept'表示用户同意订阅该条id对应的模板消息,\n // 'reject'表示用户拒绝订阅该条id对应的模板消息,\n // 'ban'表示已被后台封禁,\n // 'filter'表示该模板因为模板标题同名被后台过滤\n const res = _res as unknown as Record<string, 'accept' | 'reject' | 'ban' | 'filter'>;\n let subscribed = false;\n\n for (const templateId of tmplIds) {\n if (res[templateId] === 'accept') {\n subscribed = true;\n break;\n }\n }\n\n resolve(subscribed);\n },\n fail() {\n resolve(false);\n },\n });\n });\n}\n\n/**\n * 监听应用更新状态\n */\nexport function useAppUpdate() {\n const hasUpdate = ref(false);\n const updateReady = ref(false);\n const updateManager = uni.getUpdateManager?.();\n\n updateManager?.onCheckForUpdate((res) => {\n // 请求完新版本信息的回调\n hasUpdate.value = Boolean(res.hasUpdate);\n });\n\n updateManager?.onUpdateReady(async () => {\n updateReady.value = true;\n\n const confirm = await uniConfirm('新版本已经准备好,是否重启应用?', {\n title: '更新提示',\n confirmText: '重启',\n });\n if (!confirm) return;\n\n updateManager.applyUpdate();\n });\n\n updateManager?.onUpdateFailed(() => {\n // 新的版本下载失败\n });\n\n return { hasUpdate, updateReady };\n}\n","import { errorAssign } from '@cloudcome/utils-core/error';\n\nexport type UniFailErr = UniNamespace.GeneralCallbackResult & {\n errCode?: number;\n errno?: number;\n};\n\nexport type UniPromiseError = Error & {\n errCode: number;\n errNo: number;\n};\n\n/**\n * 包装 uni 异步函数,返回 Promise 并处理错误\n * @param promise uni 异步函数的 Promise\n * @returns Promise<T>\n * @throws UniPromiseError\n */\nexport async function uniPromise<T>(promise: Promise<T>): Promise<T> {\n try {\n const result = await promise;\n return result;\n } catch (err) {\n const res = err as unknown as UniFailErr;\n throw errorAssign(new Error(res.errMsg || '未知错误'), {\n errCode: res.errCode || -1,\n errNo: res.errno || -1,\n });\n }\n}\n\n/**\n * 包装 uni 异步函数,返回 Promise 并处理错误\n * @param runner uni 异步函数的回调\n * @returns Promise<T>\n * @throws UniPromiseError\n */\nexport async function uniCallback<T>(\n runner: (options: { success: (res: T) => void; fail: (err: UniFailErr) => void }) => unknown,\n) {\n return new Promise<T>((resolve, reject) => {\n runner({\n success(res) {\n resolve(res);\n },\n fail(err) {\n reject(\n errorAssign(new Error(err.errMsg || '未知错误'), {\n errCode: err.errCode || -1,\n errNo: err.errno || -1,\n }),\n );\n },\n });\n });\n}\n","import type { AnyObject } from '@cloudcome/utils-core/types';\nimport type { HookListenerWithDispose } from '@cloudcome/utils-vue/component';\nimport { _runLifeHook } from '@cloudcome/utils-vue/shared';\nimport { onLoad, onPageHide, onPageShow, onUnload } from '@dcloudio/uni-app';\nimport { type Reactive, reactive } from 'vue';\n\n/**\n * 用于获取页面参数的 hook 函数\n * @template T - 页面参数对象的类型,继承自 AnyObject\n * @param {function} [onPageLoad] - 页面加载时的回调函数\n * @param {T} onLoad.query - 页面参数对象\n * @returns {T} 响应式的页面参数对象\n * @example\n * // 基本用法\n * const query = usePageQuery();\n *\n * // 带回调的用法\n * const query = usePageQuery((query) => {\n * console.log('页面参数:', query);\n * });\n *\n * // 指定参数类型\n * interface PageParams {\n * id: string;\n * name?: string;\n * }\n * const query = usePageQuery<PageParams>();\n */\nexport function usePageQuery<T extends AnyObject>(onPageLoad?: (query: Reactive<T>) => void) {\n const query = reactive<T>({} as T);\n\n onLoad((_query) => {\n Object.assign(query, _query);\n onPageLoad?.(query);\n });\n\n return query;\n}\n\n/**\n * 用于处理页面加载生命周期的 hook 函数\n *\n * 该函数会在页面加载时执行传入的回调函数,并在页面卸载时执行清理操作(如果提供了清理函数)。\n * 它是 uni-app 中 onLoad 和 onUnload 生命周期的封装。\n *\n * @param {HookListenerWithDispose} load - 页面加载时的回调函数,可以返回一个清理函数\n *\n * @example\n * // 基本用法\n * usePageLoad(() => {\n * console.log('页面已加载');\n * });\n *\n * @example\n * // 带清理函数的用法\n * usePageLoad(() => {\n * console.log('页面已加载');\n *\n * // 返回一个清理函数,在页面卸载时执行\n * return () => {\n * console.log('页面将要卸载');\n * };\n * });\n *\n * @example\n * // 异步用法\n * usePageLoad(async () => {\n * const data = await fetchData();\n * console.log('获取到数据:', data);\n *\n * return () => {\n * console.log('清理资源');\n * };\n * });\n */\nexport function usePageLoad(load: HookListenerWithDispose) {\n _runLifeHook(onLoad, onUnload, load);\n}\n\n/**\n * 用于处理页面显示生命周期的 hook 函数\n *\n * 该函数会在页面显示时执行传入的回调函数,并在页面隐藏时执行清理操作(如果提供了清理函数)。\n * 它是 uni-app 中 onPageShow 和 onPageHide 生命周期的封装。\n *\n * @param {HookListenerWithDispose} pageShow - 页面显示时的回调函数,可以返回一个清理函数\n *\n * @example\n * // 基本用法\n * usePageShow(() => {\n * console.log('页面已显示');\n * });\n *\n * @example\n * // 带清理函数的用法\n * usePageShow(() => {\n * console.log('页面已显示');\n *\n * // 返回一个清理函数,在页面隐藏时执行\n * return () => {\n * console.log('页面将要隐藏');\n * };\n * });\n */\nexport function usePageShow(pageShow: HookListenerWithDispose) {\n _runLifeHook(onPageShow, onPageHide, pageShow);\n}\n","import type { AnyArray, AnyFunction } from '@cloudcome/utils-core/types';\nimport { type UseRequestOptions, type UseRequestOutput, useRequest } from '@cloudcome/utils-vue/request';\nimport type { CloudMethodOutput, UniError } from '@/cloud';\nimport type { ClientDatabaseOutput } from '@/database';\nimport { parseCloudMethodOutput } from '../_helpers';\nimport { uniLoading, uniToast } from './message';\n\nexport type CreateUseCloudObjectOptions = {\n /**\n * 模拟云对象,用于单元测试\n * @private\n */\n // biome-ignore lint/suspicious/noExplicitAny: 单测使用 any\n _mockServer?: any;\n\n /**\n * 回退错误信息\n * @default '请求失败'\n */\n fallbackErrorMessage?: string;\n\n /**\n * 请求开始前的回调函数\n */\n onBefore?: () => unknown;\n\n /**\n * 请求成功后的回调函数\n */\n onSuccess?: () => unknown;\n\n /**\n * 请求失败时的回调函数\n * @param err 错误信息\n */\n onError?: (err: UniError) => unknown;\n\n /**\n * 请求完成后的回调函数(无论成功或失败都会执行)\n */\n onAfter?: () => unknown;\n\n /**\n * 显示加载状态的回调函数,当配置了 showLoading 为 true 时会调用\n */\n onShowLoading?: () => unknown;\n\n /**\n * 隐藏加载状态的回调函数,当配置了 showLoading 为 true 时会调用\n */\n onHideLoading?: () => unknown;\n\n /**\n * 显示错误信息的回调函数,当配置了 showError 为 true 时会调用\n * @param err 错误信息\n */\n onShowError?: (err: UniError) => unknown;\n};\n\n/**\n * 云对象请求函数类型定义\n * @template F 云对象方法函数类型\n * @param input 云对象方法的参数数组\n * @returns 返回云对象方法执行结果的Promise\n */\nexport type CloudObjectRequest = <F extends AnyFunction>(\n ...input: Parameters<F>\n) => Promise<CloudMethodOutput<ReturnType<F>>>;\n\n/**\n * 用于调用云对象方法的配置选项类型定义\n * @template I 输入参数类型数组\n * @template O 输出结果类型\n */\nexport type UseCloudMethodOptions<I extends AnyArray, O> = Omit<UseRequestOptions<I, O>, 'onError'> & {\n /**\n * 请求发生错误时的回调函数\n * @param err 错误信息\n * @param inputs 请求输入参数\n */\n onError?: (err: UniError, ...inputs: I) => unknown;\n\n /**\n * 是否显示加载状态\n * @default false\n */\n showLoading?: boolean;\n\n /**\n * 是否显示错误信息\n * @default false\n */\n showError?: boolean;\n};\n\n/**\n * 用于调用云对象方法的hook函数类型定义\n * @template I 输入参数类型数组\n * @template O 输出结果类型\n */\nexport type UseCloudMethod<Api extends Record<string, AnyFunction>> = {\n <K extends keyof Api, I extends AnyArray, O>(\n method: K,\n caller: (request: Api[K], ...inputs: I) => Promise<CloudMethodOutput<O>>,\n options?: UseCloudMethodOptions<I, O>,\n ): UseRequestOutput<I, O>;\n};\n\n/**\n * 导入云对象并创建一个用于调用云对象的hook\n * @param objectName 云对象名称\n * @param importOptions 配置选项,包含模拟服务器、回退错误信息等\n * @returns 返回一个可用于调用云对象方法的hook函数\n */\nexport function importCloudObject<Api extends Record<string, AnyFunction>>(\n objectName: string,\n importOptions?: CreateUseCloudObjectOptions,\n) {\n const fallbackErrorMessage = importOptions?.fallbackErrorMessage || '请求失败';\n const server =\n importOptions?._mockServer ||\n uniCloud.importObject(objectName, {\n customUI: true,\n });\n const onShowLoading = importOptions?.onShowLoading || (() => uniLoading());\n const onHideLoading = importOptions?.onHideLoading || (() => uni.hideLoading());\n const onShowError = importOptions?.onShowError || ((err) => uniToast(err.message));\n\n /**\n * 用于调用云对象方法的hook函数\n * @template I 输入参数类型\n * @template O 输出结果类型\n * @param method 云对象方法名\n * @param caller 调用云对象的函数\n * @param options 配置选项,包含请求相关的配置\n * @returns 返回一个请求hook,用于处理云对象调用\n */\n const useCloudMethod: UseCloudMethod<Api> = (method, caller, options) => {\n // 使用请求hook处理云对象调用\n return useRequest(\n async (...inputs) => {\n const request = server[method];\n const output = await caller(request, ...inputs);\n return parseCloudMethodOutput(output, fallbackErrorMessage);\n },\n {\n ...options,\n async onBefore(...inputs) {\n if (options?.showLoading) onShowLoading();\n\n await importOptions?.onBefore?.();\n await options?.onBefore?.(...inputs);\n },\n async onSuccess(data, ...inputs) {\n await importOptions?.onSuccess?.();\n await options?.onSuccess?.(data, ...inputs);\n },\n async onError(err, ...inputs) {\n await importOptions?.onError?.(err as UniError);\n await options?.onError?.(err as UniError, ...inputs);\n\n if (options?.showError) {\n // 加延迟是尽量保证在 loading 隐藏后再显示错误信息\n setTimeout(() => {\n onShowError(err as UniError);\n });\n }\n },\n async onAfter(...inputs) {\n if (options?.showLoading) onHideLoading();\n\n await importOptions?.onAfter?.();\n await options?.onAfter?.(...inputs);\n },\n },\n );\n };\n\n return useCloudMethod;\n}\n\nexport type UseDatabaseOptions<I extends AnyArray, O> = UseRequestOptions<I, O> & {\n /**\n * 模拟数据库,用于单元测试\n */\n // biome-ignore lint/suspicious/noExplicitAny: 单测使用 any\n _mockDatabase?: any;\n};\n\n/**\n * 创建一个用于调用云数据库的hook\n * @param caller 调用云数据库的函数,接收数据库实例和输入参数,返回Promise\n * @param options 配置选项\n * @returns 返回一个请求hook,用于处理云数据库调用\n */\nexport function useDatabase<I extends AnyArray, O>(\n caller: (db: UniCloud.Database, ...inputs: I) => Promise<ClientDatabaseOutput<O>>,\n options?: UseDatabaseOptions<I, O>,\n): UseRequestOutput<I, O>;\nexport function useDatabase<I extends AnyArray, O>(\n caller: (db: UniCloud.Database, ...inputs: I) => Promise<ClientDatabaseOutput<O>>,\n options?: UseDatabaseOptions<I, O>,\n): UseRequestOutput<I, O> {\n // 获取数据库实例,优先使用模拟数据库(用于测试),否则使用uniCloud数据库\n const db = options?._mockDatabase || uniCloud.database();\n return useRequest(async (...inputs: I) => {\n const { result } = await caller(db, ...inputs);\n if (!result.errCode) return result;\n throw new Error(result.errMsg || '请求失败');\n }, options);\n}\n","import type { ComponentInternalInstance } from 'vue';\n\nexport type Rect = {\n /**\n * 元素距离屏幕的左坐标,单位:px\n */\n left: number;\n /**\n * 元素距离屏幕的上坐标,单位:px\n */\n top: number;\n /**\n * 元素距离屏幕的宽度,单位:px\n */\n width: number;\n /**\n * 元素距离屏幕的高度,单位:px\n */\n height: number;\n};\n\n/**\n * 查询元素距离屏幕的矩形信息\n * @param instance 组件实例\n * @param selector 选择器\n * @returns 元素距离屏幕的矩形信息\n */\nexport async function querySelectorRects(instance: ComponentInternalInstance, selector: string) {\n return new Promise<Rect[]>((resolve) => {\n uni\n .createSelectorQuery()\n .in(instance.proxy)\n .selectAll(selector)\n .boundingClientRect((_rects) => {\n const rects = _rects as UniApp.NodeInfo[];\n resolve(\n rects.map((rect) => ({\n left: rect.left || 0,\n top: rect.top || 0,\n width: rect.width || 0,\n height: rect.height || 0,\n })),\n );\n })\n .exec();\n });\n}\n"],"mappings":";;;;;;;;;;;;;;;AASA,SAAgB,WACd,MACA,SACA;CACA,MAAM,aAAa,SAAS,cAAc;CAC1C,MAAM,cAAc,SAAS,eAAe;CAE5C,IAAI,WAAW,SAAS,GAAG,QAAQ,KAAK,iCAAiC;CACzE,IAAI,YAAY,SAAS,GAAG,QAAQ,KAAK,kCAAkC;CAE3E,OAAO,IAAI,SAAkB,YAAY;EAEvC,iBAAiB;GACf,IAAI,UAAU;IACZ,OAAO;IACP,SAAS;IACT,YAAY;IACZ;IACA;IACA,GAAG;IACH,QAAQ,QAAQ;KACd,QAAQ,OAAO,OAAO;IACxB;GACF,CAAC;EACH,CAAC;CACH,CAAC;AACH;;;;;;;AAQA,SAAgB,UACd,MACA,SACA;CACA,MAAM,aAAa,SAAS,cAAc;CAC1C,MAAM,cAAc,SAAS,eAAe;CAE5C,IAAI,WAAW,SAAS,GAAG,QAAQ,KAAK,iCAAiC;CACzE,IAAI,YAAY,SAAS,GAAG,QAAQ,KAAK,kCAAkC;CAE3E,OAAO,IAAI,SAAiB,YAAY;EAEtC,iBAAiB;GACf,IAAI,UAAU;IACZ,OAAO;IACP,SAAS;IACT,iBAAiB;IACjB,YAAY;IACZ;IACA;IACA,UAAU;IACV,GAAG;IACH,QAAQ,QAAQ;KACd,QAAQ,OAAO,WAAW,EAAE;IAC9B;GACF,CAAC;EACH,CAAC;CACH,CAAC;AACH;;;;;;;AAQA,SAAgB,SACd,MACA,SACA;CACA,MAAM,cAAc,SAAS,eAAe;CAE5C,IAAI,YAAY,SAAS,GAAG,QAAQ,KAAK,kCAAkC;CAE3E,OAAO,IAAI,SAAe,YAAY;EAEpC,iBAAiB;GACf,IAAI,UAAU;IACZ,OAAO;IACP;IACA,YAAY;IACZ,GAAG;IACH,SAAS;IACT,YAAY;IACZ,UAAU;KACR,QAAQ;IACV;GACF,CAAC;EACH,CAAC;CACH,CAAC;AACH;AAWA,SAAgB,SACd,MACA,eACe;CACf,MAAM,UAAU,CAAC;CAEjB,IAAI,SAAS,aAAa,GACxB,QAAQ,OAAO;MAEf,OAAO,OAAO,SAAS,aAAa;CAGtC,OAAO,IAAI,SAAe,YAAY;EAEpC,WAAW,YAAY;GACrB,IAAI,UAAU;IACZ,OAAO;IACP,UAAU;IACV,MAAM,QAAQ,QAAQ;IACtB,MAAM;GACR,CAAC;GACD,aAAa,GAAI,EAAE,KAAK,OAAO;EACjC,CAAC;CACH,CAAC;AACH;;;;;AAMA,SAAgB,WAAW,QAAQ,IAAI;CACrC,IAAI,YAAY;EACd;EACA,MAAM;CACR,CAAC;AACH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC9GA,SAAgB,WAAW,SAAkC;CAC3D,aAAa,QAAQ,QAAQ,OAAO;AACtC;;;;;;AAOA,eAAsB,mBAAmB,YAA+B;CACtE,IAAI,CAAC,IAAI,yBAAyB,OAAO;CAEzC,OAAO,IAAI,SAAkB,YAAY;EACvC,MAAM,UAAU,MAAM,QAAQ,UAAU,IAAI,aAAa,CAAC,UAAU;EACpE,IAAI,wBAAwB;GAC1B;GACA,QAAQ,MAAM;IAKZ,MAAM,MAAM;IACZ,IAAI,aAAa;IAEjB,KAAK,MAAM,cAAc,SACvB,IAAI,IAAI,gBAAgB,UAAU;KAChC,aAAa;KACb;IACF;IAGF,QAAQ,UAAU;GACpB;GACA,OAAO;IACL,QAAQ,KAAK;GACf;EACF,CAAC;CACH,CAAC;AACH;;;;AAKA,SAAgB,eAAe;CAC7B,MAAM,YAAY,IAAI,KAAK;CAC3B,MAAM,cAAc,IAAI,KAAK;CAC7B,MAAM,gBAAgB,IAAI,mBAAmB;CAE7C,eAAe,kBAAkB,QAAQ;EAEvC,UAAU,QAAQ,QAAQ,IAAI,SAAS;CACzC,CAAC;CAED,eAAe,cAAc,YAAY;EACvC,YAAY,QAAQ;EAMpB,IAAI,CAAC,MAJiB,WAAW,oBAAoB;GACnD,OAAO;GACP,aAAa;EACf,CAAC,GACa;EAEd,cAAc,YAAY;CAC5B,CAAC;CAED,eAAe,qBAAqB,CAEpC,CAAC;CAED,OAAO;EAAE;EAAW;CAAY;AAClC;;;;;;;;;AC3FA,eAAsB,WAAc,SAAiC;CACnE,IAAI;EAEF,OAAO,MADc;CAEvB,SAAS,KAAK;EACZ,MAAM,MAAM;EACZ,MAAM,YAAY,IAAI,MAAM,IAAI,UAAU,MAAM,GAAG;GACjD,SAAS,IAAI,WAAW;GACxB,OAAO,IAAI,SAAS;EACtB,CAAC;CACH;AACF;;;;;;;AAQA,eAAsB,YACpB,QACA;CACA,OAAO,IAAI,SAAY,SAAS,WAAW;EACzC,OAAO;GACL,QAAQ,KAAK;IACX,QAAQ,GAAG;GACb;GACA,KAAK,KAAK;IACR,OACE,YAAY,IAAI,MAAM,IAAI,UAAU,MAAM,GAAG;KAC3C,SAAS,IAAI,WAAW;KACxB,OAAO,IAAI,SAAS;IACtB,CAAC,CACH;GACF;EACF,CAAC;CACH,CAAC;AACH;;;;;;;;;;;;;;;;;;;;;;;;;AC3BA,SAAgB,aAAkC,YAA2C;CAC3F,MAAM,QAAQ,SAAY,CAAC,CAAM;CAEjC,QAAQ,WAAW;EACjB,OAAO,OAAO,OAAO,MAAM;EAC3B,aAAa,KAAK;CACpB,CAAC;CAED,OAAO;AACT;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAsCA,SAAgB,YAAY,MAA+B;CACzD,aAAa,QAAQ,UAAU,IAAI;AACrC;;;;;;;;;;;;;;;;;;;;;;;;;;AA2BA,SAAgB,YAAY,UAAmC;CAC7D,aAAa,YAAY,YAAY,QAAQ;AAC/C;;;;;;;;;ACQA,SAAgB,kBACd,YACA,eACA;CACA,MAAM,uBAAuB,eAAe,wBAAwB;CACpE,MAAM,SACJ,eAAe,eACf,SAAS,aAAa,YAAY,EAChC,UAAU,KACZ,CAAC;CACH,MAAM,gBAAgB,eAAe,wBAAwB,WAAW;CACxE,MAAM,gBAAgB,eAAe,wBAAwB,IAAI,YAAY;CAC7E,MAAM,cAAc,eAAe,iBAAiB,QAAQ,SAAS,IAAI,OAAO;;;;;;;;;;CAWhF,MAAM,kBAAuC,QAAQ,QAAQ,YAAY;EAEvE,OAAO,WACL,OAAO,GAAG,WAAW;GACnB,MAAM,UAAU,OAAO;GAEvB,OAAO,uBAAuB,MADT,OAAO,SAAS,GAAG,MAAM,GACR,oBAAoB;EAC5D,GACA;GACE,GAAG;GACH,MAAM,SAAS,GAAG,QAAQ;IACxB,IAAI,SAAS,aAAa,cAAc;IAExC,MAAM,eAAe,WAAW;IAChC,MAAM,SAAS,WAAW,GAAG,MAAM;GACrC;GACA,MAAM,UAAU,MAAM,GAAG,QAAQ;IAC/B,MAAM,eAAe,YAAY;IACjC,MAAM,SAAS,YAAY,MAAM,GAAG,MAAM;GAC5C;GACA,MAAM,QAAQ,KAAK,GAAG,QAAQ;IAC5B,MAAM,eAAe,UAAU,GAAe;IAC9C,MAAM,SAAS,UAAU,KAAiB,GAAG,MAAM;IAEnD,IAAI,SAAS,WAEX,iBAAiB;KACf,YAAY,GAAe;IAC7B,CAAC;GAEL;GACA,MAAM,QAAQ,GAAG,QAAQ;IACvB,IAAI,SAAS,aAAa,cAAc;IAExC,MAAM,eAAe,UAAU;IAC/B,MAAM,SAAS,UAAU,GAAG,MAAM;GACpC;EACF,CACF;CACF;CAEA,OAAO;AACT;AAoBA,SAAgB,YACd,QACA,SACwB;CAExB,MAAM,KAAK,SAAS,iBAAiB,SAAS,SAAS;CACvD,OAAO,WAAW,OAAO,GAAG,WAAc;EACxC,MAAM,EAAE,WAAW,MAAM,OAAO,IAAI,GAAG,MAAM;EAC7C,IAAI,CAAC,OAAO,SAAS,OAAO;EAC5B,MAAM,IAAI,MAAM,OAAO,UAAU,MAAM;CACzC,GAAG,OAAO;AACZ;;;;;;;;;ACvLA,eAAsB,mBAAmB,UAAqC,UAAkB;CAC9F,OAAO,IAAI,SAAiB,YAAY;EACtC,IACG,oBAAoB,EACpB,GAAG,SAAS,KAAK,EACjB,UAAU,QAAQ,EAClB,oBAAoB,WAAW;GAE9B,QACE,OAAM,KAAK,UAAU;IACnB,MAAM,KAAK,QAAQ;IACnB,KAAK,KAAK,OAAO;IACjB,OAAO,KAAK,SAAS;IACrB,QAAQ,KAAK,UAAU;GACzB,EAAE,CACJ;EACF,CAAC,EACA,KAAK;CACV,CAAC;AACH"}
1
+ {"version":3,"file":"client.mjs","names":[],"sources":["../src/client/message.ts","../src/client/app.ts","../src/client/async.ts","../src/client/page.ts","../src/client/request.ts","../src/client/ui.ts"],"sourcesContent":["import { promiseDelay } from '@cloudcome/utils-core/promise';\nimport { isString } from '@cloudcome/utils-core/type';\n\n/**\n * 显示 confirm 提示\n * @param text 提示文本\n * @param options 其他选项\n * @returns 提示完成后的 Promise\n */\nexport function uniConfirm(\n text: string,\n options?: Omit<UniNamespace.ShowModalOptions, 'showCancel' | 'success' | 'content' | 'editable'>,\n) {\n const cancelText = options?.cancelText || '取消';\n const confirmText = options?.confirmText || '确认';\n\n if (cancelText.length > 4) console.warn('微信小程序内不支持 cancelText 长度超过 4 个字符');\n if (confirmText.length > 4) console.warn('微信小程序内不支持 confirmText 长度超过 4 个字符');\n\n return new Promise<boolean>((resolve) => {\n // 避免和 hideLoading 同时出现影响弹窗\n setTimeout(() => {\n uni.showModal({\n title: '请确认',\n content: text,\n showCancel: true,\n confirmText,\n cancelText,\n ...options,\n success(result) {\n resolve(result.confirm);\n },\n });\n });\n });\n}\n\n/**\n * 显示 prompt 提示\n * @param text 提示文本\n * @param options 其他选项\n * @returns 提示完成后的 Promise\n */\nexport function uniPrompt(\n text: string,\n options?: Omit<UniNamespace.ShowModalOptions, 'showCancel' | 'success' | 'content' | 'editable'>,\n) {\n const cancelText = options?.cancelText || '取消';\n const confirmText = options?.confirmText || '确认';\n\n if (cancelText.length > 4) console.warn('微信小程序内不支持 cancelText 长度超过 4 个字符');\n if (confirmText.length > 4) console.warn('微信小程序内不支持 confirmText 长度超过 4 个字符');\n\n return new Promise<string>((resolve) => {\n // 避免和 hideLoading 同时出现影响弹窗\n setTimeout(() => {\n uni.showModal({\n title: '请输入',\n content: '',\n placeholderText: text,\n showCancel: true,\n confirmText,\n cancelText,\n editable: true,\n ...options,\n success(result) {\n resolve(result.content || '');\n },\n });\n });\n });\n}\n\n/**\n * 显示 alert 提示\n * @param text 提示文本\n * @param options 其他选项\n * @returns 提示完成后的 Promise\n */\nexport function uniAlert(\n text: string,\n options?: Omit<UniNamespace.ShowModalOptions, 'cancelText' | 'showCancel' | 'success' | 'content'>,\n) {\n const confirmText = options?.confirmText || '好';\n\n if (confirmText.length > 4) console.warn('微信小程序内不支持 confirmText 长度超过 4 个字符');\n\n return new Promise<void>((resolve) => {\n // 避免和 hideLoading 同时出现影响弹窗\n setTimeout(() => {\n uni.showModal({\n title: '提示',\n confirmText,\n cancelText: '',\n ...options,\n content: text,\n showCancel: false,\n success() {\n resolve();\n },\n });\n });\n });\n}\n\n/**\n * 显示 toast 提示\n * @param text 提示文本\n * @param icon 图标\n * @param options 其他选项\n * @returns 提示完成后的 Promise\n */\nexport function uniToast(text: string, icon?: UniNamespace.ShowToastOptions['icon']): Promise<void>;\nexport function uniToast(text: string, options?: UniNamespace.ShowToastOptions): Promise<void>;\nexport function uniToast(\n text: string,\n iconOrOptions?: UniNamespace.ShowToastOptions['icon'] | UniNamespace.ShowToastOptions,\n): Promise<void> {\n const options = {} as UniNamespace.ShowToastOptions;\n\n if (isString(iconOrOptions)) {\n options.icon = iconOrOptions;\n } else {\n Object.assign(options, iconOrOptions);\n }\n\n return new Promise<void>((resolve) => {\n // 避免和 hideLoading 同时出现影响弹窗\n setTimeout(async () => {\n uni.showToast({\n title: text,\n duration: 2900,\n icon: options.icon || 'none',\n mask: false,\n });\n promiseDelay(3000).then(resolve);\n });\n });\n}\n\n/**\n * 显示 loading 提示\n * @param title 提示文本\n */\nexport function uniLoading(title = '') {\n uni.showLoading({\n title,\n mask: true,\n });\n}\n","import type { HookListenerWithDispose } from '@cloudcome/utils-vue/component';\nimport { _runLifeHook } from '@cloudcome/utils-vue/shared';\nimport { onHide, onShow } from '@dcloudio/uni-app';\nimport { ref } from 'vue';\nimport { uniConfirm } from './message';\n\n/**\n * 应用显示状态生命周期钩子函数\n *\n * 该函数用于监听应用从后台进入前台的生命周期事件。\n * 当应用从后台切换到前台时触发 onShow 回调,\n * 当应用从前台切换到后台时触发 onHide 回调。\n *\n * @param appShow - 应用显示状态变化时的回调函数,可以返回一个清理函数\n *\n * @example\n * // 基本用法\n * useAppShow(() => {\n * console.log('应用进入前台');\n *\n * // 可选:返回一个清理函数,在应用进入后台时执行\n * return () => {\n * console.log('应用进入后台');\n * };\n * });\n *\n * @example\n * // 带有异步操作的用法\n * useAppShow(async () => {\n * // 应用进入前台时刷新数据\n * await refreshUserData();\n *\n * // 返回清理函数\n * return () => {\n * // 应用进入后台时保存数据\n * saveUserData();\n * };\n * });\n */\nexport function useAppShow(appShow: HookListenerWithDispose) {\n _runLifeHook(onShow, onHide, appShow);\n}\n\n/**\n * 订阅模板消息\n * @param templateId 模板消息 ID 或 ID 列表\n * @returns Promise<boolean>\n */\nexport async function uniSubscribeNotice(templateId: string | string[]) {\n if (!uni.requestSubscribeMessage) return false;\n\n return new Promise<boolean>((resolve) => {\n const tmplIds = Array.isArray(templateId) ? templateId : [templateId];\n uni.requestSubscribeMessage({\n tmplIds,\n success(_res) {\n // 'accept'表示用户同意订阅该条id对应的模板消息,\n // 'reject'表示用户拒绝订阅该条id对应的模板消息,\n // 'ban'表示已被后台封禁,\n // 'filter'表示该模板因为模板标题同名被后台过滤\n const res = _res as unknown as Record<string, 'accept' | 'reject' | 'ban' | 'filter'>;\n let subscribed = false;\n\n for (const templateId of tmplIds) {\n if (res[templateId] === 'accept') {\n subscribed = true;\n break;\n }\n }\n\n resolve(subscribed);\n },\n fail() {\n resolve(false);\n },\n });\n });\n}\n\n/**\n * 监听应用更新状态\n */\nexport function useAppUpdate() {\n const hasUpdate = ref(false);\n const updateReady = ref(false);\n const updateManager = uni.getUpdateManager?.();\n\n updateManager?.onCheckForUpdate((res) => {\n // 请求完新版本信息的回调\n hasUpdate.value = Boolean(res.hasUpdate);\n });\n\n updateManager?.onUpdateReady(async () => {\n updateReady.value = true;\n\n const confirm = await uniConfirm('新版本已经准备好,是否重启应用?', {\n title: '更新提示',\n confirmText: '重启',\n });\n if (!confirm) return;\n\n updateManager.applyUpdate();\n });\n\n updateManager?.onUpdateFailed(() => {\n // 新的版本下载失败\n });\n\n return { hasUpdate, updateReady };\n}\n","import { errorAssign } from '@cloudcome/utils-core/error';\n\nexport type UniFailErr = UniNamespace.GeneralCallbackResult & {\n errCode?: number;\n errno?: number;\n};\n\nexport type UniPromiseError = Error & {\n errCode: number;\n errNo: number;\n};\n\n/**\n * 包装 uni 异步函数,返回 Promise 并处理错误\n * @param promise uni 异步函数的 Promise\n * @returns Promise<T>\n * @throws UniPromiseError\n */\nexport async function uniPromise<T>(promise: Promise<T>): Promise<T> {\n try {\n const result = await promise;\n return result;\n } catch (err) {\n const res = err as unknown as UniFailErr;\n throw errorAssign(new Error(res.errMsg || '未知错误'), {\n errCode: res.errCode || -1,\n errNo: res.errno || -1,\n });\n }\n}\n\n/**\n * 包装 uni 异步函数,返回 Promise 并处理错误\n * @param runner uni 异步函数的回调\n * @returns Promise<T>\n * @throws UniPromiseError\n */\nexport async function uniCallback<T>(\n runner: (options: { success: (res: T) => void; fail: (err: UniFailErr) => void }) => unknown,\n) {\n return new Promise<T>((resolve, reject) => {\n runner({\n success(res) {\n resolve(res);\n },\n fail(err) {\n reject(\n errorAssign(new Error(err.errMsg || '未知错误'), {\n errCode: err.errCode || -1,\n errNo: err.errno || -1,\n }),\n );\n },\n });\n });\n}\n","import type { AnyObject } from '@cloudcome/utils-core/types';\nimport type { HookListenerWithDispose } from '@cloudcome/utils-vue/component';\nimport { _runLifeHook } from '@cloudcome/utils-vue/shared';\nimport { onLoad, onPageHide, onPageShow, onUnload } from '@dcloudio/uni-app';\nimport { type Reactive, reactive } from 'vue';\n\n/**\n * 用于获取页面参数的 hook 函数\n * @template T - 页面参数对象的类型,继承自 AnyObject\n * @param {function} [onPageLoad] - 页面加载时的回调函数\n * @param {T} onLoad.query - 页面参数对象\n * @returns {T} 响应式的页面参数对象\n * @example\n * // 基本用法\n * const query = usePageQuery();\n *\n * // 带回调的用法\n * const query = usePageQuery((query) => {\n * console.log('页面参数:', query);\n * });\n *\n * // 指定参数类型\n * interface PageParams {\n * id: string;\n * name?: string;\n * }\n * const query = usePageQuery<PageParams>();\n */\nexport function usePageQuery<T extends AnyObject>(onPageLoad?: (query: Reactive<T>) => void) {\n const query = reactive<T>({} as T);\n\n onLoad((_query) => {\n Object.assign(query, _query);\n onPageLoad?.(query);\n });\n\n return query;\n}\n\n/**\n * 用于处理页面加载生命周期的 hook 函数\n *\n * 该函数会在页面加载时执行传入的回调函数,并在页面卸载时执行清理操作(如果提供了清理函数)。\n * 它是 uni-app 中 onLoad 和 onUnload 生命周期的封装。\n *\n * @param {HookListenerWithDispose} load - 页面加载时的回调函数,可以返回一个清理函数\n *\n * @example\n * // 基本用法\n * usePageLoad(() => {\n * console.log('页面已加载');\n * });\n *\n * @example\n * // 带清理函数的用法\n * usePageLoad(() => {\n * console.log('页面已加载');\n *\n * // 返回一个清理函数,在页面卸载时执行\n * return () => {\n * console.log('页面将要卸载');\n * };\n * });\n *\n * @example\n * // 异步用法\n * usePageLoad(async () => {\n * const data = await fetchData();\n * console.log('获取到数据:', data);\n *\n * return () => {\n * console.log('清理资源');\n * };\n * });\n */\nexport function usePageLoad(load: HookListenerWithDispose) {\n _runLifeHook(onLoad, onUnload, load);\n}\n\n/**\n * 用于处理页面显示生命周期的 hook 函数\n *\n * 该函数会在页面显示时执行传入的回调函数,并在页面隐藏时执行清理操作(如果提供了清理函数)。\n * 它是 uni-app 中 onPageShow 和 onPageHide 生命周期的封装。\n *\n * @param {HookListenerWithDispose} pageShow - 页面显示时的回调函数,可以返回一个清理函数\n *\n * @example\n * // 基本用法\n * usePageShow(() => {\n * console.log('页面已显示');\n * });\n *\n * @example\n * // 带清理函数的用法\n * usePageShow(() => {\n * console.log('页面已显示');\n *\n * // 返回一个清理函数,在页面隐藏时执行\n * return () => {\n * console.log('页面将要隐藏');\n * };\n * });\n */\nexport function usePageShow(pageShow: HookListenerWithDispose) {\n _runLifeHook(onPageShow, onPageHide, pageShow);\n}\n","import type { AnyArray, AnyFunction } from '@cloudcome/utils-core/types';\nimport { type UseRequestOptions, type UseRequestOutput, useRequest } from '@cloudcome/utils-vue/request';\nimport type { CloudMethodOutput, UniError } from '@/cloud';\nimport type { ClientDatabaseOutput } from '@/database';\nimport { parseCloudMethodOutput } from '../_helpers';\nimport { uniLoading, uniToast } from './message';\n\nexport type CreateUseCloudObjectOptions = {\n /**\n * 模拟云对象,用于单元测试\n * @private\n */\n // biome-ignore lint/suspicious/noExplicitAny: 单测使用 any\n _mockServer?: any;\n\n /**\n * 回退错误信息\n * @default '请求失败'\n */\n fallbackErrorMessage?: string;\n\n /**\n * 请求开始前的回调函数\n */\n onBefore?: () => unknown;\n\n /**\n * 请求成功后的回调函数\n */\n onSuccess?: () => unknown;\n\n /**\n * 请求失败时的回调函数\n * @param err 错误信息\n */\n onError?: (err: UniError) => unknown;\n\n /**\n * 请求完成后的回调函数(无论成功或失败都会执行)\n */\n onAfter?: () => unknown;\n\n /**\n * 显示加载状态的回调函数,当配置了 showLoading 为 true 时会调用\n */\n onShowLoading?: () => unknown;\n\n /**\n * 隐藏加载状态的回调函数,当配置了 showLoading 为 true 时会调用\n */\n onHideLoading?: () => unknown;\n\n /**\n * 显示错误信息的回调函数,当配置了 showError 为 true 时会调用\n * @param err 错误信息\n */\n onShowError?: (err: UniError) => unknown;\n};\n\n/**\n * 云对象请求函数类型定义\n * @template F 云对象方法函数类型\n * @param input 云对象方法的参数数组\n * @returns 返回云对象方法执行结果的Promise\n */\nexport type CloudObjectRequest = <F extends AnyFunction>(\n ...input: Parameters<F>\n) => Promise<CloudMethodOutput<ReturnType<F>>>;\n\n/**\n * 用于调用云对象方法的配置选项类型定义\n * @template I 输入参数类型数组\n * @template O 输出结果类型\n */\nexport type UseCloudMethodOptions<I extends AnyArray, O> = Omit<UseRequestOptions<I, O>, 'onError'> & {\n /**\n * 请求发生错误时的回调函数\n * @param err 错误信息\n * @param inputs 请求输入参数\n */\n onError?: (err: UniError, ...inputs: I) => unknown;\n\n /**\n * 是否显示加载状态\n * @default false\n * @description 支持布尔值或函数类型。当为函数时,接收请求参数并返回布尔值决定是否显示 loading。\n * @example\n * // 布尔值\n * showLoading: true\n * // 函数:根据参数决定是否显示\n * showLoading: (userId) => userId !== 'anonymous'\n */\n showLoading?: boolean | ((...inputs: I) => boolean);\n\n /**\n * 是否显示错误信息\n * @default false\n * @description 支持布尔值或函数类型。当为函数时,接收请求参数并返回布尔值决定是否显示错误提示。\n * @example\n * // 布尔值\n * showError: true\n * // 函数:根据错误码决定是否显示\n * showError: (err) => err.errCode !== 404\n */\n showError?: boolean | ((...inputs: I) => boolean);\n};\n\n/**\n * 用于调用云对象方法的hook函数类型定义\n * @template I 输入参数类型数组\n * @template O 输出结果类型\n */\nexport type UseCloudMethod<Api extends Record<string, AnyFunction>> = {\n <K extends keyof Api, I extends AnyArray, O>(\n method: K,\n caller: (request: Api[K], ...inputs: I) => Promise<CloudMethodOutput<O>>,\n options?: UseCloudMethodOptions<I, O>,\n ): UseRequestOutput<I, O>;\n};\n\n/**\n * 导入云对象并创建一个用于调用云对象的hook\n * @param objectName 云对象名称\n * @param importOptions 配置选项,包含模拟服务器、回退错误信息等\n * @returns 返回一个可用于调用云对象方法的hook函数\n */\nexport function importCloudObject<Api extends Record<string, AnyFunction>>(\n objectName: string,\n importOptions?: CreateUseCloudObjectOptions,\n) {\n const fallbackErrorMessage = importOptions?.fallbackErrorMessage || '请求失败';\n const server =\n importOptions?._mockServer ||\n uniCloud.importObject(objectName, {\n customUI: true,\n });\n const onShowLoading = importOptions?.onShowLoading || (() => uniLoading());\n const onHideLoading = importOptions?.onHideLoading || (() => uni.hideLoading());\n const onShowError = importOptions?.onShowError || ((err) => uniToast(err.message));\n\n /**\n * 用于调用云对象方法的hook函数\n * @template I 输入参数类型\n * @template O 输出结果类型\n * @param method 云对象方法名\n * @param caller 调用云对象的函数\n * @param options 配置选项,包含请求相关的配置\n * @returns 返回一个请求hook,用于处理云对象调用\n */\n const useCloudMethod: UseCloudMethod<Api> = (method, caller, options) => {\n // 使用请求hook处理云对象调用\n return useRequest(\n async (...inputs) => {\n const request = server[method];\n const output = await caller(request, ...inputs);\n return parseCloudMethodOutput(output, fallbackErrorMessage);\n },\n {\n ...options,\n async onBefore(...inputs) {\n const shouldShowLoading =\n typeof options?.showLoading === 'function' ? options.showLoading(...inputs) : options?.showLoading;\n if (shouldShowLoading) onShowLoading();\n\n await importOptions?.onBefore?.();\n await options?.onBefore?.(...inputs);\n },\n async onSuccess(data, ...inputs) {\n await importOptions?.onSuccess?.();\n await options?.onSuccess?.(data, ...inputs);\n },\n async onError(err, ...inputs) {\n await importOptions?.onError?.(err as UniError);\n await options?.onError?.(err as UniError, ...inputs);\n\n const shouldShowError =\n typeof options?.showError === 'function' ? options.showError(...inputs) : options?.showError;\n if (shouldShowError) {\n // 加延迟是尽量保证在 loading 隐藏后再显示错误信息\n setTimeout(() => {\n onShowError(err as UniError);\n });\n }\n },\n async onAfter(...inputs) {\n if (options?.showLoading) onHideLoading();\n\n await importOptions?.onAfter?.();\n await options?.onAfter?.(...inputs);\n },\n },\n );\n };\n\n return useCloudMethod;\n}\n\nexport type UseDatabaseOptions<I extends AnyArray, O> = UseRequestOptions<I, O> & {\n /**\n * 模拟数据库,用于单元测试\n */\n // biome-ignore lint/suspicious/noExplicitAny: 单测使用 any\n _mockDatabase?: any;\n};\n\n/**\n * 创建一个用于调用云数据库的hook\n * @param caller 调用云数据库的函数,接收数据库实例和输入参数,返回Promise\n * @param options 配置选项\n * @returns 返回一个请求hook,用于处理云数据库调用\n */\nexport function useDatabase<I extends AnyArray, O>(\n caller: (db: UniCloud.Database, ...inputs: I) => Promise<ClientDatabaseOutput<O>>,\n options?: UseDatabaseOptions<I, O>,\n): UseRequestOutput<I, O>;\nexport function useDatabase<I extends AnyArray, O>(\n caller: (db: UniCloud.Database, ...inputs: I) => Promise<ClientDatabaseOutput<O>>,\n options?: UseDatabaseOptions<I, O>,\n): UseRequestOutput<I, O> {\n // 获取数据库实例,优先使用模拟数据库(用于测试),否则使用uniCloud数据库\n const db = options?._mockDatabase || uniCloud.database();\n return useRequest(async (...inputs: I) => {\n const { result } = await caller(db, ...inputs);\n if (!result.errCode) return result;\n throw new Error(result.errMsg || '请求失败');\n }, options);\n}\n","import type { ComponentInternalInstance } from 'vue';\n\nexport type Rect = {\n /**\n * 元素距离屏幕的左坐标,单位:px\n */\n left: number;\n /**\n * 元素距离屏幕的上坐标,单位:px\n */\n top: number;\n /**\n * 元素距离屏幕的宽度,单位:px\n */\n width: number;\n /**\n * 元素距离屏幕的高度,单位:px\n */\n height: number;\n};\n\n/**\n * 查询元素距离屏幕的矩形信息\n * @param instance 组件实例\n * @param selector 选择器\n * @returns 元素距离屏幕的矩形信息\n */\nexport async function querySelectorRects(instance: ComponentInternalInstance, selector: string) {\n return new Promise<Rect[]>((resolve) => {\n uni\n .createSelectorQuery()\n .in(instance.proxy)\n .selectAll(selector)\n .boundingClientRect((_rects) => {\n const rects = _rects as UniApp.NodeInfo[];\n resolve(\n rects.map((rect) => ({\n left: rect.left || 0,\n top: rect.top || 0,\n width: rect.width || 0,\n height: rect.height || 0,\n })),\n );\n })\n .exec();\n });\n}\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { HasProperty, IsEmptyObject, IsOnlyProperty } from '@cloudcome/utils-core/types';
1
+ import { IsEmptyObject, IsOnlyProperty } from '@cloudcome/utils-core/types';
2
2
  import { UniErrorData } from '../_types';
3
3
  import { DbMutateCommand, DbQueryCommand } from './_command.class';
4
4
  /**
@@ -48,10 +48,7 @@ type _OnlyFieldId<D, V> = IsOnlyProperty<D, '_id'> extends true ? ('_id' extends
48
48
  */
49
49
  export type DbFields<D, S extends DbSelect<D>> = IsEmptyObject<S> extends true ? DbFieldsDefault<D> : _OnlyFieldId<S, false> extends true ? Omit<DbFieldsDefault<D>, '_id'> : _OnlyFieldId<S, true> extends true ? {
50
50
  _id: true;
51
- } : HasProperty<S, '_id'> extends true ? S : // 没有的话补上 {_id, ...}
52
- S & {
53
- _id: true;
54
- };
51
+ } : S;
55
52
  /**
56
53
  * 数据库查询结果类型
57
54
  * @template D1 - 主数据模型类型
@@ -78,6 +75,10 @@ export type DbRelation = '1:1' | '1:n' | 'n:1';
78
75
  * 判断类型是否可能为 null 或 undefined
79
76
  */
80
77
  type IsNullable<T> = null extends T ? true : undefined extends T ? true : false;
78
+ /**
79
+ * 判断字段是否为 _id(主键)
80
+ */
81
+ type IsIdField<LF> = LF extends '_id' ? true : false;
81
82
  /**
82
83
  * 数据库外键关联类型
83
84
  * @template MainData - 主表数据类型(用于判断 localField 是否可选)
@@ -88,7 +89,8 @@ type IsNullable<T> = null extends T ? true : undefined extends T ? true : false;
88
89
  * @template AS - 关联字段别名
89
90
  * @template LF - 主表关联字段名(用于判断是否可选)
90
91
  */
91
- export type DbForeign<MainData, RelatedData, RelatedSelect extends DbSelect<RelatedData>, RelatedExtra, RL extends DbRelation, AS extends string, LF extends keyof MainData> = Record<AS, RL extends '1:1' ? IsNullable<MainData[LF]> extends true ? DbQuery<RelatedData, RelatedSelect, RelatedExtra> | null : DbQuery<RelatedData, RelatedSelect, RelatedExtra> : DbQuery<RelatedData, RelatedSelect, RelatedExtra>[]>;
92
+ export type DbForeign<MainData, RelatedData, RelatedSelect extends DbSelect<RelatedData>, RelatedExtra, RL extends DbRelation, AS extends string, LF extends keyof MainData> = Record<AS, RL extends '1:1' ? IsIdField<LF> extends true ? // 主键关联:关联表不一定存在,返回 T | null
93
+ DbQuery<RelatedData, RelatedSelect, RelatedExtra> | null : IsNullable<MainData[LF]> extends true ? DbQuery<RelatedData, RelatedSelect, RelatedExtra> | null : DbQuery<RelatedData, RelatedSelect, RelatedExtra> : DbQuery<RelatedData, RelatedSelect, RelatedExtra>[]>;
92
94
  /**
93
95
  * 数据库创建数据类型
94
96
  * @template T - 数据模型类型
package/dist/database.cjs CHANGED
@@ -478,8 +478,8 @@ var Db = class Db {
478
478
  }
479
479
  this._lookupAs[as] = true;
480
480
  }
481
- if (this._hasSample) returnAggRef = returnAggRef.sample({ size: this._sampleSize });
482
481
  if (this._hasWhere) returnAggRef = returnAggRef.match(_mapCommandRaw(this._where));
482
+ if (this._hasSample) returnAggRef = returnAggRef.sample({ size: this._sampleSize });
483
483
  if (this._hasOrder) returnAggRef = returnAggRef.sort((0, _cloudcome_utils_core_object.objectMap)(this._order, (v) => v === "asc" ? 1 : -1));
484
484
  if (this._hasSkip) returnAggRef = returnAggRef.skip(this._skip);
485
485
  if (this._hasLimit) returnAggRef = returnAggRef.limit(this._limit);
@@ -1 +1 @@
1
- {"version":3,"file":"database.cjs","names":[],"sources":["../src/database/_command.class.ts","../src/database/command.ts","../src/database/each.ts","../src/database/error.ts","../src/database/paging.ts","../src/database/_db.class.ts","../src/database/proxy.ts","../src/database/transaction.ts","../src/database/upsert.ts","../src/database/unique.ts"],"sourcesContent":["// 设置私有属性和静态方法是避免在 update 的时候提示类属性\n\nexport class DbBaseCommand {\n protected _isQuery = false;\n protected _isMutate = false;\n\n constructor(\n private _command: string,\n private _parameter: unknown,\n private _options?: {\n formatParameter?: (db: UniCloud.Database) => unknown;\n rewriteValue?: (db: UniCloud.Database, parameter: unknown) => unknown;\n },\n ) {}\n\n static getValue(cmd: DbBaseCommand, db: UniCloud.Database) {\n if (cmd._options?.rewriteValue) {\n return cmd._options.rewriteValue(db, cmd._parameter);\n }\n\n return (db.command as unknown as Record<string, (value: unknown) => unknown>)[cmd._command].call(\n db.command,\n cmd._options?.formatParameter?.(db) || cmd._parameter,\n );\n }\n\n static getExpression(cmd: DbBaseCommand, fieldName: string) {\n return {\n [`$${cmd._command}`]: [fieldName, cmd._parameter],\n };\n }\n\n static isQueryCommand(cmd: DbBaseCommand) {\n return cmd._isQuery;\n }\n\n static isMutateCommand(cmd: DbBaseCommand) {\n return cmd._isMutate;\n }\n}\n\nexport class DbQueryCommand extends DbBaseCommand {\n protected _isQuery = true;\n}\n\nexport class DbMutateCommand extends DbBaseCommand {\n protected _isMutate = true;\n}\n","import { DbBaseCommand, DbMutateCommand, DbQueryCommand } from './_command.class';\n\n/**\n * 数据库查询命令对象,提供各种查询操作符\n */\nexport const dbQuery = {\n /**\n * 等于操作符\n * @param value 比较值\n * @returns DbQueryCommand 查询命令对象\n */\n eq: (value: unknown) => new DbQueryCommand('eq', value),\n\n /**\n * 不等于操作符\n * @param value 比较值\n * @returns DbQueryCommand 查询命令对象\n */\n neq: (value: unknown) => new DbQueryCommand('neq', value),\n\n /**\n * 大于操作符\n * @param value 比较值\n * @returns DbQueryCommand 查询命令对象\n */\n gt: (value: unknown) => new DbQueryCommand('gt', value),\n\n /**\n * 大于等于操作符\n * @param value 比较值\n * @returns DbQueryCommand 查询命令对象\n */\n gte: (value: unknown) => new DbQueryCommand('gte', value),\n\n /**\n * 小于操作符\n * @param value 比较值\n * @returns DbQueryCommand 查询命令对象\n */\n lt: (value: unknown) => new DbQueryCommand('lt', value),\n\n /**\n * 小于等于操作符\n * @param value 比较值\n * @returns DbQueryCommand 查询命令对象\n */\n lte: (value: unknown) => new DbQueryCommand('lte', value),\n\n /**\n * 包含在数组中操作符\n * @param value 值数组\n * @returns DbQueryCommand 查询命令对象\n */\n in: (value: unknown[]) => new DbQueryCommand('in', value),\n\n /**\n * 不包含在数组中操作符\n * @param value 值数组\n * @returns DbQueryCommand 查询命令对象\n */\n nin: (value: unknown[]) => new DbQueryCommand('nin', value),\n\n /**\n * 数组长度匹配操作符\n * @param size 数组长度\n * @returns DbQueryCommand 查询命令对象\n */\n size: (size: number) => new DbQueryCommand('size', size),\n\n /**\n * 正则表达式匹配操作符\n * @param regExp 正则表达式\n * @returns DbQueryCommand 查询命令对象\n */\n regExp: (regExp: RegExp) =>\n new DbQueryCommand('regExp', regExp, {\n rewriteValue: (_db, parameter) => parameter,\n }),\n\n /**\n * 逻辑与操作符\n * @param conditions 查询条件参数\n * @returns DbQueryCommand 查询命令对象\n */\n and: (conditions: DbQueryCommand[]) =>\n new DbQueryCommand('and', conditions, {\n formatParameter: (db) => conditions.map((c) => DbBaseCommand.getValue(c, db)),\n }),\n\n /**\n * 逻辑或操作符\n * @param conditions 查询条件参数\n * @returns DbQueryCommand 查询命令对象\n */\n or: (conditions: DbQueryCommand[]) =>\n new DbQueryCommand('or', conditions, {\n formatParameter: (db) => conditions.map((c) => DbBaseCommand.getValue(c, db)),\n }),\n};\n\n/**\n * 数据库变更命令对象,提供各种数据更新操作符\n */\nexport const dbMutate = {\n /**\n * 数值增加操作符\n * @param value 增加的数值\n * @returns DbMutateCommand 变更命令对象\n */\n inc: (value: number) => new DbMutateCommand('inc', value),\n\n /**\n * 数值乘法操作符\n * @param value 乘数\n * @returns DbMutateCommand 变更命令对象\n */\n mul: (value: number) => new DbMutateCommand('mul', value),\n\n /**\n * 设置字段值操作符\n * @param value 设置的值\n * @returns DbMutateCommand 变更命令对象\n */\n set: (value: unknown) => new DbMutateCommand('set', value),\n\n /**\n * 向数组末尾添加元素操作符\n * @param value 添加的值\n * @returns DbMutateCommand 变更命令对象\n */\n push: (value: unknown) => new DbMutateCommand('push', value),\n\n /**\n * 向数组开头添加元素操作符\n * @param value 添加的值\n * @returns DbMutateCommand 变更命令对象\n */\n unshift: (value: unknown) => new DbMutateCommand('unshift', value),\n\n /**\n * 从数组末尾移除元素操作符\n * @returns DbMutateCommand 变更命令对象\n */\n pop: () => new DbMutateCommand('pop', undefined),\n\n /**\n * 从数组开头移除元素操作符\n * @returns DbMutateCommand 变更命令对象\n */\n shift: () => new DbMutateCommand('shift', undefined),\n\n /**\n * 移除字段操作符\n * @returns DbMutateCommand 变更命令对象\n */\n remove: () => new DbMutateCommand('remove', undefined),\n};\n","import type { Db } from './_db.class';\nimport type { DbWhere } from './types';\n\n/**\n * 遍历表中的每一行数据并执行回调函数\n *\n * 采用分批查询策略,每批查询 100 条记录,通过 skip/limit 实现分页遍历,\n * 避免一次性加载大量数据导致内存溢出。\n *\n * 迭代器按顺序串行执行,即每一行数据的迭代器完成后才会处理下一行。\n *\n * @template T - 数据行类型\n * @param table 数据库表代理对象\n * @param where 查询条件\n * @param iterator 对每一行数据执行的异步迭代器函数\n * @param maxCount 最大遍历数量,默认值为 Number.MAX_SAFE_INTEGER。\n * 注意:由于分批查询机制(每批 100 条),实际遍历的行数可能略大于 maxCount,\n * 例如 maxCount=150 时,会分两批查询(0-99、100-199),实际遍历 200 行。\n * @example\n * ```ts\n * // 遍历所有状态为 active 的用户\n * await dbEach(userTable, { status: 'active' }, async (user) => {\n * await sendEmail(user.email);\n * });\n *\n * // 限制最多遍历 500 条记录\n * await dbEach(orderTable, { status: 'pending' }, async (order) => {\n * await processOrder(order);\n * }, 500);\n * ```\n */\nexport async function dbEach<T>(\n table: Db<T>,\n where: DbWhere<T>,\n iterator: (row: T) => Promise<unknown>,\n maxCount = Number.MAX_SAFE_INTEGER,\n) {\n const count = Math.min(await table.where(where).count(), maxCount);\n const limit = 100;\n\n for (let skip = 0; skip < count; skip += limit) {\n const rows = await table.where(where).limit(limit).skip(skip).many();\n\n for (const row of rows) {\n await iterator(row as T);\n }\n }\n}\n","/**\n * 数据库底层异常类\n * 当 uniCloud 数据库操作抛出错误时,统一包装为该异常\n */\nexport class DbError extends Error {\n /** 原始错误码,如 'InternalServerError' */\n errCode: string | number;\n /** MongoDB 错误码,如 'E11000'。不匹配则为空字符串 */\n dbCode: string;\n\n constructor(message: string, extra: { errCode: string | number; dbCode: string }) {\n super(message);\n this.name = 'DbError';\n this.errCode = extra.errCode;\n this.dbCode = extra.dbCode;\n }\n}\n\n/**\n * 判断错误是否为数据库底层错误\n * @param err - 任意错误对象\n * @returns 是否为 DbError\n */\nexport function isDbError(err: unknown): err is DbError {\n return err instanceof DbError;\n}\n\n/**\n * 从 MongoDB 错误消息中提取错误码\n * @param errMsg - 错误消息字符串,如 'E11000 duplicate key error...'\n * @returns MongoDB 错误码,如 'E11000'\n */\nexport function extractMongoCode(errMsg: string): string {\n const m = errMsg.match(/^E\\d+/);\n return m ? m[0] : '';\n}\n","import type { AnyObject } from '@cloudcome/utils-core/types';\nimport type { Db } from './_db.class';\nimport type { DbSelect } from './types';\n\n/**\n * 数据库分页查询函数\n * @template T - 数据类型\n * @param queryDb - 数据库查询实例\n * @returns 包含数据列表和总数的对象\n */\n\nexport async function dbPaging<\n D1,\n // biome-ignore lint/complexity/noBannedTypes: 必须这么用\n S1 extends DbSelect<D1> = {},\n // biome-ignore lint/complexity/noBannedTypes: 必须这么用\n D2 extends AnyObject = {},\n // biome-ignore lint/complexity/noBannedTypes: 必须这么用\n W2 extends AnyObject = {},\n>(queryDb: Db<D1, S1, D2, W2>) {\n // 获取原始查询条件,不包映射字段\n const where = queryDb.getWhere(true);\n\n // 克隆查询实例用于统计总数,避免影响原查询\n const countDb = queryDb.clone();\n\n // 执行查询获取数据列表\n const list = await queryDb.many();\n\n // 基于相同查询条件统计总数\n const total = await countDb.where(where).count();\n\n // 返回分页结果\n return {\n list,\n total,\n };\n}\n","import { isUniError, parseDatabaseOutput } from '@/_helpers';\nimport type { UniError } from '@/_types';\nimport { createCloudObjectError } from '@/cloud';\nimport { objectEach, objectFilter, objectMap, objectOmit } from '@cloudcome/utils-core/object';\nimport { isArray, isObject } from '@cloudcome/utils-core/type';\nimport type { AnyObject, MergeIntersection } from '@cloudcome/utils-core/types';\nimport { DbBaseCommand, type DbQueryCommand } from './_command.class';\nimport { DbError, extractMongoCode } from './error';\nimport type { DbCreate, DbForeign, DbOrder, DbQuery, DbRelation, DbSelect, DbUpdate, DbWhere } from './types';\n\n/**\n * 数据库聚合操作符命令\n */\nconst dbAgg = uniCloud.database().command.aggregate as UniCloud.AggregateCommand & {\n pipeline: () => UniCloud.AggregateReference & {\n done: () => unknown;\n };\n};\n\nconst db0 = uniCloud.database();\n\nexport type DbOptions = {\n /**\n * 数据表名称\n */\n table: string;\n\n /**\n * 事务对象,用于事务操作\n */\n // biome-ignore lint/suspicious/noExplicitAny: 必须这么用\n transaction?: any;\n\n /**\n * 模拟数据库,用于单元测试\n */\n // biome-ignore lint/suspicious/noExplicitAny: 单测使用 any\n _mockDatabase?: any;\n\n /**\n * 自定义错误处理函数\n * @param error unknown 数据库异常对象\n * @returns 自定义错误对象\n */\n parseError?: (error: unknown) => UniError;\n};\n\nexport type DbLookupOptions<\n RL extends DbRelation,\n D1,\n FD1,\n AS,\n // biome-ignore lint/suspicious/noConfusingVoidType: 必须这么用\n US extends boolean | undefined | void = undefined,\n LF extends keyof D1 & string = keyof D1 & string,\n> = {\n /**\n * 关联类型\n */\n relation: RL;\n\n /**\n * 主表字段\n */\n localField: LF;\n\n /**\n * 关联表字段\n */\n foreignField: keyof FD1 & string;\n\n /**\n * 关联数据在结果中的字段名\n */\n as: AS;\n\n /**\n * 是否取消筛选关联数据\n */\n unselect?: US;\n};\n\nexport type DbLookup = DbLookupOptions<\n // biome-ignore lint/suspicious/noExplicitAny: 必须这么用\n any,\n unknown,\n unknown,\n string,\n boolean\n> & {\n /**\n * 关联表\n */\n table: Db<unknown>;\n};\n\nlet gid = 0;\n\n/**\n * 数据库类\n * @template D1 - 主表数据\n * @template S1 - 主表筛选\n * @template D2 - 副表数据\n * @template W2 - 副表查询\n */\nexport class Db<\n D1,\n // biome-ignore lint/complexity/noBannedTypes: 必须这么用\n S1 extends DbSelect<D1> = {},\n // biome-ignore lint/complexity/noBannedTypes: 必须这么用\n D2 extends AnyObject = {},\n // biome-ignore lint/complexity/noBannedTypes: 必须这么用\n W2 extends AnyObject = {},\n> {\n /**\n * 是否为事务环境\n * - 更新条件只能是 id\n * - 删除条件只能是 id\n */\n private _isTransaction = false;\n\n private _options: DbOptions;\n\n /**\n * 构造函数,初始化数据库集合引用\n * @param collection 数据表名称\n * @param _mockDatabase 模拟数据库,用于单元测试\n */\n constructor(options: DbOptions) {\n this._options = options;\n // hostRef =\n // options._mockDatabase || options.transaction?.collection(options.table) || db0.collection(options.table);\n this._isTransaction = !!options.transaction;\n }\n\n /**\n * 创建一个新的数据库实例,可选是否移除事务\n * @param withoutTransaction 是否移除事务,默认 false\n * @returns 新的数据库实例\n */\n clone(withoutTransaction?: boolean) {\n return new Db({\n ...this._options,\n transaction: withoutTransaction ? null : this._options.transaction,\n });\n }\n\n get table() {\n return this._options.table;\n }\n\n get options() {\n return this._options;\n }\n\n get isTransaction() {\n return this._isTransaction;\n }\n\n _createHost(withoutTransaction?: boolean) {\n const options = this._options;\n return (\n options._mockDatabase ||\n (withoutTransaction ? null : options.transaction?.collection(options.table) || db0.collection(options.table))\n );\n }\n\n /**\n * 获取聚合操作实例\n * @returns 聚合操作实例\n */\n _createAggregate() {\n const host = this._createHost();\n return host.aggregate();\n }\n\n private _hasWhere = false;\n private _hasWhereId = false;\n private _where = {};\n\n /**\n * 设置查询条件\n * @param where 查询条件对象\n * @returns 当前Db实例,支持链式调用\n */\n where(where: DbWhere<D1> & W2) {\n if (this._isTransaction) throw new Error('事务模式下请使用 whereId() 方法');\n if (this._hasWhere) throw new Error('已调用过一次 db.where({...}) 或 db.whereId(id) 了');\n\n // 过滤掉值为 undefined 的键值对,数据库不支持查询全 undefined 值\n const realWhere = objectFilter(where, (value) => value !== undefined);\n\n this._hasWhere = true;\n this._where = realWhere;\n\n return this;\n }\n\n /**\n * 获取当前查询条件\n * @param plain 是否返回原始查询条件对象,默认 false\n * @returns 当前查询条件对象\n */\n getWhere(plain?: boolean) {\n return plain\n ? // biome-ignore lint/suspicious/noTsIgnore: 必须这么用\n // @ts-ignore\n objectOmit(this._where, Object.keys(this._lookupAs))\n : this._where;\n }\n\n /**\n * 根据ID设置查询条件\n * @param id 记录ID\n * @returns 当前Db实例,支持链式调用\n */\n whereId(id: string | number) {\n if (this._hasWhere) throw new Error('已调用过一次 db.where({...}) 或 db.whereId(id) 了');\n if (this._hasLimit) throw new Error('db.whereId(id) 方法不能与 db.limit() 方法同时调用');\n\n this._hasWhere = true;\n this._hasWhereId = true;\n this._where = { _id: id };\n\n return this;\n }\n\n private _hasSelect = 0;\n private _select = {};\n\n /**\n * 指定要返回的字段\n * @param fields 要返回的字段对象,true表示返回,false表示不返回\n * @returns 当前Db实例,支持链式调用\n */\n select<const S extends DbSelect<D1>>(fields: S) {\n if (this._hasSelect) throw new Error('db.select() 方法只能调用一次');\n\n this._hasSelect++;\n this._select = fields;\n\n return this as Db<D1, S, D2, W2>;\n }\n\n private _hasOrder = 0;\n private _order = {};\n\n /**\n * 设置排序规则\n * @param order 排序规则对象,key为字段名,value为\"asc\"或\"desc\"\n * @returns 当前Db实例,支持链式调用\n */\n order(order: DbOrder<D1>) {\n if (this._isTransaction) throw new Error('db.order() 方法不支持事务模式');\n\n this._hasOrder++;\n this._order = order;\n\n return this;\n }\n\n private _hasSkip = 0;\n private _skip = 0;\n\n /**\n * 跳过指定数量的记录\n * @param skip 要跳过的记录数\n * @returns 当前Db实例,支持链式调用\n */\n skip(skip: number) {\n if (this._isTransaction) throw new Error('db.skip() 方法不支持事务模式');\n if (this._hasSkip) throw new Error('db.skip() 方法只能调用一次');\n\n this._hasSkip++;\n this._skip = skip;\n\n return this;\n }\n\n private _hasLimit = 0;\n private _limit = 0;\n\n /**\n * 限制返回的记录数量\n * @param limit 最大返回记录数\n * @returns 当前Db实例,支持链式调用\n */\n limit(limit: number) {\n if (this._isTransaction) throw new Error('db.limit() 方法不支持事务模式');\n if (this._hasLimit) throw new Error('db.limit() 方法只能调用一次');\n if (this._hasSample) throw new Error('db.limit() 方法不支持 sample 条件');\n\n if (this._hasWhereId) {\n throw new Error('db.limit() 方法不能与 db.whereId(id) 方法同时调用');\n }\n\n this._hasLimit++;\n this._limit = limit;\n\n return this;\n }\n\n private _hasSample = 0;\n private _sampleSize = 0;\n\n /**\n * 随机从文档中选取指定数量的记录\n * @param size 要选取的记录数量,必须为正整数\n * @returns 当前Db实例,支持链式调用\n */\n sample(size: number) {\n if (this._isTransaction) throw new Error('db.sample() 方法不支持事务模式');\n if (this._hasSample) throw new Error('db.sample() 方法只能调用一次');\n if (this._hasLimit) throw new Error('db.sample() 方法不支持 limit 条件');\n\n this._hasSample++;\n this._sampleSize = size;\n\n return this;\n }\n\n private _hasLookup = 0;\n get hasLookup() {\n return this._hasLookup > 0;\n }\n\n private _lookups: DbLookup[] = [];\n lookup<\n FD1,\n FS1 extends DbSelect<FD1>,\n FD2 extends AnyObject,\n FW2 extends AnyObject,\n RL extends DbRelation,\n AS extends string,\n // biome-ignore lint/suspicious/noConfusingVoidType: 必须这么用\n US extends boolean | undefined | void = undefined,\n LF extends keyof D1 & string = keyof D1 & string,\n >(table: Db<FD1, FS1, FD2, FW2>, lookup: DbLookupOptions<RL, D1, FD1, AS, US, LF>) {\n if (this._isTransaction) throw new Error('db.lookup() 方法不支持事务模式');\n\n // 对方表也记为关联查询,避免做表更新操作\n table._hasLookup++;\n this._hasLookup++;\n this._lookups.push({\n ...lookup,\n table,\n } as unknown as DbLookup);\n\n // @ts-expect-error\n return this as Db<\n D1,\n S1,\n US extends true ? D2 : MergeIntersection<D2 & DbForeign<D1, FD1, FS1, FD2, RL, AS, LF>>,\n MergeIntersection<W2 & Partial<Record<AS, DbQueryCommand>>>\n >;\n }\n\n private _ending = false;\n\n private _aggregated = false;\n private _lookupAs = {} as Record<string, true>;\n private _endAggregate(aggRef: UniCloud.AggregateReference) {\n if (this._aggregated) throw new Error(`相同的数据表实例(${this.table})不能重复使用`);\n if (this._ending) throw new Error(`相同的数据表实例(${this.table})不能重复使用`);\n\n this._ending = true;\n this._aggregated = true;\n let returnAggRef = aggRef;\n let _hasAggSelect = 0;\n const aggSelect = {} as Record<string, true>;\n let hasAggUnselect = 0;\n const aggUnselect = {} as Record<string, false>;\n\n // 后做关联查询\n for (const { relation: type, as, foreignField, localField, table, unselect } of this._lookups) {\n const letName = `let${gid++}`;\n let pipeline = dbAgg.pipeline();\n\n // 关联条件\n // @ts-expect-error\n pipeline = pipeline.match({\n $expr: {\n $and: [\n type === 'n:1'\n ? { $in: [`$${foreignField}`, `$$${letName}`] }\n : { $eq: [`$${foreignField}`, `$$${letName}`] },\n ],\n },\n });\n\n // 其他查询条件\n // @ts-expect-error\n pipeline = table._endAggregate(pipeline);\n\n // @ts-expect-error\n pipeline = pipeline.done();\n\n returnAggRef = returnAggRef.lookup({\n let: {\n [letName]: `$${localField}`,\n },\n as,\n from: table.table,\n pipeline,\n });\n\n // 1对1,展开数组\n if (type === '1:1') {\n // @ts-expect-error\n returnAggRef = returnAggRef.unwind({\n path: `$${as}`,\n preserveNullAndEmptyArrays: true,\n });\n }\n\n if (unselect) {\n hasAggUnselect++;\n aggUnselect[as] = false;\n } else {\n _hasAggSelect++;\n aggSelect[as] = true;\n }\n\n this._lookupAs[as] = true;\n }\n\n // 主表查询,注意顺序,筛选->排序->跳过->限制\n if (this._hasSample) returnAggRef = returnAggRef.sample({ size: this._sampleSize });\n if (this._hasWhere) returnAggRef = returnAggRef.match(_mapCommandRaw(this._where));\n if (this._hasOrder) returnAggRef = returnAggRef.sort(objectMap(this._order, (v) => (v === 'asc' ? 1 : -1)));\n if (this._hasSkip) returnAggRef = returnAggRef.skip(this._skip);\n if (this._hasLimit) returnAggRef = returnAggRef.limit(this._limit);\n\n // 如果主表有选择字段,则合并选择字段(包括关联查询的字段和排序字段)\n if (this._hasSelect) {\n returnAggRef = returnAggRef.project(_mergeSelect({ ...this._select, ...aggSelect }, this._order));\n }\n // 如果主表没有选择字段,则排除取消选择字段\n else if (hasAggUnselect) {\n returnAggRef = returnAggRef.project(aggUnselect);\n }\n\n return returnAggRef;\n }\n\n private _endHost(host: UniCloud.CollectionReference, action: 'query' | 'create' | 'update' | 'remove' | 'count') {\n if (this._ending) throw new Error(`相同的数据表实例(${this.table})不能重复使用`);\n this._ending = true;\n\n // 事务模式下:查询/更新/删除必须使用 whereId\n if (\n this._isTransaction &&\n (action === 'query' || action === 'update' || action === 'remove') &&\n !this._hasWhereId\n ) {\n throw new Error('事务模式下查询/更新/删除条件只能是 ID,请使用 whereId() 方法');\n }\n\n let hostRef = host;\n if (this._hasWhere) {\n // 事务模式下:更新/删除/查询只能用 doc(id)\n if (this._isTransaction && (action === 'update' || action === 'remove' || action === 'query')) {\n // @ts-expect-error\n hostRef = hostRef.doc(this._where._id);\n } else {\n // @ts-expect-error\n hostRef = hostRef.where(_mapCommandRaw(this._where));\n }\n }\n\n if (this._hasSelect) {\n // @ts-expect-error\n hostRef = hostRef.field(_mergeSelect(this._select, this._order));\n }\n\n if (this._hasOrder) {\n objectEach(this._order, (val, key) => {\n // @ts-expect-error\n hostRef = hostRef.orderBy(key, val);\n });\n }\n\n // @ts-expect-error\n if (this._hasSkip) hostRef = hostRef.skip(this._skip);\n\n if (this._hasLimit && action === 'query')\n // @ts-expect-error\n hostRef = hostRef.limit(this._limit);\n else if (this._hasWhereId && action === 'query' && !this._isTransaction)\n // @ts-expect-error\n hostRef = hostRef.limit(1);\n\n return hostRef;\n }\n\n /**\n * 将 uniCloud 数据库原始错误包装为 DbError\n * @param err - 原始错误对象,来自 uniCloud DB 操作(Error 实例,含 errMsg、errCode 属性)\n * @returns DbError 实例\n */\n private _parseDbError(err: UniError) {\n const errCode = err.errCode || '';\n const message = err.errMsg || err.message;\n const dbCode = extractMongoCode(err.errMsg || err.message);\n\n if (dbCode) {\n return new DbError(message, {\n errCode: errCode,\n dbCode: dbCode,\n });\n } else {\n return err;\n }\n }\n\n /**\n * 统一处理 DB 操作抛出的错误\n * - uniCloud 数据库错误(含 errMsg)→ 包装为 DbError → 经 parseError 回调后抛出\n * - 非数据库错误(如网络中断)→ 原样抛出\n */\n private _handleDbError(err: unknown): never {\n if (isUniError(err)) {\n const dbErr = this._parseDbError(err);\n throw this._options.parseError?.(dbErr) || dbErr;\n } else {\n throw this._options.parseError?.(err) || err;\n }\n }\n\n /**\n * 执行查询操作\n * @returns 查询结果\n */\n async many() {\n try {\n let res: { data: DbQuery<D1, S1, D2>[] | DbQuery<D1, S1, D2> | undefined };\n\n // 事务模式下不支持聚合查询\n if (this._isTransaction && (this._hasLookup || this._hasSample)) {\n throw new Error('事务模式下不支持 lookup 聚合或 sample 取样查询');\n }\n\n // 关联查询 / sample 查询(sample 依赖聚合管线)\n if (this._hasLookup || this._hasSample) {\n let aggRef = this._createAggregate();\n aggRef = this._endAggregate(aggRef);\n res = await aggRef.end();\n }\n // 单表查询\n else {\n let hostRef = this._createHost();\n hostRef = this._endHost(hostRef, 'query');\n res = await hostRef.get();\n }\n\n const { data } = parseDatabaseOutput(res);\n\n // doc(id).get() 返回单个对象或 undefined,需包装为数组以统一 many() 返回值\n return isArray(data) ? data : data ? [data] : [];\n } catch (err) {\n this._handleDbError(err);\n }\n }\n\n /**\n * 只查询一条,自动添加 limit(1) 条件\n * 如果没有匹配到记录,会抛出错误\n * @returns 查询结果\n */\n async firstOrThrow(): Promise<DbQuery<D1, S1, D2>> {\n if (this._hasLimit) throw new Error('db.firstOrThrow() 方法不支持 limit 条件');\n if (!this._hasWhereId && !this._hasSample) this.limit(1);\n\n const data = await this.many();\n const res = data.at(0);\n\n if (!res) throw createCloudObjectError('查询数据为空', 'firstOrThrow');\n return res;\n }\n\n /**\n * 只查询一条,自动添加 limit(1) 条件\n * 如果没有匹配到记录,返回 null\n * @returns 查询结果或 null\n */\n async firstOrNull(): Promise<DbQuery<D1, S1, D2> | null> {\n if (this._hasLimit) throw new Error('db.firstOrNull() 方法不支持 limit 条件');\n if (!this._hasWhereId && !this._hasSample) this.limit(1);\n\n const data = await this.many();\n return data.at(0) || null;\n }\n\n /**\n * 获取匹配记录的数量\n * @returns 记录总数\n */\n async count() {\n if (this._isTransaction) throw new Error('db.count() 方法不支持事务模式');\n if (this._hasSample) throw new Error('db.count() 方法不支持 sample 取样');\n if (this._hasLookup) throw new Error('db.count() 方法不支持 lookup 聚合');\n if (this._hasSelect) throw new Error('db.count() 方法不支持 select 条件');\n if (this._hasOrder) throw new Error('db.count() 方法不支持 order 条件');\n if (this._hasSkip) throw new Error('db.count() 方法不支持 skip 条件');\n if (this._hasLimit) throw new Error('db.count() 方法不支持 limit 条件');\n\n try {\n let hostRef = this._createHost();\n hostRef = this._endHost(hostRef, 'count');\n const res = await hostRef.count();\n const { total } = parseDatabaseOutput<{ total: number }>(res);\n return total;\n } catch (err) {\n this._handleDbError(err);\n }\n }\n\n /**\n * 创建新记录\n * @param data 要创建的数据\n * @returns 创建结果\n */\n async create(data: DbCreate<D1>) {\n if (this._hasLookup) throw new Error('db.create() 方法不支持 lookup 聚合');\n if (this._hasWhere) throw new Error('db.create() 方法不支持 where 条件');\n if (this._hasSelect) throw new Error('db.create() 方法不支持 select 条件');\n if (this._hasOrder) throw new Error('db.create() 方法不支持 order 条件');\n if (this._hasSkip) throw new Error('db.create() 方法不支持 skip 条件');\n if (this._hasLimit) throw new Error('db.create() 方法不支持 limit 条件');\n\n try {\n let hostRef = this._createHost();\n hostRef = this._endHost(hostRef, 'create');\n const res = await hostRef.add(data);\n const { id } = parseDatabaseOutput<{ id: string }>(res);\n return id;\n } catch (err) {\n this._handleDbError(err);\n }\n }\n\n /**\n * 更新记录\n * @param data 要更新的数据\n * @returns 更新结果\n */\n async update(data: DbUpdate<D1>) {\n if (this._hasLookup) throw new Error('db.update() 方法不支持 lookup 聚合');\n if (!this._hasWhere) throw new Error('设置 where 条件后才能执行 db.update() 方法');\n if (this._hasSelect) throw new Error('db.update() 方法不支持 select 条件');\n if (this._hasOrder) throw new Error('db.update() 方法不支持 order 条件');\n if (this._hasSkip) throw new Error('db.update() 方法不支持 skip 条件');\n if (this._hasLimit) throw new Error('db.update() 方法不支持 limit 条件');\n\n if (this._isTransaction && !this._hasWhereId) throw new Error('事务模式下 db.update() 的 where 条件必须是 _id');\n\n try {\n let hostRef = this._createHost();\n hostRef = this._endHost(hostRef, 'update');\n const res = await hostRef.update(objectOmit(_mapCommandRaw(data), ['_id']));\n const { updated } = parseDatabaseOutput<{ updated: number }>(res);\n return updated;\n } catch (err) {\n this._handleDbError(err);\n }\n }\n\n /**\n * 删除记录\n * @returns 删除结果\n */\n async remove() {\n if (this._hasLookup) throw new Error('db.remove() 方法不支持 lookup 聚合');\n if (!this._hasWhere) throw new Error('设置 where 条件后才能执行 db.remove() 方法');\n if (this._hasSelect) throw new Error('db.remove() 方法不支持 select 条件');\n if (this._hasOrder) throw new Error('db.remove() 方法不支持 order 条件');\n if (this._hasSkip) throw new Error('db.remove() 方法不支持 skip 条件');\n if (this._hasLimit) throw new Error('db.remove() 方法不支持 limit 条件');\n\n if (this._isTransaction && !this._hasWhereId) throw new Error('事务模式下 db.remove() 的 where 条件必须是 _id');\n\n try {\n let hostRef = this._createHost();\n hostRef = this._endHost(hostRef, 'remove');\n const res = await hostRef.remove();\n const { deleted } = parseDatabaseOutput<{ deleted: number }>(res);\n return deleted;\n } catch (err) {\n this._handleDbError(err);\n }\n }\n}\n\n// biome-ignore lint/suspicious/noExplicitAny: 必须这么用\nfunction _mapCommandRaw(data: any) {\n // biome-ignore lint/suspicious/noExplicitAny: 必须这么用\n const map = (val: any): any => {\n if (!isObject(val)) return val;\n if (val instanceof DbBaseCommand) return DbBaseCommand.getValue(val, db0);\n return objectMap(val, map);\n };\n\n return objectMap(data, map);\n}\n\nfunction _mapOrderSelect(order: DbOrder<unknown>) {\n return objectMap(order, (_val, _key) => true);\n}\n\nfunction _mergeSelect(select: DbSelect<unknown>, order: DbOrder<unknown>) {\n const noSelect = Object.keys(select).length === 0;\n // 如果没有 select 条件,默认返回所有字段\n if (noSelect) return select;\n\n const onlyOmitId = Object.keys(select).length === 1 && '_id' in select && select._id === false;\n // 如果只排除 _id 字段,则保持现状\n if (onlyOmitId) return select;\n\n return {\n ...select,\n ..._mapOrderSelect(order),\n };\n}\n","import { isFunction } from '@cloudcome/utils-core/type';\nimport { Db } from './_db.class';\nimport type { DbSelect } from './types';\nimport type { UniError } from '@/_types';\n\nexport type DbProxyOptions = {\n /**\n * 自定义错误处理函数\n * @param error unknown 数据库异常对象\n * @returns 自定义错误对象\n */\n parseError?: (error: unknown) => UniError;\n};\n\n/**\n * 创建一个数据库代理对象,用于延迟实例化数据库操作类\n * @template D1 - 主表数据\n * @template S1 - 主表筛选\n * @param name - 数据库表名\n * @returns 返回一个代理对象,该对象会将属性访问转发到实际的数据库操作实例\n */\n\n// biome-ignore lint/complexity/noBannedTypes: 必须这么用\nexport function dbProxy<D1, S1 extends DbSelect<D1> = {}>(name: string, options?: DbProxyOptions) {\n return new Proxy(\n {},\n {\n get(_target, prop) {\n if (prop === '_isProxy') return true;\n\n const table = new Db<D1, S1>({ table: name, ...options });\n const tableProp = prop as keyof Db<D1, S1>;\n const ref = table[tableProp];\n\n return isFunction(ref) ? ref.bind(table) : ref;\n },\n },\n ) as Db<D1, S1>;\n}\n","import { tryFlatten } from '@cloudcome/utils-core/try';\nimport { Db } from './_db.class';\n\ntype _TransactionDb = {\n startTransaction: () => Promise<_Transaction>;\n};\n\ntype _Transaction = {\n commit: () => Promise<unknown>;\n rollback: () => Promise<unknown>;\n};\n\nexport type WithTransaction = <D1>(db: Db<D1>) => Db<D1>;\n\n/**\n * 在数据库事务中执行操作\n *\n * @template K - 事务操作返回值类型\n * @param transacting - 事务执行函数,接收事务数据库实例作为参数\n * @param _mockDatabase - 用于测试的模拟数据库对象\n * @param _mockDbInstance - 用于测试的模拟数据库实例\n * @returns 事务操作的返回结果\n *\n * @example\n * ```typescript\n * const result = await dbTransaction(async (withTransaction) => {\n * const userId = await withTransaction(db.table('user')).create({ name: 'John' });\n * const order = await withTransaction(db.table('orders')).create({ userId, amount: 100 });\n * return { user, order };\n * });\n * ```\n */\nexport async function dbTransaction<K>(\n transacting: (withTransaction: WithTransaction) => Promise<K>,\n // biome-ignore lint/suspicious/noExplicitAny: 单测使用 any\n _mockDatabase?: any,\n // biome-ignore lint/suspicious/noExplicitAny: 单测使用 any\n _mockDbInstance?: any,\n) {\n const transactionDb = (_mockDatabase || uniCloud.database()) as _TransactionDb;\n\n const [err1, transaction] = await tryFlatten(transactionDb.startTransaction());\n if (err1) throw err1;\n\n const withTransaction: WithTransaction = <D1>(db: Db<D1>) => {\n return _mockDbInstance || new Db<D1>({ ...db.options, transaction });\n };\n\n const [err2, result] = await tryFlatten(async () => {\n const result = await transacting(withTransaction);\n await transaction.commit();\n return result;\n });\n\n if (err2) {\n await tryFlatten(transaction.rollback());\n throw err2;\n }\n\n return result as unknown as K;\n}\n","import { isFunction } from '@cloudcome/utils-core/type';\nimport type { Db } from './_db.class';\nimport type { DbCreate, DbQuery, DbUpdate } from './types';\n\nexport type DbUpsertOptions<T, C extends DbCreate<T>, U extends DbUpdate<T>> = {\n /** 创建数据 */\n create: C;\n\n /**\n * 更新数据,可以是对象或根据查询结果生成更新对象的函数\n * @param row 查询到的文档数据,仅在传入函数时可用\n */\n // biome-ignore lint/complexity/noBannedTypes: 必须这么用\n update: U | ((exist: DbQuery<T, {}, {}>) => U);\n\n /** 创建前回调函数 */\n onBeforeCreate?: () => unknown;\n\n /**\n * 创建后回调函数\n * @param id 创建的文档ID\n */\n onAfterCreate?: (id: string) => unknown;\n\n /**\n * 更新前回调函数\n * @param exist 查询到的原始文档数据\n * @returns 如果返回 false,则取消更新操作\n */\n // biome-ignore lint/complexity/noBannedTypes: 必须这么用\n onBeforeUpdate?: (exist: DbQuery<T, {}, {}>) => false | unknown;\n\n /**\n * 更新后回调函数\n * @param updateData 实际更新的数据\n * @param exist 查询到的原始文档数据\n */\n // biome-ignore lint/complexity/noBannedTypes: 必须这么用\n onAfterUpdate?: (updateData: U, exist: DbQuery<T, {}, {}>) => unknown;\n\n /** 用于测试的模拟数据库实例 */\n // biome-ignore lint/suspicious/noExplicitAny: 单测使用 any\n _mockDbInstance?: any;\n};\n\n/**\n * 数据库 upsert 操作的返回结果类型\n */\nexport type DbUpsertOutput = {\n /** 操作的文档ID */\n id: string;\n /** 是否为创建操作 */\n created: boolean;\n /** 是否为更新操作 */\n updated: boolean;\n};\n\nexport async function dbUpsert<D1, C extends DbCreate<D1>, U extends DbUpdate<D1>>(\n db: Db<D1>,\n options: DbUpsertOptions<D1, C, U>,\n): Promise<DbUpsertOutput> {\n const { create, update, onBeforeCreate, onAfterCreate, onBeforeUpdate, onAfterUpdate, _mockDbInstance } = options;\n\n const _mutateDb = (_mockDbInstance || db.clone()) as Db<D1>;\n const _queryDb = (_mockDbInstance || db.clone(true)) as Db<D1>;\n\n const exist = (await _queryDb\n .where(db.getWhere(true))\n // biome-ignore lint/complexity/noBannedTypes: 必须这么用\n .firstOrNull()) as DbQuery<D1, {}, {}> | null;\n\n if (exist) {\n const skipUpdate = (await onBeforeUpdate?.(exist)) === false;\n\n if (skipUpdate) {\n // @ts-expect-error\n return { id: exist._id as string, updated: false, created: false };\n }\n\n const updateData = isFunction(update) ? update(exist) : update;\n // @ts-expect-error\n await _mutateDb.whereId(exist._id).update(updateData);\n onAfterUpdate?.(updateData, exist);\n\n // @ts-expect-error\n return { id: exist._id as string, updated: true, created: false };\n }\n\n await onBeforeCreate?.();\n const createdId = await _mutateDb.create(create);\n await onAfterCreate?.(createdId);\n\n return { id: createdId, updated: false, created: true };\n}\n","import type { Db } from './_db.class';\nimport type { DbCreate } from './types';\nimport { dbUpsert } from './upsert';\n\nexport type DbUniqueOptions<T, C extends DbCreate<T>> = {\n /** 创建数据 */\n create: C;\n\n /** 创建前回调函数 */\n onBeforeCreate?: () => unknown;\n\n /**\n * 创建后回调函数\n * @param id 创建的文档ID\n */\n onAfterCreate?: (id: string) => unknown;\n\n /** 用于测试的模拟数据库实例 */\n // biome-ignore lint/suspicious/noExplicitAny: 单测使用 any\n _mockDbInstance?: any;\n};\n\n/**\n * 数据库 upsert 操作的返回结果类型\n */\nexport type DbUniqueOutput = {\n /** 操作的文档ID */\n id: string;\n /** 是否为创建操作 */\n created: boolean;\n};\n\nexport async function dbUnique<T, C extends DbCreate<T>>(\n db: Db<T>,\n options: DbUniqueOptions<T, C>,\n): Promise<DbUniqueOutput> {\n const { id, created } = await dbUpsert(db, {\n ...options,\n // @ts-expect-error\n update: {},\n onBeforeUpdate: () => false,\n });\n return { id, created };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"database.cjs","names":[],"sources":["../src/database/_command.class.ts","../src/database/command.ts","../src/database/each.ts","../src/database/error.ts","../src/database/paging.ts","../src/database/_db.class.ts","../src/database/proxy.ts","../src/database/transaction.ts","../src/database/upsert.ts","../src/database/unique.ts"],"sourcesContent":["// 设置私有属性和静态方法是避免在 update 的时候提示类属性\n\nexport class DbBaseCommand {\n protected _isQuery = false;\n protected _isMutate = false;\n\n constructor(\n private _command: string,\n private _parameter: unknown,\n private _options?: {\n formatParameter?: (db: UniCloud.Database) => unknown;\n rewriteValue?: (db: UniCloud.Database, parameter: unknown) => unknown;\n },\n ) {}\n\n static getValue(cmd: DbBaseCommand, db: UniCloud.Database) {\n if (cmd._options?.rewriteValue) {\n return cmd._options.rewriteValue(db, cmd._parameter);\n }\n\n return (db.command as unknown as Record<string, (value: unknown) => unknown>)[cmd._command].call(\n db.command,\n cmd._options?.formatParameter?.(db) || cmd._parameter,\n );\n }\n\n static getExpression(cmd: DbBaseCommand, fieldName: string) {\n return {\n [`$${cmd._command}`]: [fieldName, cmd._parameter],\n };\n }\n\n static isQueryCommand(cmd: DbBaseCommand) {\n return cmd._isQuery;\n }\n\n static isMutateCommand(cmd: DbBaseCommand) {\n return cmd._isMutate;\n }\n}\n\nexport class DbQueryCommand extends DbBaseCommand {\n protected _isQuery = true;\n}\n\nexport class DbMutateCommand extends DbBaseCommand {\n protected _isMutate = true;\n}\n","import { DbBaseCommand, DbMutateCommand, DbQueryCommand } from './_command.class';\n\n/**\n * 数据库查询命令对象,提供各种查询操作符\n */\nexport const dbQuery = {\n /**\n * 等于操作符\n * @param value 比较值\n * @returns DbQueryCommand 查询命令对象\n */\n eq: (value: unknown) => new DbQueryCommand('eq', value),\n\n /**\n * 不等于操作符\n * @param value 比较值\n * @returns DbQueryCommand 查询命令对象\n */\n neq: (value: unknown) => new DbQueryCommand('neq', value),\n\n /**\n * 大于操作符\n * @param value 比较值\n * @returns DbQueryCommand 查询命令对象\n */\n gt: (value: unknown) => new DbQueryCommand('gt', value),\n\n /**\n * 大于等于操作符\n * @param value 比较值\n * @returns DbQueryCommand 查询命令对象\n */\n gte: (value: unknown) => new DbQueryCommand('gte', value),\n\n /**\n * 小于操作符\n * @param value 比较值\n * @returns DbQueryCommand 查询命令对象\n */\n lt: (value: unknown) => new DbQueryCommand('lt', value),\n\n /**\n * 小于等于操作符\n * @param value 比较值\n * @returns DbQueryCommand 查询命令对象\n */\n lte: (value: unknown) => new DbQueryCommand('lte', value),\n\n /**\n * 包含在数组中操作符\n * @param value 值数组\n * @returns DbQueryCommand 查询命令对象\n */\n in: (value: unknown[]) => new DbQueryCommand('in', value),\n\n /**\n * 不包含在数组中操作符\n * @param value 值数组\n * @returns DbQueryCommand 查询命令对象\n */\n nin: (value: unknown[]) => new DbQueryCommand('nin', value),\n\n /**\n * 数组长度匹配操作符\n * @param size 数组长度\n * @returns DbQueryCommand 查询命令对象\n */\n size: (size: number) => new DbQueryCommand('size', size),\n\n /**\n * 正则表达式匹配操作符\n * @param regExp 正则表达式\n * @returns DbQueryCommand 查询命令对象\n */\n regExp: (regExp: RegExp) =>\n new DbQueryCommand('regExp', regExp, {\n rewriteValue: (_db, parameter) => parameter,\n }),\n\n /**\n * 逻辑与操作符\n * @param conditions 查询条件参数\n * @returns DbQueryCommand 查询命令对象\n */\n and: (conditions: DbQueryCommand[]) =>\n new DbQueryCommand('and', conditions, {\n formatParameter: (db) => conditions.map((c) => DbBaseCommand.getValue(c, db)),\n }),\n\n /**\n * 逻辑或操作符\n * @param conditions 查询条件参数\n * @returns DbQueryCommand 查询命令对象\n */\n or: (conditions: DbQueryCommand[]) =>\n new DbQueryCommand('or', conditions, {\n formatParameter: (db) => conditions.map((c) => DbBaseCommand.getValue(c, db)),\n }),\n};\n\n/**\n * 数据库变更命令对象,提供各种数据更新操作符\n */\nexport const dbMutate = {\n /**\n * 数值增加操作符\n * @param value 增加的数值\n * @returns DbMutateCommand 变更命令对象\n */\n inc: (value: number) => new DbMutateCommand('inc', value),\n\n /**\n * 数值乘法操作符\n * @param value 乘数\n * @returns DbMutateCommand 变更命令对象\n */\n mul: (value: number) => new DbMutateCommand('mul', value),\n\n /**\n * 设置字段值操作符\n * @param value 设置的值\n * @returns DbMutateCommand 变更命令对象\n */\n set: (value: unknown) => new DbMutateCommand('set', value),\n\n /**\n * 向数组末尾添加元素操作符\n * @param value 添加的值\n * @returns DbMutateCommand 变更命令对象\n */\n push: (value: unknown) => new DbMutateCommand('push', value),\n\n /**\n * 向数组开头添加元素操作符\n * @param value 添加的值\n * @returns DbMutateCommand 变更命令对象\n */\n unshift: (value: unknown) => new DbMutateCommand('unshift', value),\n\n /**\n * 从数组末尾移除元素操作符\n * @returns DbMutateCommand 变更命令对象\n */\n pop: () => new DbMutateCommand('pop', undefined),\n\n /**\n * 从数组开头移除元素操作符\n * @returns DbMutateCommand 变更命令对象\n */\n shift: () => new DbMutateCommand('shift', undefined),\n\n /**\n * 移除字段操作符\n * @returns DbMutateCommand 变更命令对象\n */\n remove: () => new DbMutateCommand('remove', undefined),\n};\n","import type { Db } from './_db.class';\nimport type { DbWhere } from './types';\n\n/**\n * 遍历表中的每一行数据并执行回调函数\n *\n * 采用分批查询策略,每批查询 100 条记录,通过 skip/limit 实现分页遍历,\n * 避免一次性加载大量数据导致内存溢出。\n *\n * 迭代器按顺序串行执行,即每一行数据的迭代器完成后才会处理下一行。\n *\n * @template T - 数据行类型\n * @param table 数据库表代理对象\n * @param where 查询条件\n * @param iterator 对每一行数据执行的异步迭代器函数\n * @param maxCount 最大遍历数量,默认值为 Number.MAX_SAFE_INTEGER。\n * 注意:由于分批查询机制(每批 100 条),实际遍历的行数可能略大于 maxCount,\n * 例如 maxCount=150 时,会分两批查询(0-99、100-199),实际遍历 200 行。\n * @example\n * ```ts\n * // 遍历所有状态为 active 的用户\n * await dbEach(userTable, { status: 'active' }, async (user) => {\n * await sendEmail(user.email);\n * });\n *\n * // 限制最多遍历 500 条记录\n * await dbEach(orderTable, { status: 'pending' }, async (order) => {\n * await processOrder(order);\n * }, 500);\n * ```\n */\nexport async function dbEach<T>(\n table: Db<T>,\n where: DbWhere<T>,\n iterator: (row: T) => Promise<unknown>,\n maxCount = Number.MAX_SAFE_INTEGER,\n) {\n const count = Math.min(await table.where(where).count(), maxCount);\n const limit = 100;\n\n for (let skip = 0; skip < count; skip += limit) {\n const rows = await table.where(where).limit(limit).skip(skip).many();\n\n for (const row of rows) {\n await iterator(row as T);\n }\n }\n}\n","/**\n * 数据库底层异常类\n * 当 uniCloud 数据库操作抛出错误时,统一包装为该异常\n */\nexport class DbError extends Error {\n /** 原始错误码,如 'InternalServerError' */\n errCode: string | number;\n /** MongoDB 错误码,如 'E11000'。不匹配则为空字符串 */\n dbCode: string;\n\n constructor(message: string, extra: { errCode: string | number; dbCode: string }) {\n super(message);\n this.name = 'DbError';\n this.errCode = extra.errCode;\n this.dbCode = extra.dbCode;\n }\n}\n\n/**\n * 判断错误是否为数据库底层错误\n * @param err - 任意错误对象\n * @returns 是否为 DbError\n */\nexport function isDbError(err: unknown): err is DbError {\n return err instanceof DbError;\n}\n\n/**\n * 从 MongoDB 错误消息中提取错误码\n * @param errMsg - 错误消息字符串,如 'E11000 duplicate key error...'\n * @returns MongoDB 错误码,如 'E11000'\n */\nexport function extractMongoCode(errMsg: string): string {\n const m = errMsg.match(/^E\\d+/);\n return m ? m[0] : '';\n}\n","import type { AnyObject } from '@cloudcome/utils-core/types';\nimport type { Db } from './_db.class';\nimport type { DbSelect } from './types';\n\n/**\n * 数据库分页查询函数\n * @template T - 数据类型\n * @param queryDb - 数据库查询实例\n * @returns 包含数据列表和总数的对象\n */\n\nexport async function dbPaging<\n D1,\n // biome-ignore lint/complexity/noBannedTypes: 必须这么用\n S1 extends DbSelect<D1> = {},\n // biome-ignore lint/complexity/noBannedTypes: 必须这么用\n D2 extends AnyObject = {},\n // biome-ignore lint/complexity/noBannedTypes: 必须这么用\n W2 extends AnyObject = {},\n>(queryDb: Db<D1, S1, D2, W2>) {\n // 获取原始查询条件,不包映射字段\n const where = queryDb.getWhere(true);\n\n // 克隆查询实例用于统计总数,避免影响原查询\n const countDb = queryDb.clone();\n\n // 执行查询获取数据列表\n const list = await queryDb.many();\n\n // 基于相同查询条件统计总数\n const total = await countDb.where(where).count();\n\n // 返回分页结果\n return {\n list,\n total,\n };\n}\n","import { isUniError, parseDatabaseOutput } from '@/_helpers';\nimport type { UniError } from '@/_types';\nimport { createCloudObjectError } from '@/cloud';\nimport { objectEach, objectFilter, objectMap, objectOmit } from '@cloudcome/utils-core/object';\nimport { isArray, isObject } from '@cloudcome/utils-core/type';\nimport type { AnyObject, MergeIntersection } from '@cloudcome/utils-core/types';\nimport { DbBaseCommand, type DbQueryCommand } from './_command.class';\nimport { DbError, extractMongoCode } from './error';\nimport type { DbCreate, DbForeign, DbOrder, DbQuery, DbRelation, DbSelect, DbUpdate, DbWhere } from './types';\n\n/**\n * 数据库聚合操作符命令\n */\nconst dbAgg = uniCloud.database().command.aggregate as UniCloud.AggregateCommand & {\n pipeline: () => UniCloud.AggregateReference & {\n done: () => unknown;\n };\n};\n\nconst db0 = uniCloud.database();\n\nexport type DbOptions = {\n /**\n * 数据表名称\n */\n table: string;\n\n /**\n * 事务对象,用于事务操作\n */\n // biome-ignore lint/suspicious/noExplicitAny: 必须这么用\n transaction?: any;\n\n /**\n * 模拟数据库,用于单元测试\n */\n // biome-ignore lint/suspicious/noExplicitAny: 单测使用 any\n _mockDatabase?: any;\n\n /**\n * 自定义错误处理函数\n * @param error unknown 数据库异常对象\n * @returns 自定义错误对象\n */\n parseError?: (error: unknown) => UniError;\n};\n\nexport type DbLookupOptions<\n RL extends DbRelation,\n D1,\n FD1,\n AS,\n // biome-ignore lint/suspicious/noConfusingVoidType: 必须这么用\n US extends boolean | undefined | void = undefined,\n LF extends keyof D1 & string = keyof D1 & string,\n> = {\n /**\n * 关联类型\n */\n relation: RL;\n\n /**\n * 主表字段\n */\n localField: LF;\n\n /**\n * 关联表字段\n */\n foreignField: keyof FD1 & string;\n\n /**\n * 关联数据在结果中的字段名\n */\n as: AS;\n\n /**\n * 是否取消筛选关联数据\n */\n unselect?: US;\n};\n\nexport type DbLookup = DbLookupOptions<\n // biome-ignore lint/suspicious/noExplicitAny: 必须这么用\n any,\n unknown,\n unknown,\n string,\n boolean\n> & {\n /**\n * 关联表\n */\n table: Db<unknown>;\n};\n\nlet gid = 0;\n\n/**\n * 数据库类\n * @template D1 - 主表数据\n * @template S1 - 主表筛选\n * @template D2 - 副表数据\n * @template W2 - 副表查询\n */\nexport class Db<\n D1,\n // biome-ignore lint/complexity/noBannedTypes: 必须这么用\n S1 extends DbSelect<D1> = {},\n // biome-ignore lint/complexity/noBannedTypes: 必须这么用\n D2 extends AnyObject = {},\n // biome-ignore lint/complexity/noBannedTypes: 必须这么用\n W2 extends AnyObject = {},\n> {\n /**\n * 是否为事务环境\n * - 更新条件只能是 id\n * - 删除条件只能是 id\n */\n private _isTransaction = false;\n\n private _options: DbOptions;\n\n /**\n * 构造函数,初始化数据库集合引用\n * @param collection 数据表名称\n * @param _mockDatabase 模拟数据库,用于单元测试\n */\n constructor(options: DbOptions) {\n this._options = options;\n // hostRef =\n // options._mockDatabase || options.transaction?.collection(options.table) || db0.collection(options.table);\n this._isTransaction = !!options.transaction;\n }\n\n /**\n * 创建一个新的数据库实例,可选是否移除事务\n * @param withoutTransaction 是否移除事务,默认 false\n * @returns 新的数据库实例\n */\n clone(withoutTransaction?: boolean) {\n return new Db({\n ...this._options,\n transaction: withoutTransaction ? null : this._options.transaction,\n });\n }\n\n get table() {\n return this._options.table;\n }\n\n get options() {\n return this._options;\n }\n\n get isTransaction() {\n return this._isTransaction;\n }\n\n _createHost(withoutTransaction?: boolean) {\n const options = this._options;\n return (\n options._mockDatabase ||\n (withoutTransaction ? null : options.transaction?.collection(options.table) || db0.collection(options.table))\n );\n }\n\n /**\n * 获取聚合操作实例\n * @returns 聚合操作实例\n */\n _createAggregate() {\n const host = this._createHost();\n return host.aggregate();\n }\n\n private _hasWhere = false;\n private _hasWhereId = false;\n private _where = {};\n\n /**\n * 设置查询条件\n * @param where 查询条件对象\n * @returns 当前Db实例,支持链式调用\n */\n where(where: DbWhere<D1> & W2) {\n if (this._isTransaction) throw new Error('事务模式下请使用 whereId() 方法');\n if (this._hasWhere) throw new Error('已调用过一次 db.where({...}) 或 db.whereId(id) 了');\n\n // 过滤掉值为 undefined 的键值对,数据库不支持查询全 undefined 值\n const realWhere = objectFilter(where, (value) => value !== undefined);\n\n this._hasWhere = true;\n this._where = realWhere;\n\n return this;\n }\n\n /**\n * 获取当前查询条件\n * @param plain 是否返回原始查询条件对象,默认 false\n * @returns 当前查询条件对象\n */\n getWhere(plain?: boolean) {\n return plain\n ? // biome-ignore lint/suspicious/noTsIgnore: 必须这么用\n // @ts-ignore\n objectOmit(this._where, Object.keys(this._lookupAs))\n : this._where;\n }\n\n /**\n * 根据ID设置查询条件\n * @param id 记录ID\n * @returns 当前Db实例,支持链式调用\n */\n whereId(id: string | number) {\n if (this._hasWhere) throw new Error('已调用过一次 db.where({...}) 或 db.whereId(id) 了');\n if (this._hasLimit) throw new Error('db.whereId(id) 方法不能与 db.limit() 方法同时调用');\n\n this._hasWhere = true;\n this._hasWhereId = true;\n this._where = { _id: id };\n\n return this;\n }\n\n private _hasSelect = 0;\n private _select = {};\n\n /**\n * 指定要返回的字段\n * @param fields 要返回的字段对象,true表示返回,false表示不返回\n * @returns 当前Db实例,支持链式调用\n */\n select<const S extends DbSelect<D1>>(fields: S) {\n if (this._hasSelect) throw new Error('db.select() 方法只能调用一次');\n\n this._hasSelect++;\n this._select = fields;\n\n return this as Db<D1, S, D2, W2>;\n }\n\n private _hasOrder = 0;\n private _order = {};\n\n /**\n * 设置排序规则\n * @param order 排序规则对象,key为字段名,value为\"asc\"或\"desc\"\n * @returns 当前Db实例,支持链式调用\n */\n order(order: DbOrder<D1>) {\n if (this._isTransaction) throw new Error('db.order() 方法不支持事务模式');\n\n this._hasOrder++;\n this._order = order;\n\n return this;\n }\n\n private _hasSkip = 0;\n private _skip = 0;\n\n /**\n * 跳过指定数量的记录\n * @param skip 要跳过的记录数\n * @returns 当前Db实例,支持链式调用\n */\n skip(skip: number) {\n if (this._isTransaction) throw new Error('db.skip() 方法不支持事务模式');\n if (this._hasSkip) throw new Error('db.skip() 方法只能调用一次');\n\n this._hasSkip++;\n this._skip = skip;\n\n return this;\n }\n\n private _hasLimit = 0;\n private _limit = 0;\n\n /**\n * 限制返回的记录数量\n * @param limit 最大返回记录数\n * @returns 当前Db实例,支持链式调用\n */\n limit(limit: number) {\n if (this._isTransaction) throw new Error('db.limit() 方法不支持事务模式');\n if (this._hasLimit) throw new Error('db.limit() 方法只能调用一次');\n if (this._hasSample) throw new Error('db.limit() 方法不支持 sample 条件');\n\n if (this._hasWhereId) {\n throw new Error('db.limit() 方法不能与 db.whereId(id) 方法同时调用');\n }\n\n this._hasLimit++;\n this._limit = limit;\n\n return this;\n }\n\n private _hasSample = 0;\n private _sampleSize = 0;\n\n /**\n * 随机从文档中选取指定数量的记录\n * @param size 要选取的记录数量,必须为正整数\n * @returns 当前Db实例,支持链式调用\n */\n sample(size: number) {\n if (this._isTransaction) throw new Error('db.sample() 方法不支持事务模式');\n if (this._hasSample) throw new Error('db.sample() 方法只能调用一次');\n if (this._hasLimit) throw new Error('db.sample() 方法不支持 limit 条件');\n\n this._hasSample++;\n this._sampleSize = size;\n\n return this;\n }\n\n private _hasLookup = 0;\n get hasLookup() {\n return this._hasLookup > 0;\n }\n\n private _lookups: DbLookup[] = [];\n lookup<\n FD1,\n FS1 extends DbSelect<FD1>,\n FD2 extends AnyObject,\n FW2 extends AnyObject,\n RL extends DbRelation,\n AS extends string,\n // biome-ignore lint/suspicious/noConfusingVoidType: 必须这么用\n US extends boolean | undefined | void = undefined,\n LF extends keyof D1 & string = keyof D1 & string,\n >(table: Db<FD1, FS1, FD2, FW2>, lookup: DbLookupOptions<RL, D1, FD1, AS, US, LF>) {\n if (this._isTransaction) throw new Error('db.lookup() 方法不支持事务模式');\n\n // 对方表也记为关联查询,避免做表更新操作\n table._hasLookup++;\n this._hasLookup++;\n this._lookups.push({\n ...lookup,\n table,\n } as unknown as DbLookup);\n\n // @ts-expect-error\n return this as Db<\n D1,\n S1,\n US extends true ? D2 : MergeIntersection<D2 & DbForeign<D1, FD1, FS1, FD2, RL, AS, LF>>,\n MergeIntersection<W2 & Partial<Record<AS, DbQueryCommand>>>\n >;\n }\n\n private _ending = false;\n\n private _aggregated = false;\n private _lookupAs = {} as Record<string, true>;\n private _endAggregate(aggRef: UniCloud.AggregateReference) {\n if (this._aggregated) throw new Error(`相同的数据表实例(${this.table})不能重复使用`);\n if (this._ending) throw new Error(`相同的数据表实例(${this.table})不能重复使用`);\n\n this._ending = true;\n this._aggregated = true;\n let returnAggRef = aggRef;\n let _hasAggSelect = 0;\n const aggSelect = {} as Record<string, true>;\n let hasAggUnselect = 0;\n const aggUnselect = {} as Record<string, false>;\n\n // 后做关联查询\n for (const { relation: type, as, foreignField, localField, table, unselect } of this._lookups) {\n const letName = `let${gid++}`;\n let pipeline = dbAgg.pipeline();\n\n // 关联条件\n // @ts-expect-error\n pipeline = pipeline.match({\n $expr: {\n $and: [\n type === 'n:1'\n ? { $in: [`$${foreignField}`, `$$${letName}`] }\n : { $eq: [`$${foreignField}`, `$$${letName}`] },\n ],\n },\n });\n\n // 其他查询条件\n // @ts-expect-error\n pipeline = table._endAggregate(pipeline);\n\n // @ts-expect-error\n pipeline = pipeline.done();\n\n returnAggRef = returnAggRef.lookup({\n let: {\n [letName]: `$${localField}`,\n },\n as,\n from: table.table,\n pipeline,\n });\n\n // 1对1,展开数组\n if (type === '1:1') {\n // @ts-expect-error\n returnAggRef = returnAggRef.unwind({\n path: `$${as}`,\n preserveNullAndEmptyArrays: true,\n });\n }\n\n if (unselect) {\n hasAggUnselect++;\n aggUnselect[as] = false;\n } else {\n _hasAggSelect++;\n aggSelect[as] = true;\n }\n\n this._lookupAs[as] = true;\n }\n\n // 主表查询,注意顺序,筛选->排序->跳过->限制\n if (this._hasWhere) returnAggRef = returnAggRef.match(_mapCommandRaw(this._where));\n if (this._hasSample) returnAggRef = returnAggRef.sample({ size: this._sampleSize });\n if (this._hasOrder) returnAggRef = returnAggRef.sort(objectMap(this._order, (v) => (v === 'asc' ? 1 : -1)));\n if (this._hasSkip) returnAggRef = returnAggRef.skip(this._skip);\n if (this._hasLimit) returnAggRef = returnAggRef.limit(this._limit);\n\n // 如果主表有选择字段,则合并选择字段(包括关联查询的字段和排序字段)\n if (this._hasSelect) {\n returnAggRef = returnAggRef.project(_mergeSelect({ ...this._select, ...aggSelect }, this._order));\n }\n // 如果主表没有选择字段,则排除取消选择字段\n else if (hasAggUnselect) {\n returnAggRef = returnAggRef.project(aggUnselect);\n }\n\n return returnAggRef;\n }\n\n private _endHost(host: UniCloud.CollectionReference, action: 'query' | 'create' | 'update' | 'remove' | 'count') {\n if (this._ending) throw new Error(`相同的数据表实例(${this.table})不能重复使用`);\n this._ending = true;\n\n // 事务模式下:查询/更新/删除必须使用 whereId\n if (\n this._isTransaction &&\n (action === 'query' || action === 'update' || action === 'remove') &&\n !this._hasWhereId\n ) {\n throw new Error('事务模式下查询/更新/删除条件只能是 ID,请使用 whereId() 方法');\n }\n\n let hostRef = host;\n if (this._hasWhere) {\n // 事务模式下:更新/删除/查询只能用 doc(id)\n if (this._isTransaction && (action === 'update' || action === 'remove' || action === 'query')) {\n // @ts-expect-error\n hostRef = hostRef.doc(this._where._id);\n } else {\n // @ts-expect-error\n hostRef = hostRef.where(_mapCommandRaw(this._where));\n }\n }\n\n if (this._hasSelect) {\n // @ts-expect-error\n hostRef = hostRef.field(_mergeSelect(this._select, this._order));\n }\n\n if (this._hasOrder) {\n objectEach(this._order, (val, key) => {\n // @ts-expect-error\n hostRef = hostRef.orderBy(key, val);\n });\n }\n\n // @ts-expect-error\n if (this._hasSkip) hostRef = hostRef.skip(this._skip);\n\n if (this._hasLimit && action === 'query')\n // @ts-expect-error\n hostRef = hostRef.limit(this._limit);\n else if (this._hasWhereId && action === 'query' && !this._isTransaction)\n // @ts-expect-error\n hostRef = hostRef.limit(1);\n\n return hostRef;\n }\n\n /**\n * 将 uniCloud 数据库原始错误包装为 DbError\n * @param err - 原始错误对象,来自 uniCloud DB 操作(Error 实例,含 errMsg、errCode 属性)\n * @returns DbError 实例\n */\n private _parseDbError(err: UniError) {\n const errCode = err.errCode || '';\n const message = err.errMsg || err.message;\n const dbCode = extractMongoCode(err.errMsg || err.message);\n\n if (dbCode) {\n return new DbError(message, {\n errCode: errCode,\n dbCode: dbCode,\n });\n } else {\n return err;\n }\n }\n\n /**\n * 统一处理 DB 操作抛出的错误\n * - uniCloud 数据库错误(含 errMsg)→ 包装为 DbError → 经 parseError 回调后抛出\n * - 非数据库错误(如网络中断)→ 原样抛出\n */\n private _handleDbError(err: unknown): never {\n if (isUniError(err)) {\n const dbErr = this._parseDbError(err);\n throw this._options.parseError?.(dbErr) || dbErr;\n } else {\n throw this._options.parseError?.(err) || err;\n }\n }\n\n /**\n * 执行查询操作\n * @returns 查询结果\n */\n async many() {\n try {\n let res: { data: DbQuery<D1, S1, D2>[] | DbQuery<D1, S1, D2> | undefined };\n\n // 事务模式下不支持聚合查询\n if (this._isTransaction && (this._hasLookup || this._hasSample)) {\n throw new Error('事务模式下不支持 lookup 聚合或 sample 取样查询');\n }\n\n // 关联查询 / sample 查询(sample 依赖聚合管线)\n if (this._hasLookup || this._hasSample) {\n let aggRef = this._createAggregate();\n aggRef = this._endAggregate(aggRef);\n res = await aggRef.end();\n }\n // 单表查询\n else {\n let hostRef = this._createHost();\n hostRef = this._endHost(hostRef, 'query');\n res = await hostRef.get();\n }\n\n const { data } = parseDatabaseOutput(res);\n\n // doc(id).get() 返回单个对象或 undefined,需包装为数组以统一 many() 返回值\n return isArray(data) ? data : data ? [data] : [];\n } catch (err) {\n this._handleDbError(err);\n }\n }\n\n /**\n * 只查询一条,自动添加 limit(1) 条件\n * 如果没有匹配到记录,会抛出错误\n * @returns 查询结果\n */\n async firstOrThrow(): Promise<DbQuery<D1, S1, D2>> {\n if (this._hasLimit) throw new Error('db.firstOrThrow() 方法不支持 limit 条件');\n if (!this._hasWhereId && !this._hasSample) this.limit(1);\n\n const data = await this.many();\n const res = data.at(0);\n\n if (!res) throw createCloudObjectError('查询数据为空', 'firstOrThrow');\n return res;\n }\n\n /**\n * 只查询一条,自动添加 limit(1) 条件\n * 如果没有匹配到记录,返回 null\n * @returns 查询结果或 null\n */\n async firstOrNull(): Promise<DbQuery<D1, S1, D2> | null> {\n if (this._hasLimit) throw new Error('db.firstOrNull() 方法不支持 limit 条件');\n if (!this._hasWhereId && !this._hasSample) this.limit(1);\n\n const data = await this.many();\n return data.at(0) || null;\n }\n\n /**\n * 获取匹配记录的数量\n * @returns 记录总数\n */\n async count() {\n if (this._isTransaction) throw new Error('db.count() 方法不支持事务模式');\n if (this._hasSample) throw new Error('db.count() 方法不支持 sample 取样');\n if (this._hasLookup) throw new Error('db.count() 方法不支持 lookup 聚合');\n if (this._hasSelect) throw new Error('db.count() 方法不支持 select 条件');\n if (this._hasOrder) throw new Error('db.count() 方法不支持 order 条件');\n if (this._hasSkip) throw new Error('db.count() 方法不支持 skip 条件');\n if (this._hasLimit) throw new Error('db.count() 方法不支持 limit 条件');\n\n try {\n let hostRef = this._createHost();\n hostRef = this._endHost(hostRef, 'count');\n const res = await hostRef.count();\n const { total } = parseDatabaseOutput<{ total: number }>(res);\n return total;\n } catch (err) {\n this._handleDbError(err);\n }\n }\n\n /**\n * 创建新记录\n * @param data 要创建的数据\n * @returns 创建结果\n */\n async create(data: DbCreate<D1>) {\n if (this._hasLookup) throw new Error('db.create() 方法不支持 lookup 聚合');\n if (this._hasWhere) throw new Error('db.create() 方法不支持 where 条件');\n if (this._hasSelect) throw new Error('db.create() 方法不支持 select 条件');\n if (this._hasOrder) throw new Error('db.create() 方法不支持 order 条件');\n if (this._hasSkip) throw new Error('db.create() 方法不支持 skip 条件');\n if (this._hasLimit) throw new Error('db.create() 方法不支持 limit 条件');\n\n try {\n let hostRef = this._createHost();\n hostRef = this._endHost(hostRef, 'create');\n const res = await hostRef.add(data);\n const { id } = parseDatabaseOutput<{ id: string }>(res);\n return id;\n } catch (err) {\n this._handleDbError(err);\n }\n }\n\n /**\n * 更新记录\n * @param data 要更新的数据\n * @returns 更新结果\n */\n async update(data: DbUpdate<D1>) {\n if (this._hasLookup) throw new Error('db.update() 方法不支持 lookup 聚合');\n if (!this._hasWhere) throw new Error('设置 where 条件后才能执行 db.update() 方法');\n if (this._hasSelect) throw new Error('db.update() 方法不支持 select 条件');\n if (this._hasOrder) throw new Error('db.update() 方法不支持 order 条件');\n if (this._hasSkip) throw new Error('db.update() 方法不支持 skip 条件');\n if (this._hasLimit) throw new Error('db.update() 方法不支持 limit 条件');\n\n if (this._isTransaction && !this._hasWhereId) throw new Error('事务模式下 db.update() 的 where 条件必须是 _id');\n\n try {\n let hostRef = this._createHost();\n hostRef = this._endHost(hostRef, 'update');\n const res = await hostRef.update(objectOmit(_mapCommandRaw(data), ['_id']));\n const { updated } = parseDatabaseOutput<{ updated: number }>(res);\n return updated;\n } catch (err) {\n this._handleDbError(err);\n }\n }\n\n /**\n * 删除记录\n * @returns 删除结果\n */\n async remove() {\n if (this._hasLookup) throw new Error('db.remove() 方法不支持 lookup 聚合');\n if (!this._hasWhere) throw new Error('设置 where 条件后才能执行 db.remove() 方法');\n if (this._hasSelect) throw new Error('db.remove() 方法不支持 select 条件');\n if (this._hasOrder) throw new Error('db.remove() 方法不支持 order 条件');\n if (this._hasSkip) throw new Error('db.remove() 方法不支持 skip 条件');\n if (this._hasLimit) throw new Error('db.remove() 方法不支持 limit 条件');\n\n if (this._isTransaction && !this._hasWhereId) throw new Error('事务模式下 db.remove() 的 where 条件必须是 _id');\n\n try {\n let hostRef = this._createHost();\n hostRef = this._endHost(hostRef, 'remove');\n const res = await hostRef.remove();\n const { deleted } = parseDatabaseOutput<{ deleted: number }>(res);\n return deleted;\n } catch (err) {\n this._handleDbError(err);\n }\n }\n}\n\n// biome-ignore lint/suspicious/noExplicitAny: 必须这么用\nfunction _mapCommandRaw(data: any) {\n // biome-ignore lint/suspicious/noExplicitAny: 必须这么用\n const map = (val: any): any => {\n if (!isObject(val)) return val;\n if (val instanceof DbBaseCommand) return DbBaseCommand.getValue(val, db0);\n return objectMap(val, map);\n };\n\n return objectMap(data, map);\n}\n\nfunction _mapOrderSelect(order: DbOrder<unknown>) {\n return objectMap(order, (_val, _key) => true);\n}\n\nfunction _mergeSelect(select: DbSelect<unknown>, order: DbOrder<unknown>) {\n const noSelect = Object.keys(select).length === 0;\n // 如果没有 select 条件,默认返回所有字段\n if (noSelect) return select;\n\n const onlyOmitId = Object.keys(select).length === 1 && '_id' in select && select._id === false;\n // 如果只排除 _id 字段,则保持现状\n if (onlyOmitId) return select;\n\n return {\n ...select,\n ..._mapOrderSelect(order),\n };\n}\n","import { isFunction } from '@cloudcome/utils-core/type';\nimport { Db } from './_db.class';\nimport type { DbSelect } from './types';\nimport type { UniError } from '@/_types';\n\nexport type DbProxyOptions = {\n /**\n * 自定义错误处理函数\n * @param error unknown 数据库异常对象\n * @returns 自定义错误对象\n */\n parseError?: (error: unknown) => UniError;\n};\n\n/**\n * 创建一个数据库代理对象,用于延迟实例化数据库操作类\n * @template D1 - 主表数据\n * @template S1 - 主表筛选\n * @param name - 数据库表名\n * @returns 返回一个代理对象,该对象会将属性访问转发到实际的数据库操作实例\n */\n\n// biome-ignore lint/complexity/noBannedTypes: 必须这么用\nexport function dbProxy<D1, S1 extends DbSelect<D1> = {}>(name: string, options?: DbProxyOptions) {\n return new Proxy(\n {},\n {\n get(_target, prop) {\n if (prop === '_isProxy') return true;\n\n const table = new Db<D1, S1>({ table: name, ...options });\n const tableProp = prop as keyof Db<D1, S1>;\n const ref = table[tableProp];\n\n return isFunction(ref) ? ref.bind(table) : ref;\n },\n },\n ) as Db<D1, S1>;\n}\n","import { tryFlatten } from '@cloudcome/utils-core/try';\nimport { Db } from './_db.class';\n\ntype _TransactionDb = {\n startTransaction: () => Promise<_Transaction>;\n};\n\ntype _Transaction = {\n commit: () => Promise<unknown>;\n rollback: () => Promise<unknown>;\n};\n\nexport type WithTransaction = <D1>(db: Db<D1>) => Db<D1>;\n\n/**\n * 在数据库事务中执行操作\n *\n * @template K - 事务操作返回值类型\n * @param transacting - 事务执行函数,接收事务数据库实例作为参数\n * @param _mockDatabase - 用于测试的模拟数据库对象\n * @param _mockDbInstance - 用于测试的模拟数据库实例\n * @returns 事务操作的返回结果\n *\n * @example\n * ```typescript\n * const result = await dbTransaction(async (withTransaction) => {\n * const userId = await withTransaction(db.table('user')).create({ name: 'John' });\n * const order = await withTransaction(db.table('orders')).create({ userId, amount: 100 });\n * return { user, order };\n * });\n * ```\n */\nexport async function dbTransaction<K>(\n transacting: (withTransaction: WithTransaction) => Promise<K>,\n // biome-ignore lint/suspicious/noExplicitAny: 单测使用 any\n _mockDatabase?: any,\n // biome-ignore lint/suspicious/noExplicitAny: 单测使用 any\n _mockDbInstance?: any,\n) {\n const transactionDb = (_mockDatabase || uniCloud.database()) as _TransactionDb;\n\n const [err1, transaction] = await tryFlatten(transactionDb.startTransaction());\n if (err1) throw err1;\n\n const withTransaction: WithTransaction = <D1>(db: Db<D1>) => {\n return _mockDbInstance || new Db<D1>({ ...db.options, transaction });\n };\n\n const [err2, result] = await tryFlatten(async () => {\n const result = await transacting(withTransaction);\n await transaction.commit();\n return result;\n });\n\n if (err2) {\n await tryFlatten(transaction.rollback());\n throw err2;\n }\n\n return result as unknown as K;\n}\n","import { isFunction } from '@cloudcome/utils-core/type';\nimport type { Db } from './_db.class';\nimport type { DbCreate, DbQuery, DbUpdate } from './types';\n\nexport type DbUpsertOptions<T, C extends DbCreate<T>, U extends DbUpdate<T>> = {\n /** 创建数据 */\n create: C;\n\n /**\n * 更新数据,可以是对象或根据查询结果生成更新对象的函数\n * @param row 查询到的文档数据,仅在传入函数时可用\n */\n // biome-ignore lint/complexity/noBannedTypes: 必须这么用\n update: U | ((exist: DbQuery<T, {}, {}>) => U);\n\n /** 创建前回调函数 */\n onBeforeCreate?: () => unknown;\n\n /**\n * 创建后回调函数\n * @param id 创建的文档ID\n */\n onAfterCreate?: (id: string) => unknown;\n\n /**\n * 更新前回调函数\n * @param exist 查询到的原始文档数据\n * @returns 如果返回 false,则取消更新操作\n */\n // biome-ignore lint/complexity/noBannedTypes: 必须这么用\n onBeforeUpdate?: (exist: DbQuery<T, {}, {}>) => false | unknown;\n\n /**\n * 更新后回调函数\n * @param updateData 实际更新的数据\n * @param exist 查询到的原始文档数据\n */\n // biome-ignore lint/complexity/noBannedTypes: 必须这么用\n onAfterUpdate?: (updateData: U, exist: DbQuery<T, {}, {}>) => unknown;\n\n /** 用于测试的模拟数据库实例 */\n // biome-ignore lint/suspicious/noExplicitAny: 单测使用 any\n _mockDbInstance?: any;\n};\n\n/**\n * 数据库 upsert 操作的返回结果类型\n */\nexport type DbUpsertOutput = {\n /** 操作的文档ID */\n id: string;\n /** 是否为创建操作 */\n created: boolean;\n /** 是否为更新操作 */\n updated: boolean;\n};\n\nexport async function dbUpsert<D1, C extends DbCreate<D1>, U extends DbUpdate<D1>>(\n db: Db<D1>,\n options: DbUpsertOptions<D1, C, U>,\n): Promise<DbUpsertOutput> {\n const { create, update, onBeforeCreate, onAfterCreate, onBeforeUpdate, onAfterUpdate, _mockDbInstance } = options;\n\n const _mutateDb = (_mockDbInstance || db.clone()) as Db<D1>;\n const _queryDb = (_mockDbInstance || db.clone(true)) as Db<D1>;\n\n const exist = (await _queryDb\n .where(db.getWhere(true))\n // biome-ignore lint/complexity/noBannedTypes: 必须这么用\n .firstOrNull()) as DbQuery<D1, {}, {}> | null;\n\n if (exist) {\n const skipUpdate = (await onBeforeUpdate?.(exist)) === false;\n\n if (skipUpdate) {\n // @ts-expect-error\n return { id: exist._id as string, updated: false, created: false };\n }\n\n const updateData = isFunction(update) ? update(exist) : update;\n // @ts-expect-error\n await _mutateDb.whereId(exist._id).update(updateData);\n onAfterUpdate?.(updateData, exist);\n\n // @ts-expect-error\n return { id: exist._id as string, updated: true, created: false };\n }\n\n await onBeforeCreate?.();\n const createdId = await _mutateDb.create(create);\n await onAfterCreate?.(createdId);\n\n return { id: createdId, updated: false, created: true };\n}\n","import type { Db } from './_db.class';\nimport type { DbCreate } from './types';\nimport { dbUpsert } from './upsert';\n\nexport type DbUniqueOptions<T, C extends DbCreate<T>> = {\n /** 创建数据 */\n create: C;\n\n /** 创建前回调函数 */\n onBeforeCreate?: () => unknown;\n\n /**\n * 创建后回调函数\n * @param id 创建的文档ID\n */\n onAfterCreate?: (id: string) => unknown;\n\n /** 用于测试的模拟数据库实例 */\n // biome-ignore lint/suspicious/noExplicitAny: 单测使用 any\n _mockDbInstance?: any;\n};\n\n/**\n * 数据库 upsert 操作的返回结果类型\n */\nexport type DbUniqueOutput = {\n /** 操作的文档ID */\n id: string;\n /** 是否为创建操作 */\n created: boolean;\n};\n\nexport async function dbUnique<T, C extends DbCreate<T>>(\n db: Db<T>,\n options: DbUniqueOptions<T, C>,\n): Promise<DbUniqueOutput> {\n const { id, created } = await dbUpsert(db, {\n ...options,\n // @ts-expect-error\n update: {},\n onBeforeUpdate: () => false,\n });\n return { id, created };\n}\n"],"mappings":"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"}
package/dist/database.mjs CHANGED
@@ -477,8 +477,8 @@ var Db = class Db {
477
477
  }
478
478
  this._lookupAs[as] = true;
479
479
  }
480
- if (this._hasSample) returnAggRef = returnAggRef.sample({ size: this._sampleSize });
481
480
  if (this._hasWhere) returnAggRef = returnAggRef.match(_mapCommandRaw(this._where));
481
+ if (this._hasSample) returnAggRef = returnAggRef.sample({ size: this._sampleSize });
482
482
  if (this._hasOrder) returnAggRef = returnAggRef.sort(objectMap(this._order, (v) => v === "asc" ? 1 : -1));
483
483
  if (this._hasSkip) returnAggRef = returnAggRef.skip(this._skip);
484
484
  if (this._hasLimit) returnAggRef = returnAggRef.limit(this._limit);
@@ -1 +1 @@
1
- {"version":3,"file":"database.mjs","names":[],"sources":["../src/database/_command.class.ts","../src/database/command.ts","../src/database/each.ts","../src/database/error.ts","../src/database/paging.ts","../src/database/_db.class.ts","../src/database/proxy.ts","../src/database/transaction.ts","../src/database/upsert.ts","../src/database/unique.ts"],"sourcesContent":["// 设置私有属性和静态方法是避免在 update 的时候提示类属性\n\nexport class DbBaseCommand {\n protected _isQuery = false;\n protected _isMutate = false;\n\n constructor(\n private _command: string,\n private _parameter: unknown,\n private _options?: {\n formatParameter?: (db: UniCloud.Database) => unknown;\n rewriteValue?: (db: UniCloud.Database, parameter: unknown) => unknown;\n },\n ) {}\n\n static getValue(cmd: DbBaseCommand, db: UniCloud.Database) {\n if (cmd._options?.rewriteValue) {\n return cmd._options.rewriteValue(db, cmd._parameter);\n }\n\n return (db.command as unknown as Record<string, (value: unknown) => unknown>)[cmd._command].call(\n db.command,\n cmd._options?.formatParameter?.(db) || cmd._parameter,\n );\n }\n\n static getExpression(cmd: DbBaseCommand, fieldName: string) {\n return {\n [`$${cmd._command}`]: [fieldName, cmd._parameter],\n };\n }\n\n static isQueryCommand(cmd: DbBaseCommand) {\n return cmd._isQuery;\n }\n\n static isMutateCommand(cmd: DbBaseCommand) {\n return cmd._isMutate;\n }\n}\n\nexport class DbQueryCommand extends DbBaseCommand {\n protected _isQuery = true;\n}\n\nexport class DbMutateCommand extends DbBaseCommand {\n protected _isMutate = true;\n}\n","import { DbBaseCommand, DbMutateCommand, DbQueryCommand } from './_command.class';\n\n/**\n * 数据库查询命令对象,提供各种查询操作符\n */\nexport const dbQuery = {\n /**\n * 等于操作符\n * @param value 比较值\n * @returns DbQueryCommand 查询命令对象\n */\n eq: (value: unknown) => new DbQueryCommand('eq', value),\n\n /**\n * 不等于操作符\n * @param value 比较值\n * @returns DbQueryCommand 查询命令对象\n */\n neq: (value: unknown) => new DbQueryCommand('neq', value),\n\n /**\n * 大于操作符\n * @param value 比较值\n * @returns DbQueryCommand 查询命令对象\n */\n gt: (value: unknown) => new DbQueryCommand('gt', value),\n\n /**\n * 大于等于操作符\n * @param value 比较值\n * @returns DbQueryCommand 查询命令对象\n */\n gte: (value: unknown) => new DbQueryCommand('gte', value),\n\n /**\n * 小于操作符\n * @param value 比较值\n * @returns DbQueryCommand 查询命令对象\n */\n lt: (value: unknown) => new DbQueryCommand('lt', value),\n\n /**\n * 小于等于操作符\n * @param value 比较值\n * @returns DbQueryCommand 查询命令对象\n */\n lte: (value: unknown) => new DbQueryCommand('lte', value),\n\n /**\n * 包含在数组中操作符\n * @param value 值数组\n * @returns DbQueryCommand 查询命令对象\n */\n in: (value: unknown[]) => new DbQueryCommand('in', value),\n\n /**\n * 不包含在数组中操作符\n * @param value 值数组\n * @returns DbQueryCommand 查询命令对象\n */\n nin: (value: unknown[]) => new DbQueryCommand('nin', value),\n\n /**\n * 数组长度匹配操作符\n * @param size 数组长度\n * @returns DbQueryCommand 查询命令对象\n */\n size: (size: number) => new DbQueryCommand('size', size),\n\n /**\n * 正则表达式匹配操作符\n * @param regExp 正则表达式\n * @returns DbQueryCommand 查询命令对象\n */\n regExp: (regExp: RegExp) =>\n new DbQueryCommand('regExp', regExp, {\n rewriteValue: (_db, parameter) => parameter,\n }),\n\n /**\n * 逻辑与操作符\n * @param conditions 查询条件参数\n * @returns DbQueryCommand 查询命令对象\n */\n and: (conditions: DbQueryCommand[]) =>\n new DbQueryCommand('and', conditions, {\n formatParameter: (db) => conditions.map((c) => DbBaseCommand.getValue(c, db)),\n }),\n\n /**\n * 逻辑或操作符\n * @param conditions 查询条件参数\n * @returns DbQueryCommand 查询命令对象\n */\n or: (conditions: DbQueryCommand[]) =>\n new DbQueryCommand('or', conditions, {\n formatParameter: (db) => conditions.map((c) => DbBaseCommand.getValue(c, db)),\n }),\n};\n\n/**\n * 数据库变更命令对象,提供各种数据更新操作符\n */\nexport const dbMutate = {\n /**\n * 数值增加操作符\n * @param value 增加的数值\n * @returns DbMutateCommand 变更命令对象\n */\n inc: (value: number) => new DbMutateCommand('inc', value),\n\n /**\n * 数值乘法操作符\n * @param value 乘数\n * @returns DbMutateCommand 变更命令对象\n */\n mul: (value: number) => new DbMutateCommand('mul', value),\n\n /**\n * 设置字段值操作符\n * @param value 设置的值\n * @returns DbMutateCommand 变更命令对象\n */\n set: (value: unknown) => new DbMutateCommand('set', value),\n\n /**\n * 向数组末尾添加元素操作符\n * @param value 添加的值\n * @returns DbMutateCommand 变更命令对象\n */\n push: (value: unknown) => new DbMutateCommand('push', value),\n\n /**\n * 向数组开头添加元素操作符\n * @param value 添加的值\n * @returns DbMutateCommand 变更命令对象\n */\n unshift: (value: unknown) => new DbMutateCommand('unshift', value),\n\n /**\n * 从数组末尾移除元素操作符\n * @returns DbMutateCommand 变更命令对象\n */\n pop: () => new DbMutateCommand('pop', undefined),\n\n /**\n * 从数组开头移除元素操作符\n * @returns DbMutateCommand 变更命令对象\n */\n shift: () => new DbMutateCommand('shift', undefined),\n\n /**\n * 移除字段操作符\n * @returns DbMutateCommand 变更命令对象\n */\n remove: () => new DbMutateCommand('remove', undefined),\n};\n","import type { Db } from './_db.class';\nimport type { DbWhere } from './types';\n\n/**\n * 遍历表中的每一行数据并执行回调函数\n *\n * 采用分批查询策略,每批查询 100 条记录,通过 skip/limit 实现分页遍历,\n * 避免一次性加载大量数据导致内存溢出。\n *\n * 迭代器按顺序串行执行,即每一行数据的迭代器完成后才会处理下一行。\n *\n * @template T - 数据行类型\n * @param table 数据库表代理对象\n * @param where 查询条件\n * @param iterator 对每一行数据执行的异步迭代器函数\n * @param maxCount 最大遍历数量,默认值为 Number.MAX_SAFE_INTEGER。\n * 注意:由于分批查询机制(每批 100 条),实际遍历的行数可能略大于 maxCount,\n * 例如 maxCount=150 时,会分两批查询(0-99、100-199),实际遍历 200 行。\n * @example\n * ```ts\n * // 遍历所有状态为 active 的用户\n * await dbEach(userTable, { status: 'active' }, async (user) => {\n * await sendEmail(user.email);\n * });\n *\n * // 限制最多遍历 500 条记录\n * await dbEach(orderTable, { status: 'pending' }, async (order) => {\n * await processOrder(order);\n * }, 500);\n * ```\n */\nexport async function dbEach<T>(\n table: Db<T>,\n where: DbWhere<T>,\n iterator: (row: T) => Promise<unknown>,\n maxCount = Number.MAX_SAFE_INTEGER,\n) {\n const count = Math.min(await table.where(where).count(), maxCount);\n const limit = 100;\n\n for (let skip = 0; skip < count; skip += limit) {\n const rows = await table.where(where).limit(limit).skip(skip).many();\n\n for (const row of rows) {\n await iterator(row as T);\n }\n }\n}\n","/**\n * 数据库底层异常类\n * 当 uniCloud 数据库操作抛出错误时,统一包装为该异常\n */\nexport class DbError extends Error {\n /** 原始错误码,如 'InternalServerError' */\n errCode: string | number;\n /** MongoDB 错误码,如 'E11000'。不匹配则为空字符串 */\n dbCode: string;\n\n constructor(message: string, extra: { errCode: string | number; dbCode: string }) {\n super(message);\n this.name = 'DbError';\n this.errCode = extra.errCode;\n this.dbCode = extra.dbCode;\n }\n}\n\n/**\n * 判断错误是否为数据库底层错误\n * @param err - 任意错误对象\n * @returns 是否为 DbError\n */\nexport function isDbError(err: unknown): err is DbError {\n return err instanceof DbError;\n}\n\n/**\n * 从 MongoDB 错误消息中提取错误码\n * @param errMsg - 错误消息字符串,如 'E11000 duplicate key error...'\n * @returns MongoDB 错误码,如 'E11000'\n */\nexport function extractMongoCode(errMsg: string): string {\n const m = errMsg.match(/^E\\d+/);\n return m ? m[0] : '';\n}\n","import type { AnyObject } from '@cloudcome/utils-core/types';\nimport type { Db } from './_db.class';\nimport type { DbSelect } from './types';\n\n/**\n * 数据库分页查询函数\n * @template T - 数据类型\n * @param queryDb - 数据库查询实例\n * @returns 包含数据列表和总数的对象\n */\n\nexport async function dbPaging<\n D1,\n // biome-ignore lint/complexity/noBannedTypes: 必须这么用\n S1 extends DbSelect<D1> = {},\n // biome-ignore lint/complexity/noBannedTypes: 必须这么用\n D2 extends AnyObject = {},\n // biome-ignore lint/complexity/noBannedTypes: 必须这么用\n W2 extends AnyObject = {},\n>(queryDb: Db<D1, S1, D2, W2>) {\n // 获取原始查询条件,不包映射字段\n const where = queryDb.getWhere(true);\n\n // 克隆查询实例用于统计总数,避免影响原查询\n const countDb = queryDb.clone();\n\n // 执行查询获取数据列表\n const list = await queryDb.many();\n\n // 基于相同查询条件统计总数\n const total = await countDb.where(where).count();\n\n // 返回分页结果\n return {\n list,\n total,\n };\n}\n","import { isUniError, parseDatabaseOutput } from '@/_helpers';\nimport type { UniError } from '@/_types';\nimport { createCloudObjectError } from '@/cloud';\nimport { objectEach, objectFilter, objectMap, objectOmit } from '@cloudcome/utils-core/object';\nimport { isArray, isObject } from '@cloudcome/utils-core/type';\nimport type { AnyObject, MergeIntersection } from '@cloudcome/utils-core/types';\nimport { DbBaseCommand, type DbQueryCommand } from './_command.class';\nimport { DbError, extractMongoCode } from './error';\nimport type { DbCreate, DbForeign, DbOrder, DbQuery, DbRelation, DbSelect, DbUpdate, DbWhere } from './types';\n\n/**\n * 数据库聚合操作符命令\n */\nconst dbAgg = uniCloud.database().command.aggregate as UniCloud.AggregateCommand & {\n pipeline: () => UniCloud.AggregateReference & {\n done: () => unknown;\n };\n};\n\nconst db0 = uniCloud.database();\n\nexport type DbOptions = {\n /**\n * 数据表名称\n */\n table: string;\n\n /**\n * 事务对象,用于事务操作\n */\n // biome-ignore lint/suspicious/noExplicitAny: 必须这么用\n transaction?: any;\n\n /**\n * 模拟数据库,用于单元测试\n */\n // biome-ignore lint/suspicious/noExplicitAny: 单测使用 any\n _mockDatabase?: any;\n\n /**\n * 自定义错误处理函数\n * @param error unknown 数据库异常对象\n * @returns 自定义错误对象\n */\n parseError?: (error: unknown) => UniError;\n};\n\nexport type DbLookupOptions<\n RL extends DbRelation,\n D1,\n FD1,\n AS,\n // biome-ignore lint/suspicious/noConfusingVoidType: 必须这么用\n US extends boolean | undefined | void = undefined,\n LF extends keyof D1 & string = keyof D1 & string,\n> = {\n /**\n * 关联类型\n */\n relation: RL;\n\n /**\n * 主表字段\n */\n localField: LF;\n\n /**\n * 关联表字段\n */\n foreignField: keyof FD1 & string;\n\n /**\n * 关联数据在结果中的字段名\n */\n as: AS;\n\n /**\n * 是否取消筛选关联数据\n */\n unselect?: US;\n};\n\nexport type DbLookup = DbLookupOptions<\n // biome-ignore lint/suspicious/noExplicitAny: 必须这么用\n any,\n unknown,\n unknown,\n string,\n boolean\n> & {\n /**\n * 关联表\n */\n table: Db<unknown>;\n};\n\nlet gid = 0;\n\n/**\n * 数据库类\n * @template D1 - 主表数据\n * @template S1 - 主表筛选\n * @template D2 - 副表数据\n * @template W2 - 副表查询\n */\nexport class Db<\n D1,\n // biome-ignore lint/complexity/noBannedTypes: 必须这么用\n S1 extends DbSelect<D1> = {},\n // biome-ignore lint/complexity/noBannedTypes: 必须这么用\n D2 extends AnyObject = {},\n // biome-ignore lint/complexity/noBannedTypes: 必须这么用\n W2 extends AnyObject = {},\n> {\n /**\n * 是否为事务环境\n * - 更新条件只能是 id\n * - 删除条件只能是 id\n */\n private _isTransaction = false;\n\n private _options: DbOptions;\n\n /**\n * 构造函数,初始化数据库集合引用\n * @param collection 数据表名称\n * @param _mockDatabase 模拟数据库,用于单元测试\n */\n constructor(options: DbOptions) {\n this._options = options;\n // hostRef =\n // options._mockDatabase || options.transaction?.collection(options.table) || db0.collection(options.table);\n this._isTransaction = !!options.transaction;\n }\n\n /**\n * 创建一个新的数据库实例,可选是否移除事务\n * @param withoutTransaction 是否移除事务,默认 false\n * @returns 新的数据库实例\n */\n clone(withoutTransaction?: boolean) {\n return new Db({\n ...this._options,\n transaction: withoutTransaction ? null : this._options.transaction,\n });\n }\n\n get table() {\n return this._options.table;\n }\n\n get options() {\n return this._options;\n }\n\n get isTransaction() {\n return this._isTransaction;\n }\n\n _createHost(withoutTransaction?: boolean) {\n const options = this._options;\n return (\n options._mockDatabase ||\n (withoutTransaction ? null : options.transaction?.collection(options.table) || db0.collection(options.table))\n );\n }\n\n /**\n * 获取聚合操作实例\n * @returns 聚合操作实例\n */\n _createAggregate() {\n const host = this._createHost();\n return host.aggregate();\n }\n\n private _hasWhere = false;\n private _hasWhereId = false;\n private _where = {};\n\n /**\n * 设置查询条件\n * @param where 查询条件对象\n * @returns 当前Db实例,支持链式调用\n */\n where(where: DbWhere<D1> & W2) {\n if (this._isTransaction) throw new Error('事务模式下请使用 whereId() 方法');\n if (this._hasWhere) throw new Error('已调用过一次 db.where({...}) 或 db.whereId(id) 了');\n\n // 过滤掉值为 undefined 的键值对,数据库不支持查询全 undefined 值\n const realWhere = objectFilter(where, (value) => value !== undefined);\n\n this._hasWhere = true;\n this._where = realWhere;\n\n return this;\n }\n\n /**\n * 获取当前查询条件\n * @param plain 是否返回原始查询条件对象,默认 false\n * @returns 当前查询条件对象\n */\n getWhere(plain?: boolean) {\n return plain\n ? // biome-ignore lint/suspicious/noTsIgnore: 必须这么用\n // @ts-ignore\n objectOmit(this._where, Object.keys(this._lookupAs))\n : this._where;\n }\n\n /**\n * 根据ID设置查询条件\n * @param id 记录ID\n * @returns 当前Db实例,支持链式调用\n */\n whereId(id: string | number) {\n if (this._hasWhere) throw new Error('已调用过一次 db.where({...}) 或 db.whereId(id) 了');\n if (this._hasLimit) throw new Error('db.whereId(id) 方法不能与 db.limit() 方法同时调用');\n\n this._hasWhere = true;\n this._hasWhereId = true;\n this._where = { _id: id };\n\n return this;\n }\n\n private _hasSelect = 0;\n private _select = {};\n\n /**\n * 指定要返回的字段\n * @param fields 要返回的字段对象,true表示返回,false表示不返回\n * @returns 当前Db实例,支持链式调用\n */\n select<const S extends DbSelect<D1>>(fields: S) {\n if (this._hasSelect) throw new Error('db.select() 方法只能调用一次');\n\n this._hasSelect++;\n this._select = fields;\n\n return this as Db<D1, S, D2, W2>;\n }\n\n private _hasOrder = 0;\n private _order = {};\n\n /**\n * 设置排序规则\n * @param order 排序规则对象,key为字段名,value为\"asc\"或\"desc\"\n * @returns 当前Db实例,支持链式调用\n */\n order(order: DbOrder<D1>) {\n if (this._isTransaction) throw new Error('db.order() 方法不支持事务模式');\n\n this._hasOrder++;\n this._order = order;\n\n return this;\n }\n\n private _hasSkip = 0;\n private _skip = 0;\n\n /**\n * 跳过指定数量的记录\n * @param skip 要跳过的记录数\n * @returns 当前Db实例,支持链式调用\n */\n skip(skip: number) {\n if (this._isTransaction) throw new Error('db.skip() 方法不支持事务模式');\n if (this._hasSkip) throw new Error('db.skip() 方法只能调用一次');\n\n this._hasSkip++;\n this._skip = skip;\n\n return this;\n }\n\n private _hasLimit = 0;\n private _limit = 0;\n\n /**\n * 限制返回的记录数量\n * @param limit 最大返回记录数\n * @returns 当前Db实例,支持链式调用\n */\n limit(limit: number) {\n if (this._isTransaction) throw new Error('db.limit() 方法不支持事务模式');\n if (this._hasLimit) throw new Error('db.limit() 方法只能调用一次');\n if (this._hasSample) throw new Error('db.limit() 方法不支持 sample 条件');\n\n if (this._hasWhereId) {\n throw new Error('db.limit() 方法不能与 db.whereId(id) 方法同时调用');\n }\n\n this._hasLimit++;\n this._limit = limit;\n\n return this;\n }\n\n private _hasSample = 0;\n private _sampleSize = 0;\n\n /**\n * 随机从文档中选取指定数量的记录\n * @param size 要选取的记录数量,必须为正整数\n * @returns 当前Db实例,支持链式调用\n */\n sample(size: number) {\n if (this._isTransaction) throw new Error('db.sample() 方法不支持事务模式');\n if (this._hasSample) throw new Error('db.sample() 方法只能调用一次');\n if (this._hasLimit) throw new Error('db.sample() 方法不支持 limit 条件');\n\n this._hasSample++;\n this._sampleSize = size;\n\n return this;\n }\n\n private _hasLookup = 0;\n get hasLookup() {\n return this._hasLookup > 0;\n }\n\n private _lookups: DbLookup[] = [];\n lookup<\n FD1,\n FS1 extends DbSelect<FD1>,\n FD2 extends AnyObject,\n FW2 extends AnyObject,\n RL extends DbRelation,\n AS extends string,\n // biome-ignore lint/suspicious/noConfusingVoidType: 必须这么用\n US extends boolean | undefined | void = undefined,\n LF extends keyof D1 & string = keyof D1 & string,\n >(table: Db<FD1, FS1, FD2, FW2>, lookup: DbLookupOptions<RL, D1, FD1, AS, US, LF>) {\n if (this._isTransaction) throw new Error('db.lookup() 方法不支持事务模式');\n\n // 对方表也记为关联查询,避免做表更新操作\n table._hasLookup++;\n this._hasLookup++;\n this._lookups.push({\n ...lookup,\n table,\n } as unknown as DbLookup);\n\n // @ts-expect-error\n return this as Db<\n D1,\n S1,\n US extends true ? D2 : MergeIntersection<D2 & DbForeign<D1, FD1, FS1, FD2, RL, AS, LF>>,\n MergeIntersection<W2 & Partial<Record<AS, DbQueryCommand>>>\n >;\n }\n\n private _ending = false;\n\n private _aggregated = false;\n private _lookupAs = {} as Record<string, true>;\n private _endAggregate(aggRef: UniCloud.AggregateReference) {\n if (this._aggregated) throw new Error(`相同的数据表实例(${this.table})不能重复使用`);\n if (this._ending) throw new Error(`相同的数据表实例(${this.table})不能重复使用`);\n\n this._ending = true;\n this._aggregated = true;\n let returnAggRef = aggRef;\n let _hasAggSelect = 0;\n const aggSelect = {} as Record<string, true>;\n let hasAggUnselect = 0;\n const aggUnselect = {} as Record<string, false>;\n\n // 后做关联查询\n for (const { relation: type, as, foreignField, localField, table, unselect } of this._lookups) {\n const letName = `let${gid++}`;\n let pipeline = dbAgg.pipeline();\n\n // 关联条件\n // @ts-expect-error\n pipeline = pipeline.match({\n $expr: {\n $and: [\n type === 'n:1'\n ? { $in: [`$${foreignField}`, `$$${letName}`] }\n : { $eq: [`$${foreignField}`, `$$${letName}`] },\n ],\n },\n });\n\n // 其他查询条件\n // @ts-expect-error\n pipeline = table._endAggregate(pipeline);\n\n // @ts-expect-error\n pipeline = pipeline.done();\n\n returnAggRef = returnAggRef.lookup({\n let: {\n [letName]: `$${localField}`,\n },\n as,\n from: table.table,\n pipeline,\n });\n\n // 1对1,展开数组\n if (type === '1:1') {\n // @ts-expect-error\n returnAggRef = returnAggRef.unwind({\n path: `$${as}`,\n preserveNullAndEmptyArrays: true,\n });\n }\n\n if (unselect) {\n hasAggUnselect++;\n aggUnselect[as] = false;\n } else {\n _hasAggSelect++;\n aggSelect[as] = true;\n }\n\n this._lookupAs[as] = true;\n }\n\n // 主表查询,注意顺序,筛选->排序->跳过->限制\n if (this._hasSample) returnAggRef = returnAggRef.sample({ size: this._sampleSize });\n if (this._hasWhere) returnAggRef = returnAggRef.match(_mapCommandRaw(this._where));\n if (this._hasOrder) returnAggRef = returnAggRef.sort(objectMap(this._order, (v) => (v === 'asc' ? 1 : -1)));\n if (this._hasSkip) returnAggRef = returnAggRef.skip(this._skip);\n if (this._hasLimit) returnAggRef = returnAggRef.limit(this._limit);\n\n // 如果主表有选择字段,则合并选择字段(包括关联查询的字段和排序字段)\n if (this._hasSelect) {\n returnAggRef = returnAggRef.project(_mergeSelect({ ...this._select, ...aggSelect }, this._order));\n }\n // 如果主表没有选择字段,则排除取消选择字段\n else if (hasAggUnselect) {\n returnAggRef = returnAggRef.project(aggUnselect);\n }\n\n return returnAggRef;\n }\n\n private _endHost(host: UniCloud.CollectionReference, action: 'query' | 'create' | 'update' | 'remove' | 'count') {\n if (this._ending) throw new Error(`相同的数据表实例(${this.table})不能重复使用`);\n this._ending = true;\n\n // 事务模式下:查询/更新/删除必须使用 whereId\n if (\n this._isTransaction &&\n (action === 'query' || action === 'update' || action === 'remove') &&\n !this._hasWhereId\n ) {\n throw new Error('事务模式下查询/更新/删除条件只能是 ID,请使用 whereId() 方法');\n }\n\n let hostRef = host;\n if (this._hasWhere) {\n // 事务模式下:更新/删除/查询只能用 doc(id)\n if (this._isTransaction && (action === 'update' || action === 'remove' || action === 'query')) {\n // @ts-expect-error\n hostRef = hostRef.doc(this._where._id);\n } else {\n // @ts-expect-error\n hostRef = hostRef.where(_mapCommandRaw(this._where));\n }\n }\n\n if (this._hasSelect) {\n // @ts-expect-error\n hostRef = hostRef.field(_mergeSelect(this._select, this._order));\n }\n\n if (this._hasOrder) {\n objectEach(this._order, (val, key) => {\n // @ts-expect-error\n hostRef = hostRef.orderBy(key, val);\n });\n }\n\n // @ts-expect-error\n if (this._hasSkip) hostRef = hostRef.skip(this._skip);\n\n if (this._hasLimit && action === 'query')\n // @ts-expect-error\n hostRef = hostRef.limit(this._limit);\n else if (this._hasWhereId && action === 'query' && !this._isTransaction)\n // @ts-expect-error\n hostRef = hostRef.limit(1);\n\n return hostRef;\n }\n\n /**\n * 将 uniCloud 数据库原始错误包装为 DbError\n * @param err - 原始错误对象,来自 uniCloud DB 操作(Error 实例,含 errMsg、errCode 属性)\n * @returns DbError 实例\n */\n private _parseDbError(err: UniError) {\n const errCode = err.errCode || '';\n const message = err.errMsg || err.message;\n const dbCode = extractMongoCode(err.errMsg || err.message);\n\n if (dbCode) {\n return new DbError(message, {\n errCode: errCode,\n dbCode: dbCode,\n });\n } else {\n return err;\n }\n }\n\n /**\n * 统一处理 DB 操作抛出的错误\n * - uniCloud 数据库错误(含 errMsg)→ 包装为 DbError → 经 parseError 回调后抛出\n * - 非数据库错误(如网络中断)→ 原样抛出\n */\n private _handleDbError(err: unknown): never {\n if (isUniError(err)) {\n const dbErr = this._parseDbError(err);\n throw this._options.parseError?.(dbErr) || dbErr;\n } else {\n throw this._options.parseError?.(err) || err;\n }\n }\n\n /**\n * 执行查询操作\n * @returns 查询结果\n */\n async many() {\n try {\n let res: { data: DbQuery<D1, S1, D2>[] | DbQuery<D1, S1, D2> | undefined };\n\n // 事务模式下不支持聚合查询\n if (this._isTransaction && (this._hasLookup || this._hasSample)) {\n throw new Error('事务模式下不支持 lookup 聚合或 sample 取样查询');\n }\n\n // 关联查询 / sample 查询(sample 依赖聚合管线)\n if (this._hasLookup || this._hasSample) {\n let aggRef = this._createAggregate();\n aggRef = this._endAggregate(aggRef);\n res = await aggRef.end();\n }\n // 单表查询\n else {\n let hostRef = this._createHost();\n hostRef = this._endHost(hostRef, 'query');\n res = await hostRef.get();\n }\n\n const { data } = parseDatabaseOutput(res);\n\n // doc(id).get() 返回单个对象或 undefined,需包装为数组以统一 many() 返回值\n return isArray(data) ? data : data ? [data] : [];\n } catch (err) {\n this._handleDbError(err);\n }\n }\n\n /**\n * 只查询一条,自动添加 limit(1) 条件\n * 如果没有匹配到记录,会抛出错误\n * @returns 查询结果\n */\n async firstOrThrow(): Promise<DbQuery<D1, S1, D2>> {\n if (this._hasLimit) throw new Error('db.firstOrThrow() 方法不支持 limit 条件');\n if (!this._hasWhereId && !this._hasSample) this.limit(1);\n\n const data = await this.many();\n const res = data.at(0);\n\n if (!res) throw createCloudObjectError('查询数据为空', 'firstOrThrow');\n return res;\n }\n\n /**\n * 只查询一条,自动添加 limit(1) 条件\n * 如果没有匹配到记录,返回 null\n * @returns 查询结果或 null\n */\n async firstOrNull(): Promise<DbQuery<D1, S1, D2> | null> {\n if (this._hasLimit) throw new Error('db.firstOrNull() 方法不支持 limit 条件');\n if (!this._hasWhereId && !this._hasSample) this.limit(1);\n\n const data = await this.many();\n return data.at(0) || null;\n }\n\n /**\n * 获取匹配记录的数量\n * @returns 记录总数\n */\n async count() {\n if (this._isTransaction) throw new Error('db.count() 方法不支持事务模式');\n if (this._hasSample) throw new Error('db.count() 方法不支持 sample 取样');\n if (this._hasLookup) throw new Error('db.count() 方法不支持 lookup 聚合');\n if (this._hasSelect) throw new Error('db.count() 方法不支持 select 条件');\n if (this._hasOrder) throw new Error('db.count() 方法不支持 order 条件');\n if (this._hasSkip) throw new Error('db.count() 方法不支持 skip 条件');\n if (this._hasLimit) throw new Error('db.count() 方法不支持 limit 条件');\n\n try {\n let hostRef = this._createHost();\n hostRef = this._endHost(hostRef, 'count');\n const res = await hostRef.count();\n const { total } = parseDatabaseOutput<{ total: number }>(res);\n return total;\n } catch (err) {\n this._handleDbError(err);\n }\n }\n\n /**\n * 创建新记录\n * @param data 要创建的数据\n * @returns 创建结果\n */\n async create(data: DbCreate<D1>) {\n if (this._hasLookup) throw new Error('db.create() 方法不支持 lookup 聚合');\n if (this._hasWhere) throw new Error('db.create() 方法不支持 where 条件');\n if (this._hasSelect) throw new Error('db.create() 方法不支持 select 条件');\n if (this._hasOrder) throw new Error('db.create() 方法不支持 order 条件');\n if (this._hasSkip) throw new Error('db.create() 方法不支持 skip 条件');\n if (this._hasLimit) throw new Error('db.create() 方法不支持 limit 条件');\n\n try {\n let hostRef = this._createHost();\n hostRef = this._endHost(hostRef, 'create');\n const res = await hostRef.add(data);\n const { id } = parseDatabaseOutput<{ id: string }>(res);\n return id;\n } catch (err) {\n this._handleDbError(err);\n }\n }\n\n /**\n * 更新记录\n * @param data 要更新的数据\n * @returns 更新结果\n */\n async update(data: DbUpdate<D1>) {\n if (this._hasLookup) throw new Error('db.update() 方法不支持 lookup 聚合');\n if (!this._hasWhere) throw new Error('设置 where 条件后才能执行 db.update() 方法');\n if (this._hasSelect) throw new Error('db.update() 方法不支持 select 条件');\n if (this._hasOrder) throw new Error('db.update() 方法不支持 order 条件');\n if (this._hasSkip) throw new Error('db.update() 方法不支持 skip 条件');\n if (this._hasLimit) throw new Error('db.update() 方法不支持 limit 条件');\n\n if (this._isTransaction && !this._hasWhereId) throw new Error('事务模式下 db.update() 的 where 条件必须是 _id');\n\n try {\n let hostRef = this._createHost();\n hostRef = this._endHost(hostRef, 'update');\n const res = await hostRef.update(objectOmit(_mapCommandRaw(data), ['_id']));\n const { updated } = parseDatabaseOutput<{ updated: number }>(res);\n return updated;\n } catch (err) {\n this._handleDbError(err);\n }\n }\n\n /**\n * 删除记录\n * @returns 删除结果\n */\n async remove() {\n if (this._hasLookup) throw new Error('db.remove() 方法不支持 lookup 聚合');\n if (!this._hasWhere) throw new Error('设置 where 条件后才能执行 db.remove() 方法');\n if (this._hasSelect) throw new Error('db.remove() 方法不支持 select 条件');\n if (this._hasOrder) throw new Error('db.remove() 方法不支持 order 条件');\n if (this._hasSkip) throw new Error('db.remove() 方法不支持 skip 条件');\n if (this._hasLimit) throw new Error('db.remove() 方法不支持 limit 条件');\n\n if (this._isTransaction && !this._hasWhereId) throw new Error('事务模式下 db.remove() 的 where 条件必须是 _id');\n\n try {\n let hostRef = this._createHost();\n hostRef = this._endHost(hostRef, 'remove');\n const res = await hostRef.remove();\n const { deleted } = parseDatabaseOutput<{ deleted: number }>(res);\n return deleted;\n } catch (err) {\n this._handleDbError(err);\n }\n }\n}\n\n// biome-ignore lint/suspicious/noExplicitAny: 必须这么用\nfunction _mapCommandRaw(data: any) {\n // biome-ignore lint/suspicious/noExplicitAny: 必须这么用\n const map = (val: any): any => {\n if (!isObject(val)) return val;\n if (val instanceof DbBaseCommand) return DbBaseCommand.getValue(val, db0);\n return objectMap(val, map);\n };\n\n return objectMap(data, map);\n}\n\nfunction _mapOrderSelect(order: DbOrder<unknown>) {\n return objectMap(order, (_val, _key) => true);\n}\n\nfunction _mergeSelect(select: DbSelect<unknown>, order: DbOrder<unknown>) {\n const noSelect = Object.keys(select).length === 0;\n // 如果没有 select 条件,默认返回所有字段\n if (noSelect) return select;\n\n const onlyOmitId = Object.keys(select).length === 1 && '_id' in select && select._id === false;\n // 如果只排除 _id 字段,则保持现状\n if (onlyOmitId) return select;\n\n return {\n ...select,\n ..._mapOrderSelect(order),\n };\n}\n","import { isFunction } from '@cloudcome/utils-core/type';\nimport { Db } from './_db.class';\nimport type { DbSelect } from './types';\nimport type { UniError } from '@/_types';\n\nexport type DbProxyOptions = {\n /**\n * 自定义错误处理函数\n * @param error unknown 数据库异常对象\n * @returns 自定义错误对象\n */\n parseError?: (error: unknown) => UniError;\n};\n\n/**\n * 创建一个数据库代理对象,用于延迟实例化数据库操作类\n * @template D1 - 主表数据\n * @template S1 - 主表筛选\n * @param name - 数据库表名\n * @returns 返回一个代理对象,该对象会将属性访问转发到实际的数据库操作实例\n */\n\n// biome-ignore lint/complexity/noBannedTypes: 必须这么用\nexport function dbProxy<D1, S1 extends DbSelect<D1> = {}>(name: string, options?: DbProxyOptions) {\n return new Proxy(\n {},\n {\n get(_target, prop) {\n if (prop === '_isProxy') return true;\n\n const table = new Db<D1, S1>({ table: name, ...options });\n const tableProp = prop as keyof Db<D1, S1>;\n const ref = table[tableProp];\n\n return isFunction(ref) ? ref.bind(table) : ref;\n },\n },\n ) as Db<D1, S1>;\n}\n","import { tryFlatten } from '@cloudcome/utils-core/try';\nimport { Db } from './_db.class';\n\ntype _TransactionDb = {\n startTransaction: () => Promise<_Transaction>;\n};\n\ntype _Transaction = {\n commit: () => Promise<unknown>;\n rollback: () => Promise<unknown>;\n};\n\nexport type WithTransaction = <D1>(db: Db<D1>) => Db<D1>;\n\n/**\n * 在数据库事务中执行操作\n *\n * @template K - 事务操作返回值类型\n * @param transacting - 事务执行函数,接收事务数据库实例作为参数\n * @param _mockDatabase - 用于测试的模拟数据库对象\n * @param _mockDbInstance - 用于测试的模拟数据库实例\n * @returns 事务操作的返回结果\n *\n * @example\n * ```typescript\n * const result = await dbTransaction(async (withTransaction) => {\n * const userId = await withTransaction(db.table('user')).create({ name: 'John' });\n * const order = await withTransaction(db.table('orders')).create({ userId, amount: 100 });\n * return { user, order };\n * });\n * ```\n */\nexport async function dbTransaction<K>(\n transacting: (withTransaction: WithTransaction) => Promise<K>,\n // biome-ignore lint/suspicious/noExplicitAny: 单测使用 any\n _mockDatabase?: any,\n // biome-ignore lint/suspicious/noExplicitAny: 单测使用 any\n _mockDbInstance?: any,\n) {\n const transactionDb = (_mockDatabase || uniCloud.database()) as _TransactionDb;\n\n const [err1, transaction] = await tryFlatten(transactionDb.startTransaction());\n if (err1) throw err1;\n\n const withTransaction: WithTransaction = <D1>(db: Db<D1>) => {\n return _mockDbInstance || new Db<D1>({ ...db.options, transaction });\n };\n\n const [err2, result] = await tryFlatten(async () => {\n const result = await transacting(withTransaction);\n await transaction.commit();\n return result;\n });\n\n if (err2) {\n await tryFlatten(transaction.rollback());\n throw err2;\n }\n\n return result as unknown as K;\n}\n","import { isFunction } from '@cloudcome/utils-core/type';\nimport type { Db } from './_db.class';\nimport type { DbCreate, DbQuery, DbUpdate } from './types';\n\nexport type DbUpsertOptions<T, C extends DbCreate<T>, U extends DbUpdate<T>> = {\n /** 创建数据 */\n create: C;\n\n /**\n * 更新数据,可以是对象或根据查询结果生成更新对象的函数\n * @param row 查询到的文档数据,仅在传入函数时可用\n */\n // biome-ignore lint/complexity/noBannedTypes: 必须这么用\n update: U | ((exist: DbQuery<T, {}, {}>) => U);\n\n /** 创建前回调函数 */\n onBeforeCreate?: () => unknown;\n\n /**\n * 创建后回调函数\n * @param id 创建的文档ID\n */\n onAfterCreate?: (id: string) => unknown;\n\n /**\n * 更新前回调函数\n * @param exist 查询到的原始文档数据\n * @returns 如果返回 false,则取消更新操作\n */\n // biome-ignore lint/complexity/noBannedTypes: 必须这么用\n onBeforeUpdate?: (exist: DbQuery<T, {}, {}>) => false | unknown;\n\n /**\n * 更新后回调函数\n * @param updateData 实际更新的数据\n * @param exist 查询到的原始文档数据\n */\n // biome-ignore lint/complexity/noBannedTypes: 必须这么用\n onAfterUpdate?: (updateData: U, exist: DbQuery<T, {}, {}>) => unknown;\n\n /** 用于测试的模拟数据库实例 */\n // biome-ignore lint/suspicious/noExplicitAny: 单测使用 any\n _mockDbInstance?: any;\n};\n\n/**\n * 数据库 upsert 操作的返回结果类型\n */\nexport type DbUpsertOutput = {\n /** 操作的文档ID */\n id: string;\n /** 是否为创建操作 */\n created: boolean;\n /** 是否为更新操作 */\n updated: boolean;\n};\n\nexport async function dbUpsert<D1, C extends DbCreate<D1>, U extends DbUpdate<D1>>(\n db: Db<D1>,\n options: DbUpsertOptions<D1, C, U>,\n): Promise<DbUpsertOutput> {\n const { create, update, onBeforeCreate, onAfterCreate, onBeforeUpdate, onAfterUpdate, _mockDbInstance } = options;\n\n const _mutateDb = (_mockDbInstance || db.clone()) as Db<D1>;\n const _queryDb = (_mockDbInstance || db.clone(true)) as Db<D1>;\n\n const exist = (await _queryDb\n .where(db.getWhere(true))\n // biome-ignore lint/complexity/noBannedTypes: 必须这么用\n .firstOrNull()) as DbQuery<D1, {}, {}> | null;\n\n if (exist) {\n const skipUpdate = (await onBeforeUpdate?.(exist)) === false;\n\n if (skipUpdate) {\n // @ts-expect-error\n return { id: exist._id as string, updated: false, created: false };\n }\n\n const updateData = isFunction(update) ? update(exist) : update;\n // @ts-expect-error\n await _mutateDb.whereId(exist._id).update(updateData);\n onAfterUpdate?.(updateData, exist);\n\n // @ts-expect-error\n return { id: exist._id as string, updated: true, created: false };\n }\n\n await onBeforeCreate?.();\n const createdId = await _mutateDb.create(create);\n await onAfterCreate?.(createdId);\n\n return { id: createdId, updated: false, created: true };\n}\n","import type { Db } from './_db.class';\nimport type { DbCreate } from './types';\nimport { dbUpsert } from './upsert';\n\nexport type DbUniqueOptions<T, C extends DbCreate<T>> = {\n /** 创建数据 */\n create: C;\n\n /** 创建前回调函数 */\n onBeforeCreate?: () => unknown;\n\n /**\n * 创建后回调函数\n * @param id 创建的文档ID\n */\n onAfterCreate?: (id: string) => unknown;\n\n /** 用于测试的模拟数据库实例 */\n // biome-ignore lint/suspicious/noExplicitAny: 单测使用 any\n _mockDbInstance?: any;\n};\n\n/**\n * 数据库 upsert 操作的返回结果类型\n */\nexport type DbUniqueOutput = {\n /** 操作的文档ID */\n id: string;\n /** 是否为创建操作 */\n created: boolean;\n};\n\nexport async function dbUnique<T, C extends DbCreate<T>>(\n db: Db<T>,\n options: DbUniqueOptions<T, C>,\n): Promise<DbUniqueOutput> {\n const { id, created } = await dbUpsert(db, {\n ...options,\n // @ts-expect-error\n update: {},\n onBeforeUpdate: () => false,\n });\n return { id, created };\n}\n"],"mappings":";;;;;;AAEA,IAAa,gBAAb,MAA2B;CAKf;CACA;CACA;CANV,WAAqB;CACrB,YAAsB;CAEtB,YACE,UACA,YACA,UAIA;EANQ,KAAA,WAAA;EACA,KAAA,aAAA;EACA,KAAA,WAAA;CAIP;CAEH,OAAO,SAAS,KAAoB,IAAuB;EACzD,IAAI,IAAI,UAAU,cAChB,OAAO,IAAI,SAAS,aAAa,IAAI,IAAI,UAAU;EAGrD,OAAQ,GAAG,QAAmE,IAAI,UAAU,KAC1F,GAAG,SACH,IAAI,UAAU,kBAAkB,EAAE,KAAK,IAAI,UAC7C;CACF;CAEA,OAAO,cAAc,KAAoB,WAAmB;EAC1D,OAAO,GACJ,IAAI,IAAI,aAAa,CAAC,WAAW,IAAI,UAAU,EAClD;CACF;CAEA,OAAO,eAAe,KAAoB;EACxC,OAAO,IAAI;CACb;CAEA,OAAO,gBAAgB,KAAoB;EACzC,OAAO,IAAI;CACb;AACF;AAEA,IAAa,iBAAb,cAAoC,cAAc;CAChD,WAAqB;AACvB;AAEA,IAAa,kBAAb,cAAqC,cAAc;CACjD,YAAsB;AACxB;;;;;;AC1CA,IAAa,UAAU;;;;;;CAMrB,KAAK,UAAmB,IAAI,eAAe,MAAM,KAAK;;;;;;CAOtD,MAAM,UAAmB,IAAI,eAAe,OAAO,KAAK;;;;;;CAOxD,KAAK,UAAmB,IAAI,eAAe,MAAM,KAAK;;;;;;CAOtD,MAAM,UAAmB,IAAI,eAAe,OAAO,KAAK;;;;;;CAOxD,KAAK,UAAmB,IAAI,eAAe,MAAM,KAAK;;;;;;CAOtD,MAAM,UAAmB,IAAI,eAAe,OAAO,KAAK;;;;;;CAOxD,KAAK,UAAqB,IAAI,eAAe,MAAM,KAAK;;;;;;CAOxD,MAAM,UAAqB,IAAI,eAAe,OAAO,KAAK;;;;;;CAO1D,OAAO,SAAiB,IAAI,eAAe,QAAQ,IAAI;;;;;;CAOvD,SAAS,WACP,IAAI,eAAe,UAAU,QAAQ,EACnC,eAAe,KAAK,cAAc,UACpC,CAAC;;;;;;CAOH,MAAM,eACJ,IAAI,eAAe,OAAO,YAAY,EACpC,kBAAkB,OAAO,WAAW,KAAK,MAAM,cAAc,SAAS,GAAG,EAAE,CAAC,EAC9E,CAAC;;;;;;CAOH,KAAK,eACH,IAAI,eAAe,MAAM,YAAY,EACnC,kBAAkB,OAAO,WAAW,KAAK,MAAM,cAAc,SAAS,GAAG,EAAE,CAAC,EAC9E,CAAC;AACL;;;;AAKA,IAAa,WAAW;;;;;;CAMtB,MAAM,UAAkB,IAAI,gBAAgB,OAAO,KAAK;;;;;;CAOxD,MAAM,UAAkB,IAAI,gBAAgB,OAAO,KAAK;;;;;;CAOxD,MAAM,UAAmB,IAAI,gBAAgB,OAAO,KAAK;;;;;;CAOzD,OAAO,UAAmB,IAAI,gBAAgB,QAAQ,KAAK;;;;;;CAO3D,UAAU,UAAmB,IAAI,gBAAgB,WAAW,KAAK;;;;;CAMjE,WAAW,IAAI,gBAAgB,OAAO,KAAA,CAAS;;;;;CAM/C,aAAa,IAAI,gBAAgB,SAAS,KAAA,CAAS;;;;;CAMnD,cAAc,IAAI,gBAAgB,UAAU,KAAA,CAAS;AACvD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC7HA,eAAsB,OACpB,OACA,OACA,UACA,WAAW,OAAO,kBAClB;CACA,MAAM,QAAQ,KAAK,IAAI,MAAM,MAAM,MAAM,KAAK,EAAE,MAAM,GAAG,QAAQ;CACjE,MAAM,QAAQ;CAEd,KAAK,IAAI,OAAO,GAAG,OAAO,OAAO,QAAQ,OAAO;EAC9C,MAAM,OAAO,MAAM,MAAM,MAAM,KAAK,EAAE,MAAM,KAAK,EAAE,KAAK,IAAI,EAAE,KAAK;EAEnE,KAAK,MAAM,OAAO,MAChB,MAAM,SAAS,GAAQ;CAE3B;AACF;;;;;;;AC3CA,IAAa,UAAb,cAA6B,MAAM;;CAEjC;;CAEA;CAEA,YAAY,SAAiB,OAAqD;EAChF,MAAM,OAAO;EACb,KAAK,OAAO;EACZ,KAAK,UAAU,MAAM;EACrB,KAAK,SAAS,MAAM;CACtB;AACF;;;;;;AAOA,SAAgB,UAAU,KAA8B;CACtD,OAAO,eAAe;AACxB;;;;;;AAOA,SAAgB,iBAAiB,QAAwB;CACvD,MAAM,IAAI,OAAO,MAAM,OAAO;CAC9B,OAAO,IAAI,EAAE,KAAK;AACpB;;;;;;;;;ACxBA,eAAsB,SAQpB,SAA6B;CAE7B,MAAM,QAAQ,QAAQ,SAAS,IAAI;CAGnC,MAAM,UAAU,QAAQ,MAAM;CAS9B,OAAO;EACL,MAAA,MAPiB,QAAQ,KAAK;EAQ9B,OAAA,MALkB,QAAQ,MAAM,KAAK,EAAE,MAAM;CAM/C;AACF;;;;;;ACxBA,IAAM,QAAQ,SAAS,SAAS,EAAE,QAAQ;AAM1C,IAAM,MAAM,SAAS,SAAS;AA6E9B,IAAI,MAAM;;;;;;;;AASV,IAAa,KAAb,MAAa,GAQX;;;;;;CAMA,iBAAyB;CAEzB;;;;;;CAOA,YAAY,SAAoB;EAC9B,KAAK,WAAW;EAGhB,KAAK,iBAAiB,CAAC,CAAC,QAAQ;CAClC;;;;;;CAOA,MAAM,oBAA8B;EAClC,OAAO,IAAI,GAAG;GACZ,GAAG,KAAK;GACR,aAAa,qBAAqB,OAAO,KAAK,SAAS;EACzD,CAAC;CACH;CAEA,IAAI,QAAQ;EACV,OAAO,KAAK,SAAS;CACvB;CAEA,IAAI,UAAU;EACZ,OAAO,KAAK;CACd;CAEA,IAAI,gBAAgB;EAClB,OAAO,KAAK;CACd;CAEA,YAAY,oBAA8B;EACxC,MAAM,UAAU,KAAK;EACrB,OACE,QAAQ,kBACP,qBAAqB,OAAO,QAAQ,aAAa,WAAW,QAAQ,KAAK,KAAK,IAAI,WAAW,QAAQ,KAAK;CAE/G;;;;;CAMA,mBAAmB;EAEjB,OADa,KAAK,YACX,EAAK,UAAU;CACxB;CAEA,YAAoB;CACpB,cAAsB;CACtB,SAAiB,CAAC;;;;;;CAOlB,MAAM,OAAyB;EAC7B,IAAI,KAAK,gBAAgB,MAAM,IAAI,MAAM,uBAAuB;EAChE,IAAI,KAAK,WAAW,MAAM,IAAI,MAAM,2CAA2C;EAG/E,MAAM,YAAY,aAAa,QAAQ,UAAU,UAAU,KAAA,CAAS;EAEpE,KAAK,YAAY;EACjB,KAAK,SAAS;EAEd,OAAO;CACT;;;;;;CAOA,SAAS,OAAiB;EACxB,OAAO,QAGH,WAAW,KAAK,QAAQ,OAAO,KAAK,KAAK,SAAS,CAAC,IACnD,KAAK;CACX;;;;;;CAOA,QAAQ,IAAqB;EAC3B,IAAI,KAAK,WAAW,MAAM,IAAI,MAAM,2CAA2C;EAC/E,IAAI,KAAK,WAAW,MAAM,IAAI,MAAM,wCAAwC;EAE5E,KAAK,YAAY;EACjB,KAAK,cAAc;EACnB,KAAK,SAAS,EAAE,KAAK,GAAG;EAExB,OAAO;CACT;CAEA,aAAqB;CACrB,UAAkB,CAAC;;;;;;CAOnB,OAAqC,QAAW;EAC9C,IAAI,KAAK,YAAY,MAAM,IAAI,MAAM,sBAAsB;EAE3D,KAAK;EACL,KAAK,UAAU;EAEf,OAAO;CACT;CAEA,YAAoB;CACpB,SAAiB,CAAC;;;;;;CAOlB,MAAM,OAAoB;EACxB,IAAI,KAAK,gBAAgB,MAAM,IAAI,MAAM,sBAAsB;EAE/D,KAAK;EACL,KAAK,SAAS;EAEd,OAAO;CACT;CAEA,WAAmB;CACnB,QAAgB;;;;;;CAOhB,KAAK,MAAc;EACjB,IAAI,KAAK,gBAAgB,MAAM,IAAI,MAAM,qBAAqB;EAC9D,IAAI,KAAK,UAAU,MAAM,IAAI,MAAM,oBAAoB;EAEvD,KAAK;EACL,KAAK,QAAQ;EAEb,OAAO;CACT;CAEA,YAAoB;CACpB,SAAiB;;;;;;CAOjB,MAAM,OAAe;EACnB,IAAI,KAAK,gBAAgB,MAAM,IAAI,MAAM,sBAAsB;EAC/D,IAAI,KAAK,WAAW,MAAM,IAAI,MAAM,qBAAqB;EACzD,IAAI,KAAK,YAAY,MAAM,IAAI,MAAM,4BAA4B;EAEjE,IAAI,KAAK,aACP,MAAM,IAAI,MAAM,wCAAwC;EAG1D,KAAK;EACL,KAAK,SAAS;EAEd,OAAO;CACT;CAEA,aAAqB;CACrB,cAAsB;;;;;;CAOtB,OAAO,MAAc;EACnB,IAAI,KAAK,gBAAgB,MAAM,IAAI,MAAM,uBAAuB;EAChE,IAAI,KAAK,YAAY,MAAM,IAAI,MAAM,sBAAsB;EAC3D,IAAI,KAAK,WAAW,MAAM,IAAI,MAAM,4BAA4B;EAEhE,KAAK;EACL,KAAK,cAAc;EAEnB,OAAO;CACT;CAEA,aAAqB;CACrB,IAAI,YAAY;EACd,OAAO,KAAK,aAAa;CAC3B;CAEA,WAA+B,CAAC;CAChC,OAUE,OAA+B,QAAkD;EACjF,IAAI,KAAK,gBAAgB,MAAM,IAAI,MAAM,uBAAuB;EAGhE,MAAM;EACN,KAAK;EACL,KAAK,SAAS,KAAK;GACjB,GAAG;GACH;EACF,CAAwB;EAGxB,OAAO;CAMT;CAEA,UAAkB;CAElB,cAAsB;CACtB,YAAoB,CAAC;CACrB,cAAsB,QAAqC;EACzD,IAAI,KAAK,aAAa,MAAM,IAAI,MAAM,YAAY,KAAK,MAAM,QAAQ;EACrE,IAAI,KAAK,SAAS,MAAM,IAAI,MAAM,YAAY,KAAK,MAAM,QAAQ;EAEjE,KAAK,UAAU;EACf,KAAK,cAAc;EACnB,IAAI,eAAe;EACnB,IAAI,gBAAgB;EACpB,MAAM,YAAY,CAAC;EACnB,IAAI,iBAAiB;EACrB,MAAM,cAAc,CAAC;EAGrB,KAAK,MAAM,EAAE,UAAU,MAAM,IAAI,cAAc,YAAY,OAAO,cAAc,KAAK,UAAU;GAC7F,MAAM,UAAU,MAAM;GACtB,IAAI,WAAW,MAAM,SAAS;GAI9B,WAAW,SAAS,MAAM,EACxB,OAAO,EACL,MAAM,CACJ,SAAS,QACL,EAAE,KAAK,CAAC,IAAI,gBAAgB,KAAK,SAAS,EAAE,IAC5C,EAAE,KAAK,CAAC,IAAI,gBAAgB,KAAK,SAAS,EAAE,CAClD,EACF,EACF,CAAC;GAID,WAAW,MAAM,cAAc,QAAQ;GAGvC,WAAW,SAAS,KAAK;GAEzB,eAAe,aAAa,OAAO;IACjC,KAAK,GACF,UAAU,IAAI,aACjB;IACA;IACA,MAAM,MAAM;IACZ;GACF,CAAC;GAGD,IAAI,SAAS,OAEX,eAAe,aAAa,OAAO;IACjC,MAAM,IAAI;IACV,4BAA4B;GAC9B,CAAC;GAGH,IAAI,UAAU;IACZ;IACA,YAAY,MAAM;GACpB,OAAO;IACL;IACA,UAAU,MAAM;GAClB;GAEA,KAAK,UAAU,MAAM;EACvB;EAGA,IAAI,KAAK,YAAY,eAAe,aAAa,OAAO,EAAE,MAAM,KAAK,YAAY,CAAC;EAClF,IAAI,KAAK,WAAW,eAAe,aAAa,MAAM,eAAe,KAAK,MAAM,CAAC;EACjF,IAAI,KAAK,WAAW,eAAe,aAAa,KAAK,UAAU,KAAK,SAAS,MAAO,MAAM,QAAQ,IAAI,EAAG,CAAC;EAC1G,IAAI,KAAK,UAAU,eAAe,aAAa,KAAK,KAAK,KAAK;EAC9D,IAAI,KAAK,WAAW,eAAe,aAAa,MAAM,KAAK,MAAM;EAGjE,IAAI,KAAK,YACP,eAAe,aAAa,QAAQ,aAAa;GAAE,GAAG,KAAK;GAAS,GAAG;EAAU,GAAG,KAAK,MAAM,CAAC;OAG7F,IAAI,gBACP,eAAe,aAAa,QAAQ,WAAW;EAGjD,OAAO;CACT;CAEA,SAAiB,MAAoC,QAA4D;EAC/G,IAAI,KAAK,SAAS,MAAM,IAAI,MAAM,YAAY,KAAK,MAAM,QAAQ;EACjE,KAAK,UAAU;EAGf,IACE,KAAK,mBACJ,WAAW,WAAW,WAAW,YAAY,WAAW,aACzD,CAAC,KAAK,aAEN,MAAM,IAAI,MAAM,wCAAwC;EAG1D,IAAI,UAAU;EACd,IAAI,KAAK,WAEP,IAAI,KAAK,mBAAmB,WAAW,YAAY,WAAW,YAAY,WAAW,UAEnF,UAAU,QAAQ,IAAI,KAAK,OAAO,GAAG;OAGrC,UAAU,QAAQ,MAAM,eAAe,KAAK,MAAM,CAAC;EAIvD,IAAI,KAAK,YAEP,UAAU,QAAQ,MAAM,aAAa,KAAK,SAAS,KAAK,MAAM,CAAC;EAGjE,IAAI,KAAK,WACP,WAAW,KAAK,SAAS,KAAK,QAAQ;GAEpC,UAAU,QAAQ,QAAQ,KAAK,GAAG;EACpC,CAAC;EAIH,IAAI,KAAK,UAAU,UAAU,QAAQ,KAAK,KAAK,KAAK;EAEpD,IAAI,KAAK,aAAa,WAAW,SAE/B,UAAU,QAAQ,MAAM,KAAK,MAAM;OAChC,IAAI,KAAK,eAAe,WAAW,WAAW,CAAC,KAAK,gBAEvD,UAAU,QAAQ,MAAM,CAAC;EAE3B,OAAO;CACT;;;;;;CAOA,cAAsB,KAAe;EACnC,MAAM,UAAU,IAAI,WAAW;EAC/B,MAAM,UAAU,IAAI,UAAU,IAAI;EAClC,MAAM,SAAS,iBAAiB,IAAI,UAAU,IAAI,OAAO;EAEzD,IAAI,QACF,OAAO,IAAI,QAAQ,SAAS;GACjB;GACD;EACV,CAAC;OAED,OAAO;CAEX;;;;;;CAOA,eAAuB,KAAqB;EAC1C,IAAI,WAAW,GAAG,GAAG;GACnB,MAAM,QAAQ,KAAK,cAAc,GAAG;GACpC,MAAM,KAAK,SAAS,aAAa,KAAK,KAAK;EAC7C,OACE,MAAM,KAAK,SAAS,aAAa,GAAG,KAAK;CAE7C;;;;;CAMA,MAAM,OAAO;EACX,IAAI;GACF,IAAI;GAGJ,IAAI,KAAK,mBAAmB,KAAK,cAAc,KAAK,aAClD,MAAM,IAAI,MAAM,iCAAiC;GAInD,IAAI,KAAK,cAAc,KAAK,YAAY;IACtC,IAAI,SAAS,KAAK,iBAAiB;IACnC,SAAS,KAAK,cAAc,MAAM;IAClC,MAAM,MAAM,OAAO,IAAI;GACzB,OAEK;IACH,IAAI,UAAU,KAAK,YAAY;IAC/B,UAAU,KAAK,SAAS,SAAS,OAAO;IACxC,MAAM,MAAM,QAAQ,IAAI;GAC1B;GAEA,MAAM,EAAE,SAAS,oBAAoB,GAAG;GAGxC,OAAO,QAAQ,IAAI,IAAI,OAAO,OAAO,CAAC,IAAI,IAAI,CAAC;EACjD,SAAS,KAAK;GACZ,KAAK,eAAe,GAAG;EACzB;CACF;;;;;;CAOA,MAAM,eAA6C;EACjD,IAAI,KAAK,WAAW,MAAM,IAAI,MAAM,kCAAkC;EACtE,IAAI,CAAC,KAAK,eAAe,CAAC,KAAK,YAAY,KAAK,MAAM,CAAC;EAGvD,MAAM,OAAM,MADO,KAAK,KAAK,GACZ,GAAG,CAAC;EAErB,IAAI,CAAC,KAAK,MAAM,uBAAuB,UAAU,cAAc;EAC/D,OAAO;CACT;;;;;;CAOA,MAAM,cAAmD;EACvD,IAAI,KAAK,WAAW,MAAM,IAAI,MAAM,iCAAiC;EACrE,IAAI,CAAC,KAAK,eAAe,CAAC,KAAK,YAAY,KAAK,MAAM,CAAC;EAGvD,QAAO,MADY,KAAK,KAAK,GACjB,GAAG,CAAC,KAAK;CACvB;;;;;CAMA,MAAM,QAAQ;EACZ,IAAI,KAAK,gBAAgB,MAAM,IAAI,MAAM,sBAAsB;EAC/D,IAAI,KAAK,YAAY,MAAM,IAAI,MAAM,4BAA4B;EACjE,IAAI,KAAK,YAAY,MAAM,IAAI,MAAM,4BAA4B;EACjE,IAAI,KAAK,YAAY,MAAM,IAAI,MAAM,4BAA4B;EACjE,IAAI,KAAK,WAAW,MAAM,IAAI,MAAM,2BAA2B;EAC/D,IAAI,KAAK,UAAU,MAAM,IAAI,MAAM,0BAA0B;EAC7D,IAAI,KAAK,WAAW,MAAM,IAAI,MAAM,2BAA2B;EAE/D,IAAI;GACF,IAAI,UAAU,KAAK,YAAY;GAC/B,UAAU,KAAK,SAAS,SAAS,OAAO;GAExC,MAAM,EAAE,UAAU,oBAAuC,MADvC,QAAQ,MAAM,CAC4B;GAC5D,OAAO;EACT,SAAS,KAAK;GACZ,KAAK,eAAe,GAAG;EACzB;CACF;;;;;;CAOA,MAAM,OAAO,MAAoB;EAC/B,IAAI,KAAK,YAAY,MAAM,IAAI,MAAM,6BAA6B;EAClE,IAAI,KAAK,WAAW,MAAM,IAAI,MAAM,4BAA4B;EAChE,IAAI,KAAK,YAAY,MAAM,IAAI,MAAM,6BAA6B;EAClE,IAAI,KAAK,WAAW,MAAM,IAAI,MAAM,4BAA4B;EAChE,IAAI,KAAK,UAAU,MAAM,IAAI,MAAM,2BAA2B;EAC9D,IAAI,KAAK,WAAW,MAAM,IAAI,MAAM,4BAA4B;EAEhE,IAAI;GACF,IAAI,UAAU,KAAK,YAAY;GAC/B,UAAU,KAAK,SAAS,SAAS,QAAQ;GAEzC,MAAM,EAAE,OAAO,oBAAoC,MADjC,QAAQ,IAAI,IAAI,CACoB;GACtD,OAAO;EACT,SAAS,KAAK;GACZ,KAAK,eAAe,GAAG;EACzB;CACF;;;;;;CAOA,MAAM,OAAO,MAAoB;EAC/B,IAAI,KAAK,YAAY,MAAM,IAAI,MAAM,6BAA6B;EAClE,IAAI,CAAC,KAAK,WAAW,MAAM,IAAI,MAAM,iCAAiC;EACtE,IAAI,KAAK,YAAY,MAAM,IAAI,MAAM,6BAA6B;EAClE,IAAI,KAAK,WAAW,MAAM,IAAI,MAAM,4BAA4B;EAChE,IAAI,KAAK,UAAU,MAAM,IAAI,MAAM,2BAA2B;EAC9D,IAAI,KAAK,WAAW,MAAM,IAAI,MAAM,4BAA4B;EAEhE,IAAI,KAAK,kBAAkB,CAAC,KAAK,aAAa,MAAM,IAAI,MAAM,qCAAqC;EAEnG,IAAI;GACF,IAAI,UAAU,KAAK,YAAY;GAC/B,UAAU,KAAK,SAAS,SAAS,QAAQ;GAEzC,MAAM,EAAE,YAAY,oBAAyC,MAD3C,QAAQ,OAAO,WAAW,eAAe,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC,CACV;GAChE,OAAO;EACT,SAAS,KAAK;GACZ,KAAK,eAAe,GAAG;EACzB;CACF;;;;;CAMA,MAAM,SAAS;EACb,IAAI,KAAK,YAAY,MAAM,IAAI,MAAM,6BAA6B;EAClE,IAAI,CAAC,KAAK,WAAW,MAAM,IAAI,MAAM,iCAAiC;EACtE,IAAI,KAAK,YAAY,MAAM,IAAI,MAAM,6BAA6B;EAClE,IAAI,KAAK,WAAW,MAAM,IAAI,MAAM,4BAA4B;EAChE,IAAI,KAAK,UAAU,MAAM,IAAI,MAAM,2BAA2B;EAC9D,IAAI,KAAK,WAAW,MAAM,IAAI,MAAM,4BAA4B;EAEhE,IAAI,KAAK,kBAAkB,CAAC,KAAK,aAAa,MAAM,IAAI,MAAM,qCAAqC;EAEnG,IAAI;GACF,IAAI,UAAU,KAAK,YAAY;GAC/B,UAAU,KAAK,SAAS,SAAS,QAAQ;GAEzC,MAAM,EAAE,YAAY,oBAAyC,MAD3C,QAAQ,OAAO,CAC+B;GAChE,OAAO;EACT,SAAS,KAAK;GACZ,KAAK,eAAe,GAAG;EACzB;CACF;AACF;AAGA,SAAS,eAAe,MAAW;CAEjC,MAAM,OAAO,QAAkB;EAC7B,IAAI,CAAC,SAAS,GAAG,GAAG,OAAO;EAC3B,IAAI,eAAe,eAAe,OAAO,cAAc,SAAS,KAAK,GAAG;EACxE,OAAO,UAAU,KAAK,GAAG;CAC3B;CAEA,OAAO,UAAU,MAAM,GAAG;AAC5B;AAEA,SAAS,gBAAgB,OAAyB;CAChD,OAAO,UAAU,QAAQ,MAAM,SAAS,IAAI;AAC9C;AAEA,SAAS,aAAa,QAA2B,OAAyB;CAGxE,IAFiB,OAAO,KAAK,MAAM,EAAE,WAAW,GAElC,OAAO;CAIrB,IAFmB,OAAO,KAAK,MAAM,EAAE,WAAW,KAAK,SAAS,UAAU,OAAO,QAAQ,OAEzE,OAAO;CAEvB,OAAO;EACL,GAAG;EACH,GAAG,gBAAgB,KAAK;CAC1B;AACF;;;;;;;;;;AC3rBA,SAAgB,QAA0C,MAAc,SAA0B;CAChG,OAAO,IAAI,MACT,CAAC,GACD,EACE,IAAI,SAAS,MAAM;EACjB,IAAI,SAAS,YAAY,OAAO;EAEhC,MAAM,QAAQ,IAAI,GAAW;GAAE,OAAO;GAAM,GAAG;EAAQ,CAAC;EAExD,MAAM,MAAM,MAAM;EAElB,OAAO,WAAW,GAAG,IAAI,IAAI,KAAK,KAAK,IAAI;CAC7C,EACF,CACF;AACF;;;;;;;;;;;;;;;;;;;;;ACNA,eAAsB,cACpB,aAEA,eAEA,iBACA;CAGA,MAAM,CAAC,MAAM,eAAe,MAAM,YAFX,iBAAiB,SAAS,SAAS,GAEC,iBAAiB,CAAC;CAC7E,IAAI,MAAM,MAAM;CAEhB,MAAM,mBAAwC,OAAe;EAC3D,OAAO,mBAAmB,IAAI,GAAO;GAAE,GAAG,GAAG;GAAS;EAAY,CAAC;CACrE;CAEA,MAAM,CAAC,MAAM,UAAU,MAAM,WAAW,YAAY;EAClD,MAAM,SAAS,MAAM,YAAY,eAAe;EAChD,MAAM,YAAY,OAAO;EACzB,OAAO;CACT,CAAC;CAED,IAAI,MAAM;EACR,MAAM,WAAW,YAAY,SAAS,CAAC;EACvC,MAAM;CACR;CAEA,OAAO;AACT;;;ACHA,eAAsB,SACpB,IACA,SACyB;CACzB,MAAM,EAAE,QAAQ,QAAQ,gBAAgB,eAAe,gBAAgB,eAAe,oBAAoB;CAE1G,MAAM,YAAa,mBAAmB,GAAG,MAAM;CAG/C,MAAM,QAAS,OAFG,mBAAmB,GAAG,MAAM,IAAI,GAG/C,MAAM,GAAG,SAAS,IAAI,CAAC,EAEvB,YAAY;CAEf,IAAI,OAAO;EAGT,IAFoB,MAAM,iBAAiB,KAAK,MAAO,OAIrD,OAAO;GAAE,IAAI,MAAM;GAAe,SAAS;GAAO,SAAS;EAAM;EAGnE,MAAM,aAAa,WAAW,MAAM,IAAI,OAAO,KAAK,IAAI;EAExD,MAAM,UAAU,QAAQ,MAAM,GAAG,EAAE,OAAO,UAAU;EACpD,gBAAgB,YAAY,KAAK;EAGjC,OAAO;GAAE,IAAI,MAAM;GAAe,SAAS;GAAM,SAAS;EAAM;CAClE;CAEA,MAAM,iBAAiB;CACvB,MAAM,YAAY,MAAM,UAAU,OAAO,MAAM;CAC/C,MAAM,gBAAgB,SAAS;CAE/B,OAAO;EAAE,IAAI;EAAW,SAAS;EAAO,SAAS;CAAK;AACxD;;;AC7DA,eAAsB,SACpB,IACA,SACyB;CACzB,MAAM,EAAE,IAAI,YAAY,MAAM,SAAS,IAAI;EACzC,GAAG;EAEH,QAAQ,CAAC;EACT,sBAAsB;CACxB,CAAC;CACD,OAAO;EAAE;EAAI;CAAQ;AACvB"}
1
+ {"version":3,"file":"database.mjs","names":[],"sources":["../src/database/_command.class.ts","../src/database/command.ts","../src/database/each.ts","../src/database/error.ts","../src/database/paging.ts","../src/database/_db.class.ts","../src/database/proxy.ts","../src/database/transaction.ts","../src/database/upsert.ts","../src/database/unique.ts"],"sourcesContent":["// 设置私有属性和静态方法是避免在 update 的时候提示类属性\n\nexport class DbBaseCommand {\n protected _isQuery = false;\n protected _isMutate = false;\n\n constructor(\n private _command: string,\n private _parameter: unknown,\n private _options?: {\n formatParameter?: (db: UniCloud.Database) => unknown;\n rewriteValue?: (db: UniCloud.Database, parameter: unknown) => unknown;\n },\n ) {}\n\n static getValue(cmd: DbBaseCommand, db: UniCloud.Database) {\n if (cmd._options?.rewriteValue) {\n return cmd._options.rewriteValue(db, cmd._parameter);\n }\n\n return (db.command as unknown as Record<string, (value: unknown) => unknown>)[cmd._command].call(\n db.command,\n cmd._options?.formatParameter?.(db) || cmd._parameter,\n );\n }\n\n static getExpression(cmd: DbBaseCommand, fieldName: string) {\n return {\n [`$${cmd._command}`]: [fieldName, cmd._parameter],\n };\n }\n\n static isQueryCommand(cmd: DbBaseCommand) {\n return cmd._isQuery;\n }\n\n static isMutateCommand(cmd: DbBaseCommand) {\n return cmd._isMutate;\n }\n}\n\nexport class DbQueryCommand extends DbBaseCommand {\n protected _isQuery = true;\n}\n\nexport class DbMutateCommand extends DbBaseCommand {\n protected _isMutate = true;\n}\n","import { DbBaseCommand, DbMutateCommand, DbQueryCommand } from './_command.class';\n\n/**\n * 数据库查询命令对象,提供各种查询操作符\n */\nexport const dbQuery = {\n /**\n * 等于操作符\n * @param value 比较值\n * @returns DbQueryCommand 查询命令对象\n */\n eq: (value: unknown) => new DbQueryCommand('eq', value),\n\n /**\n * 不等于操作符\n * @param value 比较值\n * @returns DbQueryCommand 查询命令对象\n */\n neq: (value: unknown) => new DbQueryCommand('neq', value),\n\n /**\n * 大于操作符\n * @param value 比较值\n * @returns DbQueryCommand 查询命令对象\n */\n gt: (value: unknown) => new DbQueryCommand('gt', value),\n\n /**\n * 大于等于操作符\n * @param value 比较值\n * @returns DbQueryCommand 查询命令对象\n */\n gte: (value: unknown) => new DbQueryCommand('gte', value),\n\n /**\n * 小于操作符\n * @param value 比较值\n * @returns DbQueryCommand 查询命令对象\n */\n lt: (value: unknown) => new DbQueryCommand('lt', value),\n\n /**\n * 小于等于操作符\n * @param value 比较值\n * @returns DbQueryCommand 查询命令对象\n */\n lte: (value: unknown) => new DbQueryCommand('lte', value),\n\n /**\n * 包含在数组中操作符\n * @param value 值数组\n * @returns DbQueryCommand 查询命令对象\n */\n in: (value: unknown[]) => new DbQueryCommand('in', value),\n\n /**\n * 不包含在数组中操作符\n * @param value 值数组\n * @returns DbQueryCommand 查询命令对象\n */\n nin: (value: unknown[]) => new DbQueryCommand('nin', value),\n\n /**\n * 数组长度匹配操作符\n * @param size 数组长度\n * @returns DbQueryCommand 查询命令对象\n */\n size: (size: number) => new DbQueryCommand('size', size),\n\n /**\n * 正则表达式匹配操作符\n * @param regExp 正则表达式\n * @returns DbQueryCommand 查询命令对象\n */\n regExp: (regExp: RegExp) =>\n new DbQueryCommand('regExp', regExp, {\n rewriteValue: (_db, parameter) => parameter,\n }),\n\n /**\n * 逻辑与操作符\n * @param conditions 查询条件参数\n * @returns DbQueryCommand 查询命令对象\n */\n and: (conditions: DbQueryCommand[]) =>\n new DbQueryCommand('and', conditions, {\n formatParameter: (db) => conditions.map((c) => DbBaseCommand.getValue(c, db)),\n }),\n\n /**\n * 逻辑或操作符\n * @param conditions 查询条件参数\n * @returns DbQueryCommand 查询命令对象\n */\n or: (conditions: DbQueryCommand[]) =>\n new DbQueryCommand('or', conditions, {\n formatParameter: (db) => conditions.map((c) => DbBaseCommand.getValue(c, db)),\n }),\n};\n\n/**\n * 数据库变更命令对象,提供各种数据更新操作符\n */\nexport const dbMutate = {\n /**\n * 数值增加操作符\n * @param value 增加的数值\n * @returns DbMutateCommand 变更命令对象\n */\n inc: (value: number) => new DbMutateCommand('inc', value),\n\n /**\n * 数值乘法操作符\n * @param value 乘数\n * @returns DbMutateCommand 变更命令对象\n */\n mul: (value: number) => new DbMutateCommand('mul', value),\n\n /**\n * 设置字段值操作符\n * @param value 设置的值\n * @returns DbMutateCommand 变更命令对象\n */\n set: (value: unknown) => new DbMutateCommand('set', value),\n\n /**\n * 向数组末尾添加元素操作符\n * @param value 添加的值\n * @returns DbMutateCommand 变更命令对象\n */\n push: (value: unknown) => new DbMutateCommand('push', value),\n\n /**\n * 向数组开头添加元素操作符\n * @param value 添加的值\n * @returns DbMutateCommand 变更命令对象\n */\n unshift: (value: unknown) => new DbMutateCommand('unshift', value),\n\n /**\n * 从数组末尾移除元素操作符\n * @returns DbMutateCommand 变更命令对象\n */\n pop: () => new DbMutateCommand('pop', undefined),\n\n /**\n * 从数组开头移除元素操作符\n * @returns DbMutateCommand 变更命令对象\n */\n shift: () => new DbMutateCommand('shift', undefined),\n\n /**\n * 移除字段操作符\n * @returns DbMutateCommand 变更命令对象\n */\n remove: () => new DbMutateCommand('remove', undefined),\n};\n","import type { Db } from './_db.class';\nimport type { DbWhere } from './types';\n\n/**\n * 遍历表中的每一行数据并执行回调函数\n *\n * 采用分批查询策略,每批查询 100 条记录,通过 skip/limit 实现分页遍历,\n * 避免一次性加载大量数据导致内存溢出。\n *\n * 迭代器按顺序串行执行,即每一行数据的迭代器完成后才会处理下一行。\n *\n * @template T - 数据行类型\n * @param table 数据库表代理对象\n * @param where 查询条件\n * @param iterator 对每一行数据执行的异步迭代器函数\n * @param maxCount 最大遍历数量,默认值为 Number.MAX_SAFE_INTEGER。\n * 注意:由于分批查询机制(每批 100 条),实际遍历的行数可能略大于 maxCount,\n * 例如 maxCount=150 时,会分两批查询(0-99、100-199),实际遍历 200 行。\n * @example\n * ```ts\n * // 遍历所有状态为 active 的用户\n * await dbEach(userTable, { status: 'active' }, async (user) => {\n * await sendEmail(user.email);\n * });\n *\n * // 限制最多遍历 500 条记录\n * await dbEach(orderTable, { status: 'pending' }, async (order) => {\n * await processOrder(order);\n * }, 500);\n * ```\n */\nexport async function dbEach<T>(\n table: Db<T>,\n where: DbWhere<T>,\n iterator: (row: T) => Promise<unknown>,\n maxCount = Number.MAX_SAFE_INTEGER,\n) {\n const count = Math.min(await table.where(where).count(), maxCount);\n const limit = 100;\n\n for (let skip = 0; skip < count; skip += limit) {\n const rows = await table.where(where).limit(limit).skip(skip).many();\n\n for (const row of rows) {\n await iterator(row as T);\n }\n }\n}\n","/**\n * 数据库底层异常类\n * 当 uniCloud 数据库操作抛出错误时,统一包装为该异常\n */\nexport class DbError extends Error {\n /** 原始错误码,如 'InternalServerError' */\n errCode: string | number;\n /** MongoDB 错误码,如 'E11000'。不匹配则为空字符串 */\n dbCode: string;\n\n constructor(message: string, extra: { errCode: string | number; dbCode: string }) {\n super(message);\n this.name = 'DbError';\n this.errCode = extra.errCode;\n this.dbCode = extra.dbCode;\n }\n}\n\n/**\n * 判断错误是否为数据库底层错误\n * @param err - 任意错误对象\n * @returns 是否为 DbError\n */\nexport function isDbError(err: unknown): err is DbError {\n return err instanceof DbError;\n}\n\n/**\n * 从 MongoDB 错误消息中提取错误码\n * @param errMsg - 错误消息字符串,如 'E11000 duplicate key error...'\n * @returns MongoDB 错误码,如 'E11000'\n */\nexport function extractMongoCode(errMsg: string): string {\n const m = errMsg.match(/^E\\d+/);\n return m ? m[0] : '';\n}\n","import type { AnyObject } from '@cloudcome/utils-core/types';\nimport type { Db } from './_db.class';\nimport type { DbSelect } from './types';\n\n/**\n * 数据库分页查询函数\n * @template T - 数据类型\n * @param queryDb - 数据库查询实例\n * @returns 包含数据列表和总数的对象\n */\n\nexport async function dbPaging<\n D1,\n // biome-ignore lint/complexity/noBannedTypes: 必须这么用\n S1 extends DbSelect<D1> = {},\n // biome-ignore lint/complexity/noBannedTypes: 必须这么用\n D2 extends AnyObject = {},\n // biome-ignore lint/complexity/noBannedTypes: 必须这么用\n W2 extends AnyObject = {},\n>(queryDb: Db<D1, S1, D2, W2>) {\n // 获取原始查询条件,不包映射字段\n const where = queryDb.getWhere(true);\n\n // 克隆查询实例用于统计总数,避免影响原查询\n const countDb = queryDb.clone();\n\n // 执行查询获取数据列表\n const list = await queryDb.many();\n\n // 基于相同查询条件统计总数\n const total = await countDb.where(where).count();\n\n // 返回分页结果\n return {\n list,\n total,\n };\n}\n","import { isUniError, parseDatabaseOutput } from '@/_helpers';\nimport type { UniError } from '@/_types';\nimport { createCloudObjectError } from '@/cloud';\nimport { objectEach, objectFilter, objectMap, objectOmit } from '@cloudcome/utils-core/object';\nimport { isArray, isObject } from '@cloudcome/utils-core/type';\nimport type { AnyObject, MergeIntersection } from '@cloudcome/utils-core/types';\nimport { DbBaseCommand, type DbQueryCommand } from './_command.class';\nimport { DbError, extractMongoCode } from './error';\nimport type { DbCreate, DbForeign, DbOrder, DbQuery, DbRelation, DbSelect, DbUpdate, DbWhere } from './types';\n\n/**\n * 数据库聚合操作符命令\n */\nconst dbAgg = uniCloud.database().command.aggregate as UniCloud.AggregateCommand & {\n pipeline: () => UniCloud.AggregateReference & {\n done: () => unknown;\n };\n};\n\nconst db0 = uniCloud.database();\n\nexport type DbOptions = {\n /**\n * 数据表名称\n */\n table: string;\n\n /**\n * 事务对象,用于事务操作\n */\n // biome-ignore lint/suspicious/noExplicitAny: 必须这么用\n transaction?: any;\n\n /**\n * 模拟数据库,用于单元测试\n */\n // biome-ignore lint/suspicious/noExplicitAny: 单测使用 any\n _mockDatabase?: any;\n\n /**\n * 自定义错误处理函数\n * @param error unknown 数据库异常对象\n * @returns 自定义错误对象\n */\n parseError?: (error: unknown) => UniError;\n};\n\nexport type DbLookupOptions<\n RL extends DbRelation,\n D1,\n FD1,\n AS,\n // biome-ignore lint/suspicious/noConfusingVoidType: 必须这么用\n US extends boolean | undefined | void = undefined,\n LF extends keyof D1 & string = keyof D1 & string,\n> = {\n /**\n * 关联类型\n */\n relation: RL;\n\n /**\n * 主表字段\n */\n localField: LF;\n\n /**\n * 关联表字段\n */\n foreignField: keyof FD1 & string;\n\n /**\n * 关联数据在结果中的字段名\n */\n as: AS;\n\n /**\n * 是否取消筛选关联数据\n */\n unselect?: US;\n};\n\nexport type DbLookup = DbLookupOptions<\n // biome-ignore lint/suspicious/noExplicitAny: 必须这么用\n any,\n unknown,\n unknown,\n string,\n boolean\n> & {\n /**\n * 关联表\n */\n table: Db<unknown>;\n};\n\nlet gid = 0;\n\n/**\n * 数据库类\n * @template D1 - 主表数据\n * @template S1 - 主表筛选\n * @template D2 - 副表数据\n * @template W2 - 副表查询\n */\nexport class Db<\n D1,\n // biome-ignore lint/complexity/noBannedTypes: 必须这么用\n S1 extends DbSelect<D1> = {},\n // biome-ignore lint/complexity/noBannedTypes: 必须这么用\n D2 extends AnyObject = {},\n // biome-ignore lint/complexity/noBannedTypes: 必须这么用\n W2 extends AnyObject = {},\n> {\n /**\n * 是否为事务环境\n * - 更新条件只能是 id\n * - 删除条件只能是 id\n */\n private _isTransaction = false;\n\n private _options: DbOptions;\n\n /**\n * 构造函数,初始化数据库集合引用\n * @param collection 数据表名称\n * @param _mockDatabase 模拟数据库,用于单元测试\n */\n constructor(options: DbOptions) {\n this._options = options;\n // hostRef =\n // options._mockDatabase || options.transaction?.collection(options.table) || db0.collection(options.table);\n this._isTransaction = !!options.transaction;\n }\n\n /**\n * 创建一个新的数据库实例,可选是否移除事务\n * @param withoutTransaction 是否移除事务,默认 false\n * @returns 新的数据库实例\n */\n clone(withoutTransaction?: boolean) {\n return new Db({\n ...this._options,\n transaction: withoutTransaction ? null : this._options.transaction,\n });\n }\n\n get table() {\n return this._options.table;\n }\n\n get options() {\n return this._options;\n }\n\n get isTransaction() {\n return this._isTransaction;\n }\n\n _createHost(withoutTransaction?: boolean) {\n const options = this._options;\n return (\n options._mockDatabase ||\n (withoutTransaction ? null : options.transaction?.collection(options.table) || db0.collection(options.table))\n );\n }\n\n /**\n * 获取聚合操作实例\n * @returns 聚合操作实例\n */\n _createAggregate() {\n const host = this._createHost();\n return host.aggregate();\n }\n\n private _hasWhere = false;\n private _hasWhereId = false;\n private _where = {};\n\n /**\n * 设置查询条件\n * @param where 查询条件对象\n * @returns 当前Db实例,支持链式调用\n */\n where(where: DbWhere<D1> & W2) {\n if (this._isTransaction) throw new Error('事务模式下请使用 whereId() 方法');\n if (this._hasWhere) throw new Error('已调用过一次 db.where({...}) 或 db.whereId(id) 了');\n\n // 过滤掉值为 undefined 的键值对,数据库不支持查询全 undefined 值\n const realWhere = objectFilter(where, (value) => value !== undefined);\n\n this._hasWhere = true;\n this._where = realWhere;\n\n return this;\n }\n\n /**\n * 获取当前查询条件\n * @param plain 是否返回原始查询条件对象,默认 false\n * @returns 当前查询条件对象\n */\n getWhere(plain?: boolean) {\n return plain\n ? // biome-ignore lint/suspicious/noTsIgnore: 必须这么用\n // @ts-ignore\n objectOmit(this._where, Object.keys(this._lookupAs))\n : this._where;\n }\n\n /**\n * 根据ID设置查询条件\n * @param id 记录ID\n * @returns 当前Db实例,支持链式调用\n */\n whereId(id: string | number) {\n if (this._hasWhere) throw new Error('已调用过一次 db.where({...}) 或 db.whereId(id) 了');\n if (this._hasLimit) throw new Error('db.whereId(id) 方法不能与 db.limit() 方法同时调用');\n\n this._hasWhere = true;\n this._hasWhereId = true;\n this._where = { _id: id };\n\n return this;\n }\n\n private _hasSelect = 0;\n private _select = {};\n\n /**\n * 指定要返回的字段\n * @param fields 要返回的字段对象,true表示返回,false表示不返回\n * @returns 当前Db实例,支持链式调用\n */\n select<const S extends DbSelect<D1>>(fields: S) {\n if (this._hasSelect) throw new Error('db.select() 方法只能调用一次');\n\n this._hasSelect++;\n this._select = fields;\n\n return this as Db<D1, S, D2, W2>;\n }\n\n private _hasOrder = 0;\n private _order = {};\n\n /**\n * 设置排序规则\n * @param order 排序规则对象,key为字段名,value为\"asc\"或\"desc\"\n * @returns 当前Db实例,支持链式调用\n */\n order(order: DbOrder<D1>) {\n if (this._isTransaction) throw new Error('db.order() 方法不支持事务模式');\n\n this._hasOrder++;\n this._order = order;\n\n return this;\n }\n\n private _hasSkip = 0;\n private _skip = 0;\n\n /**\n * 跳过指定数量的记录\n * @param skip 要跳过的记录数\n * @returns 当前Db实例,支持链式调用\n */\n skip(skip: number) {\n if (this._isTransaction) throw new Error('db.skip() 方法不支持事务模式');\n if (this._hasSkip) throw new Error('db.skip() 方法只能调用一次');\n\n this._hasSkip++;\n this._skip = skip;\n\n return this;\n }\n\n private _hasLimit = 0;\n private _limit = 0;\n\n /**\n * 限制返回的记录数量\n * @param limit 最大返回记录数\n * @returns 当前Db实例,支持链式调用\n */\n limit(limit: number) {\n if (this._isTransaction) throw new Error('db.limit() 方法不支持事务模式');\n if (this._hasLimit) throw new Error('db.limit() 方法只能调用一次');\n if (this._hasSample) throw new Error('db.limit() 方法不支持 sample 条件');\n\n if (this._hasWhereId) {\n throw new Error('db.limit() 方法不能与 db.whereId(id) 方法同时调用');\n }\n\n this._hasLimit++;\n this._limit = limit;\n\n return this;\n }\n\n private _hasSample = 0;\n private _sampleSize = 0;\n\n /**\n * 随机从文档中选取指定数量的记录\n * @param size 要选取的记录数量,必须为正整数\n * @returns 当前Db实例,支持链式调用\n */\n sample(size: number) {\n if (this._isTransaction) throw new Error('db.sample() 方法不支持事务模式');\n if (this._hasSample) throw new Error('db.sample() 方法只能调用一次');\n if (this._hasLimit) throw new Error('db.sample() 方法不支持 limit 条件');\n\n this._hasSample++;\n this._sampleSize = size;\n\n return this;\n }\n\n private _hasLookup = 0;\n get hasLookup() {\n return this._hasLookup > 0;\n }\n\n private _lookups: DbLookup[] = [];\n lookup<\n FD1,\n FS1 extends DbSelect<FD1>,\n FD2 extends AnyObject,\n FW2 extends AnyObject,\n RL extends DbRelation,\n AS extends string,\n // biome-ignore lint/suspicious/noConfusingVoidType: 必须这么用\n US extends boolean | undefined | void = undefined,\n LF extends keyof D1 & string = keyof D1 & string,\n >(table: Db<FD1, FS1, FD2, FW2>, lookup: DbLookupOptions<RL, D1, FD1, AS, US, LF>) {\n if (this._isTransaction) throw new Error('db.lookup() 方法不支持事务模式');\n\n // 对方表也记为关联查询,避免做表更新操作\n table._hasLookup++;\n this._hasLookup++;\n this._lookups.push({\n ...lookup,\n table,\n } as unknown as DbLookup);\n\n // @ts-expect-error\n return this as Db<\n D1,\n S1,\n US extends true ? D2 : MergeIntersection<D2 & DbForeign<D1, FD1, FS1, FD2, RL, AS, LF>>,\n MergeIntersection<W2 & Partial<Record<AS, DbQueryCommand>>>\n >;\n }\n\n private _ending = false;\n\n private _aggregated = false;\n private _lookupAs = {} as Record<string, true>;\n private _endAggregate(aggRef: UniCloud.AggregateReference) {\n if (this._aggregated) throw new Error(`相同的数据表实例(${this.table})不能重复使用`);\n if (this._ending) throw new Error(`相同的数据表实例(${this.table})不能重复使用`);\n\n this._ending = true;\n this._aggregated = true;\n let returnAggRef = aggRef;\n let _hasAggSelect = 0;\n const aggSelect = {} as Record<string, true>;\n let hasAggUnselect = 0;\n const aggUnselect = {} as Record<string, false>;\n\n // 后做关联查询\n for (const { relation: type, as, foreignField, localField, table, unselect } of this._lookups) {\n const letName = `let${gid++}`;\n let pipeline = dbAgg.pipeline();\n\n // 关联条件\n // @ts-expect-error\n pipeline = pipeline.match({\n $expr: {\n $and: [\n type === 'n:1'\n ? { $in: [`$${foreignField}`, `$$${letName}`] }\n : { $eq: [`$${foreignField}`, `$$${letName}`] },\n ],\n },\n });\n\n // 其他查询条件\n // @ts-expect-error\n pipeline = table._endAggregate(pipeline);\n\n // @ts-expect-error\n pipeline = pipeline.done();\n\n returnAggRef = returnAggRef.lookup({\n let: {\n [letName]: `$${localField}`,\n },\n as,\n from: table.table,\n pipeline,\n });\n\n // 1对1,展开数组\n if (type === '1:1') {\n // @ts-expect-error\n returnAggRef = returnAggRef.unwind({\n path: `$${as}`,\n preserveNullAndEmptyArrays: true,\n });\n }\n\n if (unselect) {\n hasAggUnselect++;\n aggUnselect[as] = false;\n } else {\n _hasAggSelect++;\n aggSelect[as] = true;\n }\n\n this._lookupAs[as] = true;\n }\n\n // 主表查询,注意顺序,筛选->排序->跳过->限制\n if (this._hasWhere) returnAggRef = returnAggRef.match(_mapCommandRaw(this._where));\n if (this._hasSample) returnAggRef = returnAggRef.sample({ size: this._sampleSize });\n if (this._hasOrder) returnAggRef = returnAggRef.sort(objectMap(this._order, (v) => (v === 'asc' ? 1 : -1)));\n if (this._hasSkip) returnAggRef = returnAggRef.skip(this._skip);\n if (this._hasLimit) returnAggRef = returnAggRef.limit(this._limit);\n\n // 如果主表有选择字段,则合并选择字段(包括关联查询的字段和排序字段)\n if (this._hasSelect) {\n returnAggRef = returnAggRef.project(_mergeSelect({ ...this._select, ...aggSelect }, this._order));\n }\n // 如果主表没有选择字段,则排除取消选择字段\n else if (hasAggUnselect) {\n returnAggRef = returnAggRef.project(aggUnselect);\n }\n\n return returnAggRef;\n }\n\n private _endHost(host: UniCloud.CollectionReference, action: 'query' | 'create' | 'update' | 'remove' | 'count') {\n if (this._ending) throw new Error(`相同的数据表实例(${this.table})不能重复使用`);\n this._ending = true;\n\n // 事务模式下:查询/更新/删除必须使用 whereId\n if (\n this._isTransaction &&\n (action === 'query' || action === 'update' || action === 'remove') &&\n !this._hasWhereId\n ) {\n throw new Error('事务模式下查询/更新/删除条件只能是 ID,请使用 whereId() 方法');\n }\n\n let hostRef = host;\n if (this._hasWhere) {\n // 事务模式下:更新/删除/查询只能用 doc(id)\n if (this._isTransaction && (action === 'update' || action === 'remove' || action === 'query')) {\n // @ts-expect-error\n hostRef = hostRef.doc(this._where._id);\n } else {\n // @ts-expect-error\n hostRef = hostRef.where(_mapCommandRaw(this._where));\n }\n }\n\n if (this._hasSelect) {\n // @ts-expect-error\n hostRef = hostRef.field(_mergeSelect(this._select, this._order));\n }\n\n if (this._hasOrder) {\n objectEach(this._order, (val, key) => {\n // @ts-expect-error\n hostRef = hostRef.orderBy(key, val);\n });\n }\n\n // @ts-expect-error\n if (this._hasSkip) hostRef = hostRef.skip(this._skip);\n\n if (this._hasLimit && action === 'query')\n // @ts-expect-error\n hostRef = hostRef.limit(this._limit);\n else if (this._hasWhereId && action === 'query' && !this._isTransaction)\n // @ts-expect-error\n hostRef = hostRef.limit(1);\n\n return hostRef;\n }\n\n /**\n * 将 uniCloud 数据库原始错误包装为 DbError\n * @param err - 原始错误对象,来自 uniCloud DB 操作(Error 实例,含 errMsg、errCode 属性)\n * @returns DbError 实例\n */\n private _parseDbError(err: UniError) {\n const errCode = err.errCode || '';\n const message = err.errMsg || err.message;\n const dbCode = extractMongoCode(err.errMsg || err.message);\n\n if (dbCode) {\n return new DbError(message, {\n errCode: errCode,\n dbCode: dbCode,\n });\n } else {\n return err;\n }\n }\n\n /**\n * 统一处理 DB 操作抛出的错误\n * - uniCloud 数据库错误(含 errMsg)→ 包装为 DbError → 经 parseError 回调后抛出\n * - 非数据库错误(如网络中断)→ 原样抛出\n */\n private _handleDbError(err: unknown): never {\n if (isUniError(err)) {\n const dbErr = this._parseDbError(err);\n throw this._options.parseError?.(dbErr) || dbErr;\n } else {\n throw this._options.parseError?.(err) || err;\n }\n }\n\n /**\n * 执行查询操作\n * @returns 查询结果\n */\n async many() {\n try {\n let res: { data: DbQuery<D1, S1, D2>[] | DbQuery<D1, S1, D2> | undefined };\n\n // 事务模式下不支持聚合查询\n if (this._isTransaction && (this._hasLookup || this._hasSample)) {\n throw new Error('事务模式下不支持 lookup 聚合或 sample 取样查询');\n }\n\n // 关联查询 / sample 查询(sample 依赖聚合管线)\n if (this._hasLookup || this._hasSample) {\n let aggRef = this._createAggregate();\n aggRef = this._endAggregate(aggRef);\n res = await aggRef.end();\n }\n // 单表查询\n else {\n let hostRef = this._createHost();\n hostRef = this._endHost(hostRef, 'query');\n res = await hostRef.get();\n }\n\n const { data } = parseDatabaseOutput(res);\n\n // doc(id).get() 返回单个对象或 undefined,需包装为数组以统一 many() 返回值\n return isArray(data) ? data : data ? [data] : [];\n } catch (err) {\n this._handleDbError(err);\n }\n }\n\n /**\n * 只查询一条,自动添加 limit(1) 条件\n * 如果没有匹配到记录,会抛出错误\n * @returns 查询结果\n */\n async firstOrThrow(): Promise<DbQuery<D1, S1, D2>> {\n if (this._hasLimit) throw new Error('db.firstOrThrow() 方法不支持 limit 条件');\n if (!this._hasWhereId && !this._hasSample) this.limit(1);\n\n const data = await this.many();\n const res = data.at(0);\n\n if (!res) throw createCloudObjectError('查询数据为空', 'firstOrThrow');\n return res;\n }\n\n /**\n * 只查询一条,自动添加 limit(1) 条件\n * 如果没有匹配到记录,返回 null\n * @returns 查询结果或 null\n */\n async firstOrNull(): Promise<DbQuery<D1, S1, D2> | null> {\n if (this._hasLimit) throw new Error('db.firstOrNull() 方法不支持 limit 条件');\n if (!this._hasWhereId && !this._hasSample) this.limit(1);\n\n const data = await this.many();\n return data.at(0) || null;\n }\n\n /**\n * 获取匹配记录的数量\n * @returns 记录总数\n */\n async count() {\n if (this._isTransaction) throw new Error('db.count() 方法不支持事务模式');\n if (this._hasSample) throw new Error('db.count() 方法不支持 sample 取样');\n if (this._hasLookup) throw new Error('db.count() 方法不支持 lookup 聚合');\n if (this._hasSelect) throw new Error('db.count() 方法不支持 select 条件');\n if (this._hasOrder) throw new Error('db.count() 方法不支持 order 条件');\n if (this._hasSkip) throw new Error('db.count() 方法不支持 skip 条件');\n if (this._hasLimit) throw new Error('db.count() 方法不支持 limit 条件');\n\n try {\n let hostRef = this._createHost();\n hostRef = this._endHost(hostRef, 'count');\n const res = await hostRef.count();\n const { total } = parseDatabaseOutput<{ total: number }>(res);\n return total;\n } catch (err) {\n this._handleDbError(err);\n }\n }\n\n /**\n * 创建新记录\n * @param data 要创建的数据\n * @returns 创建结果\n */\n async create(data: DbCreate<D1>) {\n if (this._hasLookup) throw new Error('db.create() 方法不支持 lookup 聚合');\n if (this._hasWhere) throw new Error('db.create() 方法不支持 where 条件');\n if (this._hasSelect) throw new Error('db.create() 方法不支持 select 条件');\n if (this._hasOrder) throw new Error('db.create() 方法不支持 order 条件');\n if (this._hasSkip) throw new Error('db.create() 方法不支持 skip 条件');\n if (this._hasLimit) throw new Error('db.create() 方法不支持 limit 条件');\n\n try {\n let hostRef = this._createHost();\n hostRef = this._endHost(hostRef, 'create');\n const res = await hostRef.add(data);\n const { id } = parseDatabaseOutput<{ id: string }>(res);\n return id;\n } catch (err) {\n this._handleDbError(err);\n }\n }\n\n /**\n * 更新记录\n * @param data 要更新的数据\n * @returns 更新结果\n */\n async update(data: DbUpdate<D1>) {\n if (this._hasLookup) throw new Error('db.update() 方法不支持 lookup 聚合');\n if (!this._hasWhere) throw new Error('设置 where 条件后才能执行 db.update() 方法');\n if (this._hasSelect) throw new Error('db.update() 方法不支持 select 条件');\n if (this._hasOrder) throw new Error('db.update() 方法不支持 order 条件');\n if (this._hasSkip) throw new Error('db.update() 方法不支持 skip 条件');\n if (this._hasLimit) throw new Error('db.update() 方法不支持 limit 条件');\n\n if (this._isTransaction && !this._hasWhereId) throw new Error('事务模式下 db.update() 的 where 条件必须是 _id');\n\n try {\n let hostRef = this._createHost();\n hostRef = this._endHost(hostRef, 'update');\n const res = await hostRef.update(objectOmit(_mapCommandRaw(data), ['_id']));\n const { updated } = parseDatabaseOutput<{ updated: number }>(res);\n return updated;\n } catch (err) {\n this._handleDbError(err);\n }\n }\n\n /**\n * 删除记录\n * @returns 删除结果\n */\n async remove() {\n if (this._hasLookup) throw new Error('db.remove() 方法不支持 lookup 聚合');\n if (!this._hasWhere) throw new Error('设置 where 条件后才能执行 db.remove() 方法');\n if (this._hasSelect) throw new Error('db.remove() 方法不支持 select 条件');\n if (this._hasOrder) throw new Error('db.remove() 方法不支持 order 条件');\n if (this._hasSkip) throw new Error('db.remove() 方法不支持 skip 条件');\n if (this._hasLimit) throw new Error('db.remove() 方法不支持 limit 条件');\n\n if (this._isTransaction && !this._hasWhereId) throw new Error('事务模式下 db.remove() 的 where 条件必须是 _id');\n\n try {\n let hostRef = this._createHost();\n hostRef = this._endHost(hostRef, 'remove');\n const res = await hostRef.remove();\n const { deleted } = parseDatabaseOutput<{ deleted: number }>(res);\n return deleted;\n } catch (err) {\n this._handleDbError(err);\n }\n }\n}\n\n// biome-ignore lint/suspicious/noExplicitAny: 必须这么用\nfunction _mapCommandRaw(data: any) {\n // biome-ignore lint/suspicious/noExplicitAny: 必须这么用\n const map = (val: any): any => {\n if (!isObject(val)) return val;\n if (val instanceof DbBaseCommand) return DbBaseCommand.getValue(val, db0);\n return objectMap(val, map);\n };\n\n return objectMap(data, map);\n}\n\nfunction _mapOrderSelect(order: DbOrder<unknown>) {\n return objectMap(order, (_val, _key) => true);\n}\n\nfunction _mergeSelect(select: DbSelect<unknown>, order: DbOrder<unknown>) {\n const noSelect = Object.keys(select).length === 0;\n // 如果没有 select 条件,默认返回所有字段\n if (noSelect) return select;\n\n const onlyOmitId = Object.keys(select).length === 1 && '_id' in select && select._id === false;\n // 如果只排除 _id 字段,则保持现状\n if (onlyOmitId) return select;\n\n return {\n ...select,\n ..._mapOrderSelect(order),\n };\n}\n","import { isFunction } from '@cloudcome/utils-core/type';\nimport { Db } from './_db.class';\nimport type { DbSelect } from './types';\nimport type { UniError } from '@/_types';\n\nexport type DbProxyOptions = {\n /**\n * 自定义错误处理函数\n * @param error unknown 数据库异常对象\n * @returns 自定义错误对象\n */\n parseError?: (error: unknown) => UniError;\n};\n\n/**\n * 创建一个数据库代理对象,用于延迟实例化数据库操作类\n * @template D1 - 主表数据\n * @template S1 - 主表筛选\n * @param name - 数据库表名\n * @returns 返回一个代理对象,该对象会将属性访问转发到实际的数据库操作实例\n */\n\n// biome-ignore lint/complexity/noBannedTypes: 必须这么用\nexport function dbProxy<D1, S1 extends DbSelect<D1> = {}>(name: string, options?: DbProxyOptions) {\n return new Proxy(\n {},\n {\n get(_target, prop) {\n if (prop === '_isProxy') return true;\n\n const table = new Db<D1, S1>({ table: name, ...options });\n const tableProp = prop as keyof Db<D1, S1>;\n const ref = table[tableProp];\n\n return isFunction(ref) ? ref.bind(table) : ref;\n },\n },\n ) as Db<D1, S1>;\n}\n","import { tryFlatten } from '@cloudcome/utils-core/try';\nimport { Db } from './_db.class';\n\ntype _TransactionDb = {\n startTransaction: () => Promise<_Transaction>;\n};\n\ntype _Transaction = {\n commit: () => Promise<unknown>;\n rollback: () => Promise<unknown>;\n};\n\nexport type WithTransaction = <D1>(db: Db<D1>) => Db<D1>;\n\n/**\n * 在数据库事务中执行操作\n *\n * @template K - 事务操作返回值类型\n * @param transacting - 事务执行函数,接收事务数据库实例作为参数\n * @param _mockDatabase - 用于测试的模拟数据库对象\n * @param _mockDbInstance - 用于测试的模拟数据库实例\n * @returns 事务操作的返回结果\n *\n * @example\n * ```typescript\n * const result = await dbTransaction(async (withTransaction) => {\n * const userId = await withTransaction(db.table('user')).create({ name: 'John' });\n * const order = await withTransaction(db.table('orders')).create({ userId, amount: 100 });\n * return { user, order };\n * });\n * ```\n */\nexport async function dbTransaction<K>(\n transacting: (withTransaction: WithTransaction) => Promise<K>,\n // biome-ignore lint/suspicious/noExplicitAny: 单测使用 any\n _mockDatabase?: any,\n // biome-ignore lint/suspicious/noExplicitAny: 单测使用 any\n _mockDbInstance?: any,\n) {\n const transactionDb = (_mockDatabase || uniCloud.database()) as _TransactionDb;\n\n const [err1, transaction] = await tryFlatten(transactionDb.startTransaction());\n if (err1) throw err1;\n\n const withTransaction: WithTransaction = <D1>(db: Db<D1>) => {\n return _mockDbInstance || new Db<D1>({ ...db.options, transaction });\n };\n\n const [err2, result] = await tryFlatten(async () => {\n const result = await transacting(withTransaction);\n await transaction.commit();\n return result;\n });\n\n if (err2) {\n await tryFlatten(transaction.rollback());\n throw err2;\n }\n\n return result as unknown as K;\n}\n","import { isFunction } from '@cloudcome/utils-core/type';\nimport type { Db } from './_db.class';\nimport type { DbCreate, DbQuery, DbUpdate } from './types';\n\nexport type DbUpsertOptions<T, C extends DbCreate<T>, U extends DbUpdate<T>> = {\n /** 创建数据 */\n create: C;\n\n /**\n * 更新数据,可以是对象或根据查询结果生成更新对象的函数\n * @param row 查询到的文档数据,仅在传入函数时可用\n */\n // biome-ignore lint/complexity/noBannedTypes: 必须这么用\n update: U | ((exist: DbQuery<T, {}, {}>) => U);\n\n /** 创建前回调函数 */\n onBeforeCreate?: () => unknown;\n\n /**\n * 创建后回调函数\n * @param id 创建的文档ID\n */\n onAfterCreate?: (id: string) => unknown;\n\n /**\n * 更新前回调函数\n * @param exist 查询到的原始文档数据\n * @returns 如果返回 false,则取消更新操作\n */\n // biome-ignore lint/complexity/noBannedTypes: 必须这么用\n onBeforeUpdate?: (exist: DbQuery<T, {}, {}>) => false | unknown;\n\n /**\n * 更新后回调函数\n * @param updateData 实际更新的数据\n * @param exist 查询到的原始文档数据\n */\n // biome-ignore lint/complexity/noBannedTypes: 必须这么用\n onAfterUpdate?: (updateData: U, exist: DbQuery<T, {}, {}>) => unknown;\n\n /** 用于测试的模拟数据库实例 */\n // biome-ignore lint/suspicious/noExplicitAny: 单测使用 any\n _mockDbInstance?: any;\n};\n\n/**\n * 数据库 upsert 操作的返回结果类型\n */\nexport type DbUpsertOutput = {\n /** 操作的文档ID */\n id: string;\n /** 是否为创建操作 */\n created: boolean;\n /** 是否为更新操作 */\n updated: boolean;\n};\n\nexport async function dbUpsert<D1, C extends DbCreate<D1>, U extends DbUpdate<D1>>(\n db: Db<D1>,\n options: DbUpsertOptions<D1, C, U>,\n): Promise<DbUpsertOutput> {\n const { create, update, onBeforeCreate, onAfterCreate, onBeforeUpdate, onAfterUpdate, _mockDbInstance } = options;\n\n const _mutateDb = (_mockDbInstance || db.clone()) as Db<D1>;\n const _queryDb = (_mockDbInstance || db.clone(true)) as Db<D1>;\n\n const exist = (await _queryDb\n .where(db.getWhere(true))\n // biome-ignore lint/complexity/noBannedTypes: 必须这么用\n .firstOrNull()) as DbQuery<D1, {}, {}> | null;\n\n if (exist) {\n const skipUpdate = (await onBeforeUpdate?.(exist)) === false;\n\n if (skipUpdate) {\n // @ts-expect-error\n return { id: exist._id as string, updated: false, created: false };\n }\n\n const updateData = isFunction(update) ? update(exist) : update;\n // @ts-expect-error\n await _mutateDb.whereId(exist._id).update(updateData);\n onAfterUpdate?.(updateData, exist);\n\n // @ts-expect-error\n return { id: exist._id as string, updated: true, created: false };\n }\n\n await onBeforeCreate?.();\n const createdId = await _mutateDb.create(create);\n await onAfterCreate?.(createdId);\n\n return { id: createdId, updated: false, created: true };\n}\n","import type { Db } from './_db.class';\nimport type { DbCreate } from './types';\nimport { dbUpsert } from './upsert';\n\nexport type DbUniqueOptions<T, C extends DbCreate<T>> = {\n /** 创建数据 */\n create: C;\n\n /** 创建前回调函数 */\n onBeforeCreate?: () => unknown;\n\n /**\n * 创建后回调函数\n * @param id 创建的文档ID\n */\n onAfterCreate?: (id: string) => unknown;\n\n /** 用于测试的模拟数据库实例 */\n // biome-ignore lint/suspicious/noExplicitAny: 单测使用 any\n _mockDbInstance?: any;\n};\n\n/**\n * 数据库 upsert 操作的返回结果类型\n */\nexport type DbUniqueOutput = {\n /** 操作的文档ID */\n id: string;\n /** 是否为创建操作 */\n created: boolean;\n};\n\nexport async function dbUnique<T, C extends DbCreate<T>>(\n db: Db<T>,\n options: DbUniqueOptions<T, C>,\n): Promise<DbUniqueOutput> {\n const { id, created } = await dbUpsert(db, {\n ...options,\n // @ts-expect-error\n update: {},\n onBeforeUpdate: () => false,\n });\n return { id, created };\n}\n"],"mappings":"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"}
package/dist/index.cjs CHANGED
@@ -3,7 +3,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
3
  /**
4
4
  * `@cloudcome/utils-uni` 版本号
5
5
  */
6
- var VERSION = "1.46.0";
6
+ var VERSION = "1.48.0";
7
7
  //#endregion
8
8
  exports.VERSION = VERSION;
9
9
 
package/dist/index.mjs CHANGED
@@ -2,7 +2,7 @@
2
2
  /**
3
3
  * `@cloudcome/utils-uni` 版本号
4
4
  */
5
- var VERSION = "1.46.0";
5
+ var VERSION = "1.48.0";
6
6
  //#endregion
7
7
  export { VERSION };
8
8
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cloudcome/utils-uni",
3
- "version": "1.46.0",
3
+ "version": "1.48.0",
4
4
  "description": "cloudcome utils for uni-app",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.mjs",