From d57ca9b07c39262e9ecc0af1baa8e71a958ad41d Mon Sep 17 00:00:00 2001 From: Abdullah Atta Date: Mon, 13 Nov 2023 10:17:42 +0500 Subject: [PATCH] core: return FilteredSelector from attachments.ofNote --- packages/core/src/collections/attachments.ts | 64 ++++++++++++-------- packages/core/src/database/sql-collection.ts | 18 ++++-- 2 files changed, 52 insertions(+), 30 deletions(-) diff --git a/packages/core/src/collections/attachments.ts b/packages/core/src/collections/attachments.ts index 50beb15b9..4bb28e67f 100644 --- a/packages/core/src/collections/attachments.ts +++ b/packages/core/src/collections/attachments.ts @@ -19,21 +19,15 @@ along with this program. If not, see . import { ICollection } from "./collection"; import { getId } from "../utils/id"; -import { hasItem } from "../utils/array"; import { EV, EVENTS } from "../common"; import dataurl from "../utils/dataurl"; import dayjs from "dayjs"; -import { - DocumentMimeTypes, - getFileNameWithExtension, - isImage, - isWebClip -} from "../utils/filename"; +import { DocumentMimeTypes, getFileNameWithExtension } from "../utils/filename"; import { Cipher, DataFormat, SerializedKey } from "@notesnook/crypto"; import { Output } from "../interfaces"; import { Attachment } from "../types"; import Database from "../api"; -import { SQLCollection } from "../database/sql-collection"; +import { FilteredSelector, SQLCollection } from "../database/sql-collection"; import { isFalse } from "../database"; export class Attachments implements ICollection { @@ -234,21 +228,37 @@ export class Attachments implements ICollection { ); } - async ofNote( + ofNote( noteId: string, ...types: ("files" | "images" | "webclips" | "all")[] - ): Promise { - const noteAttachments = await this.db.relations - .from({ type: "note", id: noteId }, "attachment") - .resolve(); - - if (types.includes("all")) return noteAttachments; - - return noteAttachments.filter((a) => { - if (isImage(a.mimeType) && types.includes("images")) return true; - else if (isWebClip(a.mimeType) && types.includes("webclips")) return true; - else if (types.includes("files")) return true; - }); + ) { + const selector = this.db.relations.from( + { type: "note", id: noteId }, + "attachment" + ).selector; + return new FilteredSelector( + "attachments", + types.includes("all") + ? selector.filter + : selector.filter.where((eb) => { + const filters = []; + if (types.includes("images")) + filters.push(eb("mimeType", "like", `image/%`)); + if (types.includes("webclips")) + filters.push( + eb("mimeType", "==", `application/vnd.notesnook.web-clip`) + ); + if (types.includes("files")) { + filters.push( + eb.and([ + eb("mimeType", "!=", `application/vnd.notesnook.web-clip`), + eb("mimeType", "not like", `image/%`) + ]) + ); + } + return eb.or(filters); + }) + ); } async exists(hash: string) { @@ -337,12 +347,18 @@ export class Attachments implements ICollection { } async downloadMedia(noteId: string, hashesToLoad?: string[]) { - let attachments = await this.ofNote(noteId, "images", "webclips"); + const attachments = this.ofNote(noteId, "images", "webclips").fields([ + "attachments.id", + "attachments.hash", + "attachments.chunkSize" + ]); if (hashesToLoad) - attachments = attachments.filter((a) => hasItem(hashesToLoad, a.hash)); + attachments.where((eb) => eb.and([eb("hash", "in", hashesToLoad)])); await this.db.fs().queueDownloads( - attachments.map((a) => ({ + ( + await attachments.items() + ).map((a) => ({ filename: a.hash, chunkSize: a.chunkSize })), diff --git a/packages/core/src/database/sql-collection.ts b/packages/core/src/database/sql-collection.ts index 1ffc6d56d..588fe6c93 100644 --- a/packages/core/src/database/sql-collection.ts +++ b/packages/core/src/database/sql-collection.ts @@ -254,15 +254,14 @@ export class SQLCollection< export class FilteredSelector { private _fields: AnyColumnWithTable[] = []; + filter: SelectQueryBuilder; constructor( readonly type: keyof DatabaseSchema, - readonly filter: SelectQueryBuilder< - DatabaseSchema, - keyof DatabaseSchema, - unknown - >, + filter: SelectQueryBuilder, readonly batchSize: number = 500 - ) {} + ) { + this.filter = filter; + } fields(fields: AnyColumnWithTable[]) { this._fields = fields; @@ -330,6 +329,13 @@ export class FilteredSelector { return item as T | undefined; } + where( + expr: ExpressionOrFactory + ) { + this.filter = this.filter.where(expr); + return this; + } + async *map( fn: (item: T) => TReturnType ): AsyncIterableIterator {