From 1928125e3c3ff17e86e838a9c84ddfadb2631a48 Mon Sep 17 00:00:00 2001 From: Simonas Karuzas Date: Mon, 9 Dec 2019 20:09:47 +0200 Subject: [PATCH] feat: Saving message and VC meta data --- packages/daf-data-store/src/data-store.ts | 136 ++++++++++++++---- .../src/migrations/001.initial.ts | 53 ++++--- .../src/migrations/002.second.ts | 30 ++-- 3 files changed, 145 insertions(+), 74 deletions(-) diff --git a/packages/daf-data-store/src/data-store.ts b/packages/daf-data-store/src/data-store.ts index 1deb454d2..7a8846b30 100644 --- a/packages/daf-data-store/src/data-store.ts +++ b/packages/daf-data-store/src/data-store.ts @@ -201,15 +201,18 @@ export class DataStore { async allIdentities() { const vcSubjects = await this.db.rows('select distinct sub as did from verifiable_credentials', null) const vcIssuers = await this.db.rows('select distinct iss as did from verifiable_credentials', null) - const messageSubjects = await this.db.rows( - 'select distinct sub as did from messages where sub is not null', + const messageReceivers = await this.db.rows( + 'select distinct receiver as did from messages where receiver is not null', + null, + ) + const messageSenders = await this.db.rows( + 'select distinct sender as did from messages where sender is not null', null, ) - const messageIssuers = await this.db.rows('select distinct iss as did from messages', null) const uniqueDids = [ ...new Set([ - ...messageSubjects.map((item: any) => item.did), - ...messageIssuers.map((item: any) => item.did), + ...messageReceivers.map((item: any) => item.did), + ...messageSenders.map((item: any) => item.did), ...vcIssuers.map((item: any) => item.did), ...vcSubjects.map((item: any) => item.did), ]), @@ -244,8 +247,8 @@ export class DataStore { } async latestMessageTimestamps() { - let query = - 'SELECT * from (select sub as did, nbf as timestamp, source_type as sourceType FROM messages ORDER BY nbf desc) GROUP BY did, sourceType' + let query = `SELECT * FROM ( SELECT m.id, m."timestamp", m.sender AS did, md. "type" AS sourceType, md.id AS sourceId FROM messages AS m + LEFT JOIN messages_meta_data AS md ON m.id = md.message_id) GROUP BY did, sourceType` return await this.db.rows(query, []) } @@ -264,42 +267,121 @@ export class DataStore { } async saveMessage(message: Message) { - const query = sql - .insert('messages', { - hash: message.id, - iss: message.from, - sub: message.to, - nbf: message.timestamp, - type: message.type, - tag: message.threadId, - jwt: message.raw, - data: message.data && JSON.stringify(message.data), - meta: message.meta && JSON.stringify(message.meta), - source_type: message.meta.type, - source_id: message.meta.id, - }) + const messageId = message.id + + // Check if the message is already saved + const searchQuery = sql + .select('id') + .from('messages') + .where({ id: messageId }) .toParams() + const searchResult = await this.db.rows(searchQuery.text, searchQuery.values) + if (searchResult.length > 0) { + this.updateMetaData(message) + } else { + const query = sql + .insert('messages', { + id: messageId, + sender: message.from, + receiver: message.to, + timestamp: message.timestamp, + type: message.type, + thread_id: message.threadId, + raw: message.raw, + data: message.data && JSON.stringify(message.data), + }) + .toParams() + + await this.db.run(query.text, query.values) + + await this.saveMetaData(message) + await this.saveVerifiableCredentials(message) + } - await this.db.run(query.text, query.values) + return { hash: message.id, iss: { did: message.from } } + } + + private async updateMetaData(message: Message) { + const { id, allMeta } = message + for (const metaData of allMeta) { + const query = sql + .select('type, id, data') + .from('messages_meta_data') + .where({ + message_id: id, + type: metaData.type, + id: metaData.id, + }) + .toParams() + const rows = await this.db.rows(query.text, query.values) + if (rows.length === 0) { + const insertQuery = sql + .insert('messages_meta_data', { + message_id: id, + type: metaData.type, + id: metaData.id, + data: metaData.data && JSON.stringify(metaData.data), + }) + .toParams() + await this.db.run(insertQuery.text, insertQuery.values) + } + } + } + + private async saveMetaData(message: Message) { + const messageId = message.id + + for (const metaData of message.allMeta) { + const query = sql + .insert('messages_meta_data', { + message_id: messageId, + type: metaData.type, + id: metaData.id, + data: metaData.data && JSON.stringify(metaData.data), + }) + .toParams() + await this.db.run(query.text, query.values) + } + } + + async saveVerifiableCredentials(message: Message) { + const messageId = message.id if (message.type == 'w3c.vp' || message.type == 'w3c.vc') { for (const vc of message.vc) { - await this.saveVerifiableCredential(vc, message.id) + await this.saveVerifiableCredential(vc, messageId) } } - - return { hash: message.id, iss: { did: message.from } } } - async saveVerifiableCredential(vc: any, messageHash: string) { + async saveVerifiableCredential(vc: any, messageId: string) { const verifiableCredential = vc.payload as any const vcHash = blake.blake2bHex(vc.jwt) + const metaData = sql + .insert('verifiable_credentials_meta_data', { + message_id: messageId, + hash: vcHash, + }) + .toParams() + + await this.db.run(metaData.text, metaData.values) + + // Check if + const searchQuery = sql + .select('hash') + .from('verifiable_credentials') + .where({ hash: vcHash }) + .toParams() + const searchResult = await this.db.rows(searchQuery.text, searchQuery.values) + if (searchResult.length > 0) { + return vcHash + } + const query = sql .insert('verifiable_credentials', { hash: vcHash, - parent_hash: messageHash, iss: verifiableCredential.iss, sub: verifiableCredential.sub, nbf: verifiableCredential.nbf, diff --git a/packages/daf-data-store/src/migrations/001.initial.ts b/packages/daf-data-store/src/migrations/001.initial.ts index 7ccd8a993..b87a96dde 100644 --- a/packages/daf-data-store/src/migrations/001.initial.ts +++ b/packages/daf-data-store/src/migrations/001.initial.ts @@ -4,28 +4,31 @@ export const initial: Migration = { run: async (db: DbDriver) => { await db.run( `CREATE TABLE IF NOT EXISTS messages ( - hash TEXT, - parent_hash TEXT, - iss TEXT, - sub TEXT, + id TEXT PRIMARY KEY, + thread_id TEXT, + sender TEXT, + receiver TEXT, type TEXT, - tag TEXT, data TEXT, - iat NUMERIC, - nbf NUMERIC, - jwt TEXT, - meta TEXT, - source_type TEXT, - source_id TEXT, - internal NUMERIC NOT NULL default 1 - );`, + raw TEXT, + timestamp NUMERIC + );`, + [], + ) + + await db.run( + `CREATE TABLE IF NOT EXISTS messages_meta_data ( + message_id TEXT, + data TEXT, + type TEXT, + id TEXT + );`, [], ) await db.run( `CREATE TABLE IF NOT EXISTS verifiable_credentials ( hash TEXT, - parent_hash TEXT, iss TEXT, aud TEXT, sub TEXT, @@ -37,6 +40,14 @@ export const initial: Migration = { [], ) + await db.run( + `CREATE TABLE IF NOT EXISTS verifiable_credentials_meta_data ( + message_id TEXT, + hash TEXT + );`, + [], + ) + await db.run( `CREATE TABLE IF NOT EXISTS verifiable_credentials_fields ( parent_hash INTEGER, @@ -49,19 +60,5 @@ export const initial: Migration = { );`, [], ) - - await db.run( - `CREATE TRIGGER IF NOT EXISTS delete_messages BEFORE DELETE ON "messages" BEGIN - DELETE FROM verifiable_credentials where parent_hash = old.hash; - END;`, - [], - ) - - await db.run( - `CREATE TRIGGER IF NOT EXISTS delete_verifiable_credentials BEFORE DELETE ON "verifiable_credentials" BEGIN - DELETE FROM verifiable_credentials_fields where parent_hash = old.hash; - END;`, - [], - ) }, } diff --git a/packages/daf-data-store/src/migrations/002.second.ts b/packages/daf-data-store/src/migrations/002.second.ts index 7e91b2fcb..b6fffac4e 100644 --- a/packages/daf-data-store/src/migrations/002.second.ts +++ b/packages/daf-data-store/src/migrations/002.second.ts @@ -2,37 +2,29 @@ import { DbDriver, Migration } from '../types' export const second: Migration = { run: async (db: DbDriver) => { + await db.run(`CREATE INDEX IF NOT EXISTS "messages_id" ON "messages" ("id");`, []) + await db.run(`CREATE INDEX IF NOT EXISTS "messages_thread_id" ON "messages" ("thread_id");`, []) + await db.run(`CREATE INDEX IF NOT EXISTS "messages_receiver" ON "messages" ("receiver");`, []) + await db.run(`CREATE INDEX IF NOT EXISTS "messages_sender" ON "messages" ("sender");`, []) await db.run( - `CREATE INDEX IF NOT EXISTS "messages_hash" ON "messages" ("hash");`, - [], - ) - await db.run( - `CREATE INDEX IF NOT EXISTS "messages_parent_hash" ON "messages" ("parent_hash");`, - [], - ) - await db.run( - `CREATE INDEX IF NOT EXISTS "messages_sub" ON "messages" ("sub");`, - [], - ) - await db.run( - `CREATE INDEX IF NOT EXISTS "messages_iss" ON "messages" ("iss");`, + `CREATE INDEX IF NOT EXISTS "messages_meta_data_message_id" ON "messages_meta_data" ("message_id");`, [], ) - await db.run( - `CREATE INDEX IF NOT EXISTS "messages_source_type" ON "messages" ("source_type");`, - [], - ) + await db.run(`CREATE INDEX IF NOT EXISTS "messages_meta_data_type" ON "messages_meta_data" ("type");`, []) + + await db.run(`CREATE INDEX IF NOT EXISTS "messages_meta_data_id" ON "messages_meta_data" ("id");`, []) await db.run( - `CREATE INDEX IF NOT EXISTS "messages_source_id" ON "messages" ("source_id");`, + `CREATE INDEX IF NOT EXISTS "verifiable_credentials_meta_data_message_id" ON "verifiable_credentials_meta_data" ("message_id");`, [], ) await db.run( - `CREATE INDEX IF NOT EXISTS "verifiable_credentials_parent_hash" ON "verifiable_credentials" ("parent_hash");`, + `CREATE INDEX IF NOT EXISTS "verifiable_credentials_meta_data_hash" ON "verifiable_credentials_meta_data" ("hash");`, [], ) + await db.run( `CREATE INDEX IF NOT EXISTS "verifiable_credentials_iss" ON "verifiable_credentials" ("iss");`, [],