Skip to content

Commit

Permalink
🗃️ fix: add migration to new data structure
Browse files Browse the repository at this point in the history
  • Loading branch information
arvinxx committed Jan 23, 2024
1 parent 42003fd commit 06ca7b5
Show file tree
Hide file tree
Showing 17 changed files with 553 additions and 40 deletions.
21 changes: 19 additions & 2 deletions src/database/core/db.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import Dexie from 'dexie';
import Dexie, { Transaction } from 'dexie';

import { DBModel } from '@/database/core/types/db';
import { DB_File } from '@/database/schemas/files';
Expand Down Expand Up @@ -33,7 +33,9 @@ export class LocalDB extends Dexie {
this.version(1).stores(dbSchemaV1);
this.version(2).stores(dbSchemaV2);
this.version(3).stores(dbSchemaV3);
this.version(4).stores(dbSchemaV4);
this.version(4)
.stores(dbSchemaV4)
.upgrade((trans) => this.upgradeToV4(trans));

this.files = this.table('files');
this.sessions = this.table('sessions');
Expand All @@ -42,6 +44,21 @@ export class LocalDB extends Dexie {
this.plugins = this.table('plugins');
this.sessionGroups = this.table('sessionGroups');
}

/**
* 2024.01.22
*
* DB V3 to V4
* from `group = pinned` to `pinned:true`
*/
upgradeToV4 = async (trans: Transaction) => {
const sessions = trans.table('sessions');
await sessions.toCollection().modify((session) => {
// translate boolean to number
session.pinned = session.group === 'pinned' ? 1 : 0;
session.group = 'default';
});
};
}

export const LocalDBInstance = new LocalDB();
Expand Down
2 changes: 1 addition & 1 deletion src/database/models/__tests__/session.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ describe('SessionModel', () => {
const group: SessionGroupId = 'testGroup';
await SessionModel.batchCreate([sessionData, sessionData] as LobeAgentSession[]);

const sessionsByGroup = await SessionModel.queryByGroup(group);
const sessionsByGroup = await SessionModel.querySessionsByGroupId(group);

// Assuming all created sessions belong to the same group
expect(sessionsByGroup).toHaveLength(2);
Expand Down
15 changes: 7 additions & 8 deletions src/database/models/message.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ class _MessageModel extends BaseModel {

/**
* Deletes multiple messages based on the assistantId and optionally the topicId.
* If topicId is not provided, it deletes messages where topicId is undefined.
* If topicId is not provided, it deletes messages where topicId is undefined or null.
* If topicId is provided, it deletes messages with that specific topicId.
*
* @param {string} sessionId - The identifier of the assistant associated with the messages.
Expand All @@ -142,13 +142,12 @@ class _MessageModel extends BaseModel {
async batchDelete(sessionId: string, topicId: string | undefined): Promise<void> {
// If topicId is specified, use both assistantId and topicId as the filter criteria in the query.
// Otherwise, filter by assistantId and require that topicId is undefined.
const query =
topicId !== undefined
? this.table.where({ sessionId, topicId }) // Use a compound index
: this.table
.where('sessionId')
.equals(sessionId)
.and((message) => message.topicId === undefined);
const query = !!topicId
? this.table.where({ sessionId, topicId }) // Use a compound index
: this.table
.where('sessionId')
.equals(sessionId)
.and((message) => !message.topicId);

// Retrieve a collection of message IDs that satisfy the criteria
const messageIds = await query.primaryKeys();
Expand Down
90 changes: 69 additions & 21 deletions src/database/models/session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@ class _SessionModel extends BaseModel {
}

async batchCreate(sessions: LobeAgentSession[]) {
return this._batchAdd(sessions, { idGenerator: uuid });
const DB_Sessions = sessions.map((s) => this.mapToDB_Session(s));

return this._batchAdd<DB_Session>(DB_Sessions, { idGenerator: uuid });
}

async query({
Expand All @@ -36,20 +38,52 @@ class _SessionModel extends BaseModel {
}: { current?: number; pageSize?: number } = {}): Promise<LobeSessions> {
const offset = current * pageSize;

return this.table.orderBy('updatedAt').reverse().offset(offset).limit(pageSize).toArray();
const items: DBModel<DB_Session>[] = await this.table
.orderBy('updatedAt')
.reverse()
.offset(offset)
.limit(pageSize)
.toArray();

return this.mapToAgentSessions(items);
}

async queryWithGroups(): Promise<ChatSessionList> {
const groups = await SessionGroupModel.query();
const customGroups = await this.queryByGroupIds(groups.map((item) => item.id));
const defaultItems = await this.querySessionsByGroupId(SessionDefaultGroup.Default);
const pinnedItems = await this.getPinnedSessions();

const all = await this.query();
return {
all,
customGroup: groups.map((group) => ({
...group,
children: customGroups[group.id],
})),
default: defaultItems,
pinned: pinnedItems,
};
}

/**
* get sessions by group
* @param group
*/
async queryByGroup(group: SessionGroupId): Promise<LobeSessions> {
return this.table.where('group').equals(group).toArray();
async querySessionsByGroupId(group: SessionGroupId): Promise<LobeSessions> {
const items: DBModel<DB_Session>[] = await this.table
.where('group')
.equals(group)
.and((session) => !session.pinned)
.reverse()
.sortBy('updatedAt');

return this.mapToAgentSessions(items);
}

async queryByGroupIds(groups: string[]) {
const pools = groups.map(async (id) => {
return [id, await this.queryByGroup(id)] as const;
return [id, await this.querySessionsByGroupId(id)] as const;
});
const groupItems = await Promise.all(pools);

Expand All @@ -60,6 +94,10 @@ class _SessionModel extends BaseModel {
return super._update(id, data);
}

async updatePinned(id: string, pinned: boolean) {
return this.update(id, { pinned: pinned ? 1 : 0 });
}

async updateConfig(id: string, data: DeepPartial<LobeAgentConfig>) {
const session = await this.findById(id);
if (!session) return;
Expand All @@ -68,6 +106,7 @@ class _SessionModel extends BaseModel {

return this.update(id, { config });
}

/**
* Delete a session , also delete all messages and topic associated with it.
*/
Expand Down Expand Up @@ -164,13 +203,13 @@ class _SessionModel extends BaseModel {
]);

// Retrieve unique sessions by IDs
const data = await this.table
const items: DBModel<DB_Session>[] = await this.table
.where('id')
.anyOf([...combinedSessionIds])
.toArray();

console.timeEnd('queryByKeyword');
return data;
return this.mapToAgentSessions(items);
}

async duplicate(id: string, newTitle?: string) {
Expand All @@ -182,25 +221,34 @@ class _SessionModel extends BaseModel {
return this._add(newSession, uuid());
}

async queryWithGroups(): Promise<ChatSessionList> {
const groups = await SessionGroupModel.query();
const customGroups = await this.queryByGroupIds(groups.map((item) => item.id));
async getPinnedSessions(): Promise<LobeSessions> {
const items: DBModel<DB_Session>[] = await this.table
.where('pinned')
.equals(1)
.reverse()
.sortBy('updatedAt');

const defaultItems = await this.queryByGroup(SessionDefaultGroup.Default);
const pinnedItems = await this.queryByGroup(SessionDefaultGroup.Pinned);
// const pinnedItems = await this.table.where('pinned').equals(1).toArray();
return this.mapToAgentSessions(items);
}

const all = await this.query();
private mapToDB_Session(session: LobeAgentSession): DBModel<DB_Session> {
return {
all,
customGroup: groups.map((group) => ({
...group,
children: customGroups[group.id],
})),
default: defaultItems,
pinned: pinnedItems,
...session,
group: session.group || SessionDefaultGroup.Default,
pinned: session.pinned ? 1 : 0,
};
}

private DB_SessionToAgentSession(session: DBModel<DB_Session>) {
return {
...session,
pinned: !!session.pinned,
} as LobeAgentSession;
}

private mapToAgentSessions(session: DBModel<DB_Session>[]) {
return session.map((item) => this.DB_SessionToAgentSession(item));
}
}

export const SessionModel = new _SessionModel();
1 change: 1 addition & 0 deletions src/database/schemas/session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ export const DB_SessionSchema = z.object({
config: AgentSchema,
group: z.string().default('default'),
meta: LobeMetaDataSchema,
pinned: z.number().int().min(0).max(1).optional(),
type: z.enum(['agent', 'group']).default('agent'),
});

Expand Down
72 changes: 72 additions & 0 deletions src/migrations/FromV2ToV3/fixtures/input-v2-session.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
{
"exportType": "sessions",
"state": {
"sessions": [
{
"config": {
"displayMode": "chat",
"historyCount": 1,
"model": "gpt-3.5-turbo",
"params": {
"frequency_penalty": 0,
"presence_penalty": 0,
"temperature": 0.6,
"top_p": 1,
"max_tokens": 2200
},
"plugins": [],
"systemRole": "你是一名 Postgresql 的数据库专家。用户是一名数据库小白,你需要使用简单直白的方式告诉用户如何使用 ostgresql 和它相应的 orm 工具 primsa",
"enableCompressThreshold": false,
"enableMaxTokens": false,
"inputTemplate": ""
},
"createdAt": 1698463356269,
"id": "06cc3e20-e870-4099-a619-c07a849d742d",
"meta": {
"avatar": "🐘",
"backgroundColor": "rgba(0,0,0,0)",
"title": "Postgresql 指南",
"description": "PostgreSQL 数据库和 Prisma ORM 工具的简单使用指南",
"tags": ["数据库", "PostgreSQL", "教程", "ORM", "Prisma"]
},
"type": "agent",
"updatedAt": 1698463356269,
"group": "pinned"
},
{
"config": {
"displayMode": "chat",
"historyCount": 1,
"model": "gpt-3.5-turbo",
"params": {
"frequency_penalty": 0,
"presence_penalty": 0,
"temperature": 0.6,
"top_p": 1,
"max_tokens": 2200
},
"plugins": [],
"systemRole": "你是一名 Postgresql 的数据库专家。用户是一名数据库小白,你需要使用简单直白的方式告诉用户如何使用 ostgresql 和它相应的 orm 工具 primsa",
"enableCompressThreshold": false,
"enableMaxTokens": false,
"inputTemplate": ""
},
"createdAt": 1698463356269,
"id": "06cc3e20-e870-4098-a619-c07a849d74dd",
"meta": {
"avatar": "🐘",
"backgroundColor": "rgba(0,0,0,0)",
"title": "Postgresql 指南",
"description": "PostgreSQL 数据库和 Prisma ORM 工具的简单使用指南",
"tags": ["数据库", "PostgreSQL", "教程", "ORM", "Prisma"]
},
"type": "agent",
"updatedAt": 1698463356269,
"group": "default"
}
],
"topics": [],
"messages": []
},
"version": 2
}
Loading

0 comments on commit 06ca7b5

Please sign in to comment.