diff --git a/.version b/.version index 2e6e783f7a..3f0eefd624 100644 --- a/.version +++ b/.version @@ -1 +1 @@ -0.1.168 +0.1.170 diff --git a/bun.lock b/bun.lock index 78df6e65a9..d0dc34e78c 100644 --- a/bun.lock +++ b/bun.lock @@ -39,7 +39,7 @@ "@hcengineering/communication-shared": "workspace:*", "@hcengineering/communication-types": "workspace:*", "postgres": "^3.4.4", - "uuid": "^11.0.3", + "uuid": "^11.1.0", }, "devDependencies": { "@types/bun": "^1.1.14", @@ -57,6 +57,7 @@ "@hcengineering/communication-types": "workspace:*", "@hcengineering/communication-yaml": "workspace:*", "fast-equals": "^5.0.1", + "uuid": "^11.1.0", }, "devDependencies": { "@types/bun": "^1.1.14", @@ -125,6 +126,7 @@ "name": "@hcengineering/communication-shared", "version": "0.1.0", "dependencies": { + "@hcengineering/communication-sdk-types": "workspace:*", "@hcengineering/communication-types": "workspace:*", }, "devDependencies": { diff --git a/package.json b/package.json index b0806980ee..3c7cb52242 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,8 @@ "lint": "turbo run lint", "format": "turbo run format", "reformat": "turbo run format && turbo run lint -- --fix", - "format:check": "prettier --check \"**/*.ts\"" + "format:check": "prettier --check \"**/*.ts\"", + "clean": "turbo run clean" }, "devDependencies": { "@eslint/js": "^9.24.0", diff --git a/packages/client-query/package.json b/packages/client-query/package.json index 7b600e99bc..f741f4a8c0 100644 --- a/packages/client-query/package.json +++ b/packages/client-query/package.json @@ -1,7 +1,7 @@ { "name": "@hcengineering/communication-client-query", "version": "0.1.0", - "main": "src/index.ts", + "main": "dist/index.js", "module": "dist/index.js", "types": "./types/index.d.ts", "files": [ @@ -14,7 +14,8 @@ "build:types": "tsc --project ./tsconfig.json --emitDeclarationOnly --declarationDir ./types", "build:browser": "bun build src/index.ts --outdir dist --target browser", "lint": "eslint src/*.ts", - "format": "prettier --write src/**/*.ts " + "format": "prettier --write src/**/*.ts ", + "clean": "rm -rf dist && rm -rf types && rm -rf .turbo" }, "devDependencies": { "@types/bun": "^1.1.14" diff --git a/packages/client-query/src/index.ts b/packages/client-query/src/index.ts index 8054edea47..4e4c75ce1f 100644 --- a/packages/client-query/src/index.ts +++ b/packages/client-query/src/index.ts @@ -13,8 +13,9 @@ // limitations under the License. // -import { LiveQueries, type QueryClient } from '@hcengineering/communication-query' +import { LiveQueries } from '@hcengineering/communication-query' import type { WorkspaceID } from '@hcengineering/communication-types' +import type { FindClient } from '@hcengineering/communication-sdk-types' import { LabelsQuery, MessagesQuery, NotificationContextsQuery, NotificationsQuery } from './query' @@ -38,7 +39,7 @@ export function createLabelsQuery(): LabelsQuery { } export function initLiveQueries( - client: QueryClient, + client: FindClient, workspace: WorkspaceID, filesUrl: string, destroyFn?: (fn: () => void) => void diff --git a/packages/cockroach/package.json b/packages/cockroach/package.json index 6b9a8147b1..dcd49c8db0 100644 --- a/packages/cockroach/package.json +++ b/packages/cockroach/package.json @@ -1,7 +1,7 @@ { "name": "@hcengineering/communication-cockroach", "version": "0.1.0", - "main": "src/index.ts", + "main": "dist/index.js", "module": "dist/index.js", "types": "./types/index.d.ts", "files": [ @@ -14,7 +14,8 @@ "build:types": "tsc --project ./tsconfig.json --emitDeclarationOnly --declarationDir ./types", "build:node": "bun build src/index.ts --target node --format cjs --outfile dist/index.js", "lint": "eslint src/*.ts", - "format": "prettier --write src/**/*.ts" + "format": "prettier --write src/**/*.ts", + "clean": "rm -rf dist && rm -rf types && rm -rf .turbo" }, "devDependencies": { "@types/bun": "^1.1.14" @@ -24,7 +25,7 @@ "@hcengineering/communication-sdk-types": "workspace:*", "@hcengineering/communication-types": "workspace:*", "postgres": "^3.4.4", - "uuid": "^11.0.3" + "uuid": "^11.1.0" }, "peerDependencies": { "typescript": "^5.6.3" diff --git a/packages/cockroach/src/adapter.ts b/packages/cockroach/src/adapter.ts index 5e4353ffe2..f9493b4735 100644 --- a/packages/cockroach/src/adapter.ts +++ b/packages/cockroach/src/adapter.ts @@ -89,12 +89,13 @@ export class CockroachAdapter implements DbAdapter { async createPatch( card: CardID, message: MessageID, + messageCreated: Date, type: PatchType, content: RichText, creator: SocialID, created: Date ): Promise { - await this.message.createPatch(card, message, type, content, creator, created) + await this.message.createPatch(card, message, messageCreated, type, content, creator, created) } async createMessagesGroup(card: CardID, blobId: BlobID, fromDate: Date, toDate: Date, count: number): Promise { @@ -108,20 +109,28 @@ export class CockroachAdapter implements DbAdapter { async createReaction( card: CardID, message: MessageID, + messageCreated: Date, reaction: string, creator: SocialID, created: Date ): Promise { - await this.message.createReaction(card, message, reaction, creator, created) + await this.message.createReaction(card, message, messageCreated, reaction, creator, created) } - async removeReaction(card: CardID, message: MessageID, reaction: string, creator: SocialID): Promise { - await this.message.removeReaction(card, message, reaction, creator, new Date()) + async removeReaction( + card: CardID, + message: MessageID, + messageCreated: Date, + reaction: string, + creator: SocialID + ): Promise { + await this.message.removeReaction(card, message, messageCreated, reaction, creator, new Date()) } async createFile( card: CardID, message: MessageID, + messageCreated: Date, blobId: BlobID, fileType: string, filename: string, @@ -129,15 +138,21 @@ export class CockroachAdapter implements DbAdapter { creator: SocialID, created: Date ): Promise { - await this.message.createFile(card, message, blobId, fileType, filename, size, creator, created) + await this.message.createFile(card, message, messageCreated, blobId, fileType, filename, size, creator, created) } async removeFile(card: CardID, message: MessageID, blobId: BlobID): Promise { await this.message.removeFile(card, message, blobId) } - async createThread(card: CardID, message: MessageID, thread: CardID, created: Date): Promise { - await this.message.createThread(card, message, thread, created) + async createThread( + card: CardID, + message: MessageID, + messageCreated: Date, + thread: CardID, + created: Date + ): Promise { + await this.message.createThread(card, message, messageCreated, thread, created) } async updateThread(thread: CardID, op: 'increment' | 'decrement', lastReply?: Date): Promise { diff --git a/packages/cockroach/src/db/mapping.ts b/packages/cockroach/src/db/mapping.ts index cde06de62d..3eb6012bf7 100644 --- a/packages/cockroach/src/db/mapping.ts +++ b/packages/cockroach/src/db/mapping.ts @@ -67,8 +67,8 @@ interface RawNotification extends NotificationDb { message_external_id?: string message_created?: Date message_group_blob_id?: BlobID - message_group_from_sec?: Date - message_group_to_sec?: Date + message_group_from_date?: Date + message_group_to_date?: Date message_group_count?: number message_patches?: { patch_type: PatchType @@ -100,6 +100,7 @@ export function toMessage(raw: RawMessage): Message { ? { card: raw.card_id, message: String(raw.id) as MessageID, + messageCreated: new Date(raw.created), thread: raw.thread_id, repliesCount: raw.replies_count ?? 0, lastReply: raw.last_reply ?? new Date() @@ -123,6 +124,7 @@ export function toFile(raw: FileDb): File { return { card: raw.card_id, message: String(raw.message_id) as MessageID, + messageCreated: new Date(raw.message_created), blobId: raw.blob_id, type: raw.type, filename: raw.filename, @@ -136,9 +138,9 @@ export function toMessagesGroup(raw: MessagesGroupDb): MessagesGroup { return { card: raw.card_id, blobId: raw.blob_id, - fromSec: raw.from_sec, - toSec: raw.to_sec, - count: raw.count, + fromDate: raw.from_date, + toDate: raw.to_date, + count: Number(raw.count), patches: raw.patches == null ? [] : raw.patches.filter((it: any) => it.message_id != null).map(toPatch) } } @@ -146,6 +148,7 @@ export function toMessagesGroup(raw: MessagesGroupDb): MessagesGroup { export function toPatch(raw: PatchDb): Patch { return { type: raw.type, + messageCreated: new Date(raw.message_created), message: String(raw.message_id) as MessageID, content: raw.content, creator: raw.creator, @@ -157,6 +160,7 @@ export function toThread(raw: ThreadDb): Thread { return { card: raw.card_id, message: String(raw.message_id) as MessageID, + messageCreated: new Date(raw.message_created), thread: raw.thread_id, repliesCount: raw.replies_count, lastReply: raw.last_reply @@ -223,12 +227,12 @@ function toNotificationRaw( let messageGroup: MessagesGroup | undefined - if (raw.message_group_blob_id != null && raw.message_group_from_sec != null && raw.message_group_to_sec != null) { + if (raw.message_group_blob_id != null && raw.message_group_from_date != null && raw.message_group_to_date != null) { messageGroup = { card, blobId: raw.message_group_blob_id, - fromSec: new Date(raw.message_group_from_sec), - toSec: new Date(raw.message_group_to_sec), + fromDate: new Date(raw.message_group_from_date), + toDate: new Date(raw.message_group_to_date), count: raw.message_group_count ?? 0 } } diff --git a/packages/cockroach/src/db/message.ts b/packages/cockroach/src/db/message.ts index ed89a04cfe..2046e2fb21 100644 --- a/packages/cockroach/src/db/message.ts +++ b/packages/cockroach/src/db/message.ts @@ -29,7 +29,6 @@ import { SortingOrder, type Thread } from '@hcengineering/communication-types' -import { generateMessageId, parseMessageId } from '@hcengineering/communication-shared' import { BaseDb } from './base' import { @@ -55,9 +54,7 @@ export class MessagesDb extends BaseDb { data?: MessageData, externalId?: string ): Promise { - const id = generateMessageId() - const db: MessageDb = { - id, + const db: Omit = { type, workspace_id: this.workspace, card_id: card, @@ -68,26 +65,17 @@ export class MessagesDb extends BaseDb { external_id: externalId } - const sql = `INSERT INTO ${TableName.Message} (workspace_id, card_id, id, content, creator, created, type, data, external_id) - VALUES ($1::uuid, $2::varchar, $3::bigint, $4::text, $5::varchar, $6::timestamptz, $7::varchar, $8::jsonb, $9::varchar)` + const sql = `INSERT INTO ${TableName.Message} (workspace_id, card_id, content, creator, created, type, data, external_id) + VALUES ($1::uuid, $2::varchar, $3::text, $4::varchar, $5::timestamptz, $6::varchar, $7::jsonb, $8::varchar) + RETURNING id::text` - await this.execute( + const result = await this.execute( sql, - [ - db.workspace_id, - db.card_id, - db.id, - db.content, - db.creator, - db.created, - db.type, - db.data ?? {}, - externalId ?? null - ], + [db.workspace_id, db.card_id, db.content, db.creator, db.created, db.type, db.data ?? {}, externalId ?? null], 'insert message' ) - return id + return result.map((it: any) => it.id)[0] } async removeMessages(card: CardID, messages: MessageID[], socialIds?: SocialID[]): Promise { @@ -116,7 +104,7 @@ export class MessagesDb extends BaseDb { values.push(messages) } - const sql = `DELETE FROM ${TableName.Message} WHERE ${where.join(' AND ')} RETURNING id` + const sql = `DELETE FROM ${TableName.Message} WHERE ${where.join(' AND ')} RETURNING id::text` const result = await this.execute(sql, values, 'remove messages') @@ -126,6 +114,7 @@ export class MessagesDb extends BaseDb { async createPatch( card: CardID, message: MessageID, + messageCreated: Date, type: PatchType, content: string, creator: SocialID, @@ -139,15 +128,15 @@ export class MessagesDb extends BaseDb { content, creator, created, - message_created_sec: parseMessageId(message) + message_created: messageCreated } - const sql = `INSERT INTO ${TableName.Patch} (workspace_id, card_id, message_id, type, content, creator, created, message_created_sec) + const sql = `INSERT INTO ${TableName.Patch} (workspace_id, card_id, message_id, type, content, creator, created, message_created) VALUES ($1::uuid, $2::varchar, $3::bigint, $4::varchar, $5::text, $6::varchar, $7::timestamptz, $8::timestamptz)` await this.execute( sql, - [db.workspace_id, db.card_id, db.message_id, db.type, db.content, db.creator, db.created, db.message_created_sec], + [db.workspace_id, db.card_id, db.message_id, db.type, db.content, db.creator, db.created, db.message_created], 'insert patch' ) } @@ -156,6 +145,7 @@ export class MessagesDb extends BaseDb { async createFile( card: CardID, message: MessageID, + messageCreated: Date, blobId: BlobID, fileType: string, filename: string, @@ -173,9 +163,9 @@ export class MessagesDb extends BaseDb { size, creator, created, - message_created_sec: parseMessageId(message) + message_created: messageCreated } - const sql = `INSERT INTO ${TableName.File} (workspace_id, card_id, message_id, blob_id, type, filename, creator, created, message_created_sec, size) + const sql = `INSERT INTO ${TableName.File} (workspace_id, card_id, message_id, blob_id, type, filename, creator, created, message_created, size) VALUES ($1::uuid, $2::varchar, $3::int8, $4::uuid, $5::varchar, $6::varchar, $7::varchar, $8::timestamptz, $9::timestamptz, $10::int8)` await this.execute( @@ -189,7 +179,7 @@ export class MessagesDb extends BaseDb { db.filename, db.creator, db.created, - db.message_created_sec, + db.message_created, db.size ], 'insert file' @@ -210,6 +200,7 @@ export class MessagesDb extends BaseDb { async createReaction( card: CardID, message: MessageID, + messageCreated: Date, reaction: string, creator: SocialID, created: Date @@ -238,13 +229,14 @@ export class MessagesDb extends BaseDb { 'insert reaction' ) } else { - await this.createPatch(card, message, PatchType.addReaction, reaction, creator, created) + await this.createPatch(card, message, messageCreated, PatchType.addReaction, reaction, creator, created) } } async removeReaction( card: CardID, message: MessageID, + messageCreated: Date, reaction: string, creator: SocialID, created: Date @@ -265,26 +257,33 @@ export class MessagesDb extends BaseDb { AND creator = $5::varchar` await this.execute(sql, [this.workspace, card, message, reaction, creator], 'remove reaction') } else { - await this.createPatch(card, message, PatchType.removeReaction, reaction, creator, created) + await this.createPatch(card, message, messageCreated, PatchType.removeReaction, reaction, creator, created) } } // Thread - async createThread(card: CardID, message: MessageID, thread: CardID, created: Date): Promise { + async createThread( + card: CardID, + message: MessageID, + messageCreated: Date, + thread: CardID, + created: Date + ): Promise { const db: ThreadDb = { workspace_id: this.workspace, card_id: card, message_id: message, + message_created: messageCreated, thread_id: thread, replies_count: 0, last_reply: created } const sql = `INSERT INTO ${TableName.Thread} (workspace_id, card_id, message_id, thread_id, replies_count, - last_reply) - VALUES ($1::uuid, $2::varchar, $3::bigint, $4::varchar, $5::int, $6::timestamptz)` + last_reply, message_created) + VALUES ($1::uuid, $2::varchar, $3::bigint, $4::varchar, $5::int, $6::timestamptz, $7::timestamptz)` await this.execute( sql, - [db.workspace_id, db.card_id, db.message_id, db.thread_id, db.replies_count, db.last_reply], + [db.workspace_id, db.card_id, db.message_id, db.thread_id, db.replies_count, db.last_reply, db.message_created], 'insert thread' ) } @@ -312,21 +311,21 @@ export class MessagesDb extends BaseDb { } // MessagesGroup - async createMessagesGroup(card: CardID, blobId: BlobID, fromSec: Date, toSec: Date, count: number): Promise { + async createMessagesGroup(card: CardID, blobId: BlobID, fromDate: Date, toDate: Date, count: number): Promise { const db: MessagesGroupDb = { workspace_id: this.workspace, card_id: card, blob_id: blobId, - from_sec: fromSec, - to_sec: toSec, + from_date: fromDate, + to_date: toDate, count } - const sql = `INSERT INTO ${TableName.MessagesGroup} (workspace_id, card_id, blob_id, from_sec, to_sec, count) + const sql = `INSERT INTO ${TableName.MessagesGroup} (workspace_id, card_id, blob_id, from_date, to_date, count) VALUES ($1::uuid, $2::varchar, $3::uuid, $4::timestamptz, $5::timestamptz, $6::int)` await this.execute( sql, - [db.workspace_id, db.card_id, db.blob_id, db.from_sec, db.to_sec, db.count], + [db.workspace_id, db.card_id, db.blob_id, db.from_date, db.to_date, db.count], 'insert messages group' ) } @@ -388,7 +387,8 @@ export class MessagesDb extends BaseDb { f.message_id, jsonb_agg(jsonb_build_object( 'card_id', f.card_id, - 'message_id', f.message_id, + 'message_id', f.message_id::text, + 'message_created', f.message_created, 'blob_id', f.blob_id, 'type', f.type, 'filename', f.filename, @@ -414,7 +414,7 @@ export class MessagesDb extends BaseDb { r.card_id, r.message_id, jsonb_agg(jsonb_build_object( - 'message_id', r.message_id, + 'message_id', r.message_id::text, 'reaction', r.reaction, 'creator', r.creator, 'created', r.created @@ -484,7 +484,7 @@ export class MessagesDb extends BaseDb { return ` SELECT - m.id, + m.id::text, m.card_id, m.type, m.content, @@ -546,7 +546,8 @@ export class MessagesDb extends BaseDb { // Find thread async findThread(thread: CardID): Promise { const sql = `SELECT t.card_id, - t.message_id, + t.message_id::text, + t.message_created, t.thread_id, t.replies_count, t.last_reply @@ -564,14 +565,15 @@ export class MessagesDb extends BaseDb { const select = ` SELECT mg.card_id, mg.blob_id, - mg.from_sec, - mg.to_sec, + mg.from_date, + mg.to_date, mg.count, patches FROM ${TableName.MessagesGroup} mg CROSS JOIN LATERAL ( SELECT jsonb_agg(jsonb_build_object( - 'message_id', p.message_id, + 'message_id', p.message_id::text, + 'message_created', p.message_created, 'type', p.type, 'content', p.content, 'creator', p.creator, @@ -580,14 +582,14 @@ export class MessagesDb extends BaseDb { FROM ${TableName.Patch} p WHERE p.workspace_id = mg.workspace_id AND p.card_id = mg.card_id - AND p.message_created_sec BETWEEN mg.from_sec AND mg.to_sec + AND p.message_created BETWEEN mg.from_date AND mg.to_date ) sub` const { where, values } = this.buildMessagesGroupWhere(params) const orderBy = - params.orderBy === 'toSec' - ? `ORDER BY mg.to_sec ${params.order === SortingOrder.Ascending ? 'ASC' : 'DESC'}` - : `ORDER BY mg.from_sec ${params.order === SortingOrder.Ascending ? 'ASC' : 'DESC'}` + params.orderBy === 'toDate' + ? `ORDER BY mg.to_date ${params.order === SortingOrder.Ascending ? 'ASC' : 'DESC'}` + : `ORDER BY mg.from_date ${params.order === SortingOrder.Ascending ? 'ASC' : 'DESC'}` const limit = params.limit != null ? ` LIMIT ${params.limit}` : '' const sql = [select, where, orderBy, limit].join(' ') @@ -613,14 +615,14 @@ export class MessagesDb extends BaseDb { values.push(params.blobId) } - const fromDateCondition = getCondition('mg', 'from_sec', index, params.fromSec, 'timestamptz') + const fromDateCondition = getCondition('mg', 'from_date', index, params.fromDate, 'timestamptz') if (fromDateCondition != null) { where.push(fromDateCondition.where) values.push(...fromDateCondition.values) index = fromDateCondition.index } - const toDateCondition = getCondition('mg', 'to_sec', index, params.toSec, 'timestamptz') + const toDateCondition = getCondition('mg', 'to_date', index, params.toDate, 'timestamptz') if (toDateCondition != null) { where.push(toDateCondition.where) values.push(...toDateCondition.values) diff --git a/packages/cockroach/src/db/notification.ts b/packages/cockroach/src/db/notification.ts index 3b6137c4f8..0999df2277 100644 --- a/packages/cockroach/src/db/notification.ts +++ b/packages/cockroach/src/db/notification.ts @@ -46,7 +46,7 @@ export class NotificationsDb extends BaseDb { const sqlValues = collaborators .map((account, index) => { - const i = index * 3 + const i = index * 5 values.push(this.workspace, card, account, date ?? new Date(), cardType) return `($${i + 1}::uuid, $${i + 2}::varchar, $${i + 3}::uuid, $${i + 4}::timestamptz, $${i + 5}::varchar)` }) @@ -104,7 +104,7 @@ export class NotificationsDb extends BaseDb { } const sql = `INSERT INTO ${TableName.Notification} (message_id, context_id, created) VALUES ($1::bigint, $2::int8, $3::timestamptz) - RETURNING id` + RETURNING id::text` const result = await this.execute(sql, [db.message_id, db.context_id, db.created], 'insert notification') return result[0].id as NotificationID } @@ -131,7 +131,7 @@ export class NotificationsDb extends BaseDb { } const sql = `INSERT INTO ${TableName.NotificationContext} (workspace_id, card_id, account, last_view, last_update) VALUES ($1::uuid, $2::varchar, $3::uuid, $4::timestamptz, $5::timestamptz) - RETURNING id` + RETURNING id::text` const result = await this.execute( sql, [db.workspace_id, db.card_id, db.account, db.last_view, db.last_update], @@ -142,8 +142,8 @@ export class NotificationsDb extends BaseDb { async removeContext(context: ContextID, account: AccountID): Promise { const sql = `DELETE - FROM ${TableName.Notification} - WHERE context = $1::int8 AND account = $2::uuid` + FROM ${TableName.NotificationContext} + WHERE id = $1::int8 AND account = $2::uuid` await this.execute(sql, [context, account], 'remove notification context') } @@ -183,9 +183,9 @@ export class NotificationsDb extends BaseDb { let joinMessages = '' let buildObject = ` JSONB_BUILD_OBJECT( - 'id', n.id, + 'id', n.id::text, 'created', n.created, - 'message_id', n.message_id + 'message_id', n.message_id::text )` if (withMessages) { @@ -197,13 +197,13 @@ export class NotificationsDb extends BaseDb { LEFT JOIN ${TableName.MessagesGroup} mg ON nc.workspace_id = mg.workspace_id AND nc.card_id = mg.card_id - AND n.created BETWEEN mg.from_sec AND mg.to_sec` + AND n.created BETWEEN mg.from_date AND mg.to_date` buildObject = ` JSONB_BUILD_OBJECT( - 'id', n.id, + 'id', n.id::text, 'created', n.created, - 'message_id', n.message_id, + 'message_id', n.message_id::text, 'message_type', m.type, 'message_content', m.content, 'message_data', m.data, @@ -211,8 +211,8 @@ export class NotificationsDb extends BaseDb { 'message_creator', m.creator, 'message_created', m.created, 'message_group_blob_id', mg.blob_id, - 'message_group_from_sec', mg.from_sec, - 'message_group_to_sec', mg.to_sec, + 'message_group_from_date', mg.from_date, + 'message_group_to_date', mg.to_date, 'message_group_count', mg.count, 'message_patches', ( SELECT COALESCE( @@ -270,7 +270,7 @@ export class NotificationsDb extends BaseDb { } const sql = ` - SELECT nc.id, + SELECT nc.id::text, nc.card_id, nc.account, nc.last_view, @@ -307,8 +307,8 @@ export class NotificationsDb extends BaseDb { m.data AS message_data, m.external_id AS message_external_id, mg.blob_id AS message_group_blob_id, - mg.from_sec AS message_group_from_sec, - mg.to_sec AS message_group_to_sec, + mg.from_date AS message_group_from_date, + mg.to_date AS message_group_to_date, mg.count AS message_group_count, (SELECT json_agg( jsonb_build_object( @@ -330,7 +330,7 @@ export class NotificationsDb extends BaseDb { LEFT JOIN ${TableName.MessagesGroup} mg ON nc.workspace_id = mg.workspace_id AND nc.card_id = mg.card_id - AND n.created BETWEEN mg.from_sec AND mg.to_sec + AND n.created BETWEEN mg.from_date AND mg.to_date ` } diff --git a/packages/cockroach/src/db/schema.ts b/packages/cockroach/src/db/schema.ts index 1721517fc6..69f2c6d07e 100644 --- a/packages/cockroach/src/db/schema.ts +++ b/packages/cockroach/src/db/schema.ts @@ -58,8 +58,8 @@ export interface MessagesGroupDb { workspace_id: WorkspaceID card_id: CardID blob_id: BlobID - from_sec: Date - to_sec: Date + from_date: Date + to_date: Date count: number patches?: PatchDb[] } @@ -72,7 +72,7 @@ export interface PatchDb { content: RichText creator: SocialID created: Date - message_created_sec: Date + message_created: Date } export interface ReactionDb { @@ -94,13 +94,14 @@ export interface FileDb { type: string creator: SocialID created: Date - message_created_sec: Date + message_created: Date } export interface ThreadDb { workspace_id: WorkspaceID card_id: CardID message_id: MessageID + message_created: Date thread_id: CardID replies_count: number last_reply: Date diff --git a/packages/cockroach/src/init.ts b/packages/cockroach/src/init.ts index 6d5b9e7aac..29a598f78b 100644 --- a/packages/cockroach/src/init.ts +++ b/packages/cockroach/src/init.ts @@ -57,10 +57,22 @@ export async function initSchema(sql: postgres.Sql) { } function getMigrations(): [string, string][] { - return [migrationO1(), migrationO2(), migrationO3(), migrationO4(), migrationO5()] + return [ + migrationV1_1(), + migrationV2_1(), + migrationV3_1(), + migrationV4_1(), + migrationV4_2(), + migrationV5_1(), + migrationV5_2(), + migrationV5_3(), + migrationV5_4(), + migrationV5_5(), + migrationV5_6() + ] } -function migrationO1(): [string, string] { +function migrationV1_1(): [string, string] { const sql = ` CREATE TABLE IF NOT EXISTS communication.messages ( @@ -204,7 +216,7 @@ function migrationO1(): [string, string] { return ['init_tables_01', sql] } -function migrationO2(): [string, string] { +function migrationV2_1(): [string, string] { const sql = ` CREATE TABLE IF NOT EXISTS communication.label ( @@ -220,15 +232,15 @@ function migrationO2(): [string, string] { return ['init_labels_02', sql] } -function migrationO3(): [string, string] { +function migrationV3_1(): [string, string] { const sql = ` ALTER TABLE communication.collaborators - ADD COLUMN IF NOT EXISTS card_type VARCHAR(255) NOT NULL DEFAULT 'card:class:Card'; + ADD COLUMN IF NOT EXISTS card_type VARCHAR(255) NOT NULL DEFAULT 'card:class:Card'; ` return ['add_card_type_to_collaborators_03', sql] } -function migrationO4(): [string, string] { +function migrationV4_1(): [string, string] { const sql = ` ALTER TABLE communication.messages ADD COLUMN IF NOT EXISTS external_id VARCHAR(255); @@ -236,7 +248,7 @@ function migrationO4(): [string, string] { return ['message_add_external_id_column', sql] } -function migrationO5(): [string, string] { +function migrationV4_2(): [string, string] { const sql = ` CREATE UNIQUE INDEX IF NOT EXISTS idx_messages_unique_external_id ON communication.messages (external_id) @@ -244,3 +256,86 @@ function migrationO5(): [string, string] { ` return ['message_add_external_id_column_unique_index', sql] } + +function migrationV5_1(): [string, string] { + const sql = ` + ALTER TABLE communication.reactions + DROP CONSTRAINT IF EXISTS reactions_workspace_id_card_id_message_id_fkey; + ` + return ['remove-reactions-fk_v5_1', sql] +} + +function migrationV5_2(): [string, string] { + const sql = ` + ALTER TABLE communication.messages + ALTER COLUMN id SET DEFAULT unique_rowid(); + + ALTER TABLE communication.messages + DROP CONSTRAINT IF EXISTS messages_pkey, + ADD CONSTRAINT messages_pkey PRIMARY KEY (id);` + return ['migrate-message-id_v5_2', sql] +} + +function migrationV5_3(): [string, string] { + const sql = ` + ALTER TABLE communication.messages_groups ADD COLUMN from_date TIMESTAMPTZ; + ALTER TABLE communication.messages_groups ADD COLUMN to_date TIMESTAMPTZ; + ALTER TABLE communication.patch ADD COLUMN message_created TIMESTAMPTZ; + ALTER TABLE communication.files ADD COLUMN message_created TIMESTAMPTZ; + ALTER TABLE communication.thread ADD COLUMN IF NOT EXISTS message_created TIMESTAMPTZ NOT NULL DEFAULT now(); + DROP INDEX IF EXISTS communication.thread_workspace_id_card_id_message_id_key CASCADE; + ALTER TABLE communication.thread ADD CONSTRAINT thread_unique_constraint UNIQUE (message_id); + ` + return ['add-date-columns_v5_3', sql] +} + +function migrationV5_4(): [string, string] { + const sql = ` + UPDATE communication.messages_groups + SET from_date = from_sec::TIMESTAMPTZ, + to_date = to_sec::TIMESTAMPTZ; + + ALTER TABLE communication.messages_groups ALTER COLUMN from_date SET NOT NULL; + ALTER TABLE communication.messages_groups ALTER COLUMN to_date SET NOT NULL; + + ALTER TABLE communication.messages_groups DROP COLUMN from_sec; + ALTER TABLE communication.messages_groups DROP COLUMN to_sec; + + UPDATE communication.patch + SET message_created = message_created_sec::TIMESTAMPTZ; + + ALTER TABLE communication.patch ALTER COLUMN message_created SET NOT NULL; + ALTER TABLE communication.patch DROP COLUMN message_created_sec; + + UPDATE communication.files + SET message_created = message_created_sec::TIMESTAMPTZ; + + ALTER TABLE communication.files ALTER COLUMN message_created SET NOT NULL; + ALTER TABLE communication.files DROP COLUMN message_created_sec; + ` + return ['migrate-date-values_v5_4', sql] +} + +function migrationV5_5(): [string, string] { + const sql = ` + ALTER TABLE communication.reactions + DROP CONSTRAINT IF EXISTS reactions_pkey; + ALTER TABLE communication.reactions + ADD CONSTRAINT reactions_pkey PRIMARY KEY (message_id, creator, reaction); + ` + return ['migrate-reactions-pk_v5_5', sql] +} + +function migrationV5_6(): [string, string] { + const sql = ` + ALTER TABLE communication.files + DROP CONSTRAINT IF EXISTS files_pkey; + ALTER TABLE communication.files + ADD CONSTRAINT files_pkey PRIMARY KEY (message_id, blob_id); + + ALTER TABLE communication.reactions + ADD CONSTRAINT reactions_message_fkey FOREIGN KEY (message_id) + REFERENCES communication.messages (id) ON DELETE CASCADE; + ` + return ['migrate-constraints_v5_6', sql] +} diff --git a/packages/query/package.json b/packages/query/package.json index d38f232a40..a8b30e2249 100644 --- a/packages/query/package.json +++ b/packages/query/package.json @@ -1,7 +1,7 @@ { "name": "@hcengineering/communication-query", "version": "0.1.0", - "main": "src/index.ts", + "main": "dist/index.js", "module": "dist/index.js", "types": "./types/index.d.ts", "files": [ @@ -14,7 +14,8 @@ "build:types": "tsc --project ./tsconfig.json --emitDeclarationOnly --declarationDir ./types", "build:browser": "bun build src/index.ts --outdir dist --target browser", "lint": "eslint src/*.ts", - "format": "prettier --write src/**/*.ts " + "format": "prettier --write src/**/*.ts ", + "clean": "rm -rf dist && rm -rf types && rm -rf .turbo" }, "devDependencies": { "@types/bun": "^1.1.14", @@ -25,7 +26,8 @@ "@hcengineering/communication-shared": "workspace:*", "@hcengineering/communication-types": "workspace:*", "@hcengineering/communication-yaml": "workspace:*", - "fast-equals": "^5.0.1" + "fast-equals": "^5.0.1", + "uuid": "^11.1.0" }, "peerDependencies": { "typescript": "^5.6.3" diff --git a/packages/query/src/index.ts b/packages/query/src/index.ts index d5362634f0..580b18d7b6 100644 --- a/packages/query/src/index.ts +++ b/packages/query/src/index.ts @@ -14,4 +14,3 @@ // export * from './lq' -export type { QueryClient } from './types' diff --git a/packages/query/src/label/query.ts b/packages/query/src/label/query.ts index 8bc384fa32..44294da16c 100644 --- a/packages/query/src/label/query.ts +++ b/packages/query/src/label/query.ts @@ -16,6 +16,7 @@ import type { FindLabelsParams, Label, WorkspaceID } from '@hcengineering/communication-types' import { type EventResult, + type FindClient, type LabelCreatedEvent, type LabelRemovedEvent, LabelResponseEventType, @@ -25,7 +26,7 @@ import { } from '@hcengineering/communication-sdk-types' import { QueryResult } from '../result' -import { type Query, type QueryClient, type QueryId } from '../types' +import { type Query, type QueryId } from '../types' function getId(label: Label): string { return `${label.label}:${label.card}:${label.account}` @@ -35,7 +36,7 @@ export class LabelsQuery implements Query { private result: Promise> | QueryResult