From 27cb2efbea5157f44d4d96f30874d39b12bb36b8 Mon Sep 17 00:00:00 2001
From: Hugo Trentesaux <hugo@trentesaux.fr>
Date: Mon, 6 May 2024 17:18:09 +0200
Subject: [PATCH] wip tx comments

---
 README.md                                     |  3 +-
 doc/edit-database.md                          | 11 +++
 .../tables/public_transaction_comments.yaml   |  3 +
 .../databases/default/tables/tables.yaml      |  1 +
 .../default/1715007055748_squashed/down.sql   | 21 +++++
 .../default/1715007055748_squashed/up.sql     | 19 ++++
 src/cesium-plus.ts                            |  3 +-
 src/consts.ts                                 |  4 +
 src/indexer/database.ts                       | 92 ++++++++++++-------
 src/types.ts                                  |  7 ++
 10 files changed, 128 insertions(+), 36 deletions(-)
 create mode 100644 doc/edit-database.md
 create mode 100644 hasura/metadata/databases/default/tables/public_transaction_comments.yaml
 create mode 100644 hasura/migrations/default/1715007055748_squashed/down.sql
 create mode 100644 hasura/migrations/default/1715007055748_squashed/up.sql

diff --git a/README.md b/README.md
index 32b2f96..b652c9c 100644
--- a/README.md
+++ b/README.md
@@ -70,6 +70,7 @@ More detail in the doc below.
 - [start the indexer](./doc/start-indexer.md) (dev mode)
 - [using dev tool](./doc/using-dev-tool.md) (for debugging)
 - [importing cesium plus data](./doc/cesium-plus-import.md) (advanced)
+- [edit the database](./doc/edit-database.md) (dev)
 
 ## TODO
 
@@ -87,7 +88,7 @@ Features
     - [ ] make the app build in prod mode
     - [ ] allow connecting the app to a custom RPC endpoint
 - [ ] manage unpin requests when user/admin wants to delete data, see refcount
-- [ ] document dev database change with tracking hasura console and squashing migrations
+- [x] document dev database change with tracking hasura console and squashing migrations
 - [ ] add transaction comment
 - [ ] add version history to database (history of index request CIDs) -> not systematic
 - [ ] update description of pubkey field to ss58
diff --git a/doc/edit-database.md b/doc/edit-database.md
new file mode 100644
index 0000000..3d50a6f
--- /dev/null
+++ b/doc/edit-database.md
@@ -0,0 +1,11 @@
+# Edit database
+
+This is how to change something to the database structure:
+
+```sh
+# start hasura console that tracks database changes
+pnpm hasura console
+# do your stuff graphically...
+# squash the changes for a cleaner commit history
+pnpm hasura migrate squash --from 1712826828679
+```
diff --git a/hasura/metadata/databases/default/tables/public_transaction_comments.yaml b/hasura/metadata/databases/default/tables/public_transaction_comments.yaml
new file mode 100644
index 0000000..a1dde30
--- /dev/null
+++ b/hasura/metadata/databases/default/tables/public_transaction_comments.yaml
@@ -0,0 +1,3 @@
+table:
+  name: transaction_comments
+  schema: public
diff --git a/hasura/metadata/databases/default/tables/tables.yaml b/hasura/metadata/databases/default/tables/tables.yaml
index 58519d4..67e57bf 100644
--- a/hasura/metadata/databases/default/tables/tables.yaml
+++ b/hasura/metadata/databases/default/tables/tables.yaml
@@ -1,2 +1,3 @@
 - "!include public_meta.yaml"
 - "!include public_profiles.yaml"
+- "!include public_transaction_comments.yaml"
diff --git a/hasura/migrations/default/1715007055748_squashed/down.sql b/hasura/migrations/default/1715007055748_squashed/down.sql
new file mode 100644
index 0000000..60a04c4
--- /dev/null
+++ b/hasura/migrations/default/1715007055748_squashed/down.sql
@@ -0,0 +1,21 @@
+
+comment on column "public"."transaction_comments"."time" is NULL;
+ALTER TABLE "public"."transaction_comments" ALTER COLUMN "time" TYPE timestamp with time zone;
+
+ALTER TABLE "public"."profiles" ALTER COLUMN "time" TYPE timestamp with time zone;
+
+-- Could not auto-generate a down migration.
+-- Please write an appropriate down migration for the SQL below:
+-- alter table "public"."transaction_comments" add column "time" timestamptz
+--  not null;
+
+
+comment on column "public"."transaction_comments"."comment" is NULL;
+
+comment on column "public"."transaction_comments"."tx_id" is NULL;
+
+comment on column "public"."transaction_comments"."pubkey" is NULL;
+
+DROP TABLE "public"."transaction_comments";
+
+comment on column "public"."profiles"."pubkey" is E'base58 pubkey of profile owner';
diff --git a/hasura/migrations/default/1715007055748_squashed/up.sql b/hasura/migrations/default/1715007055748_squashed/up.sql
new file mode 100644
index 0000000..ed9825a
--- /dev/null
+++ b/hasura/migrations/default/1715007055748_squashed/up.sql
@@ -0,0 +1,19 @@
+
+
+comment on column "public"."profiles"."pubkey" is E'ss58 address of profile owner';
+
+CREATE TABLE "public"."transaction_comments" ("index_request_cid" text NOT NULL, "pubkey" text NOT NULL, "tx_id" text NOT NULL, "comment" text NOT NULL, PRIMARY KEY ("tx_id","pubkey") , UNIQUE ("index_request_cid"));COMMENT ON TABLE "public"."transaction_comments" IS E'Transaction comments';
+
+comment on column "public"."transaction_comments"."pubkey" is E'ss58 address of author';
+
+comment on column "public"."transaction_comments"."tx_id" is E'transaction id in the form "blockNumber-hashStart-eventNumber"';
+
+comment on column "public"."transaction_comments"."comment" is E'content of the transaction comment';
+
+alter table "public"."transaction_comments" add column "time" timestamptz
+ not null;
+
+ALTER TABLE "public"."profiles" ALTER COLUMN "time" TYPE timestamp;
+
+ALTER TABLE "public"."transaction_comments" ALTER COLUMN "time" TYPE timestamp;
+comment on column "public"."transaction_comments"."time" is E'timestamp of the index request';
diff --git a/src/cesium-plus.ts b/src/cesium-plus.ts
index 9262ec2..7e3b4fe 100644
--- a/src/cesium-plus.ts
+++ b/src/cesium-plus.ts
@@ -2,9 +2,8 @@ import { CID } from 'multiformats'
 import { kubo } from './kubo'
 import { Buffer } from 'buffer'
 import { timestampToKey, arrayToVinode, mergeInodesSyncCID } from './processor'
-import { type IndexRequest } from './types'
 import { CESIUM_PLUS_PROFILE_IMPORT } from './consts'
-import type{  CplusProfile, Avatar } from './types'
+import type { CplusProfile, Avatar, IndexRequest } from './types'
 
 // ========================= import functions
 
diff --git a/src/consts.ts b/src/consts.ts
index 38eb214..4259394 100644
--- a/src/consts.ts
+++ b/src/consts.ts
@@ -18,6 +18,10 @@ export const CESIUM_PLUS_PROFILE_IMPORT = CID.parse('bafkreiawtammeqc55cssr2zepf
 export const CESIUM_PLUS_PROFILE_INSERT = CID.parse('bafkreigi5phtqpo6a2f3tx4obaja4fzevy3nyvnl4bnkcxylyqnfeowzbm')
 export const CESIUM_PLUS_PROFILE_DELETE = CID.parse('bafkreic5bv5ytl7zv5rh5j2bd5mw6nfrn33mxhiobgmpsiu65yjw3eeduu')
 
+// document kind for transaction comment (old ones and new ones)
+export const TRANSACTION_COMMENT_V1 = 'TODO'
+export const TRANSACTION_COMMENT = CID.parse('bafkreiegjt5mrfj2hshuw6koejdfiykq57mzjeprfckxj5zpxxtqj4qzeu')
+
 // ==========
 
 // explorer resources
diff --git a/src/indexer/database.ts b/src/indexer/database.ts
index 335e624..aaaad26 100644
--- a/src/indexer/database.ts
+++ b/src/indexer/database.ts
@@ -1,9 +1,13 @@
-import { CESIUM_PLUS_PROFILE_IMPORT, CESIUM_PLUS_PROFILE_INSERT, CESIUM_PLUS_PROFILE_DELETE } from '../consts'
-import type { IndexRequest } from '../types'
+import {
+  CESIUM_PLUS_PROFILE_IMPORT,
+  CESIUM_PLUS_PROFILE_INSERT,
+  CESIUM_PLUS_PROFILE_DELETE,
+  TRANSACTION_COMMENT
+} from '../consts'
+import type { CplusProfile, IndexRequest, TxComment } from '../types'
 import { CID } from 'multiformats'
 import pg from 'pg'
 import { kubo } from '../kubo'
-import type { CplusProfile } from '../cesium-plus'
 
 // define form env
 const env = {
@@ -103,6 +107,29 @@ const cesiumPlusProfile: QueryBuilder = {
   ]
 }
 
+// transaction comment query and param builder
+// prevents overwrite
+const txComment: QueryBuilder = {
+  query: `INSERT INTO
+    transaction_comments(index_request_cid, time, pubkey, tx_id, comment)
+    VALUES ($1, $2, $3, $4, $5)
+    ON CONFLICT (pubkey, tx_id)
+    DO NOTHING;
+        `,
+  paramBuilder: (irCID: CID, ir: IndexRequest, _dataCID: CID, data: TxComment) => [
+    // $1 index_request_cid
+    irCID.toString(),
+    // $2 time
+    new Date(ir.time).toISOString(),
+    // $3 pubkey
+    ir.pubkey,
+    // $4 tx_id
+    data.tx_id,
+    // $5 comment
+    data.comment
+  ]
+}
+
 /// return data handler for a query builder
 const dataHandler: <T>(
   q: QueryBuilder,
@@ -114,50 +141,49 @@ const dataHandler: <T>(
   return client.query(q.query, q.paramBuilder(irCID, ir, dataCID, data))
 }
 
+// handle index request with non-null data
+async function handleIrWithNonNullData<T>(irCID: CID, ir: IndexRequest, q: QueryBuilder): Promise<void> {
+  const dataCID = ir.data
+  if (dataCID == null) {
+    console.log('no data when required')
+    return
+  }
+  kubo.dag
+    .get(dataCID)
+    .then((d) => d.value)
+    .then(dataHandler<T>(q, irCID, ir, dataCID))
+    .catch((e) => {
+      console.log(e)
+      console.log('☁️  could not get data to index ' + dataCID)
+    })
+}
+
 // insert index request in database
 export async function handleInsertRequest(irCID: CID, ir: IndexRequest) {
   console.log('💾 indexing ' + irCID)
 
   switch (ir.kind.toString()) {
-    // insert index request
-    case CESIUM_PLUS_PROFILE_INSERT.toString(): {
-      const dataCID = ir.data
-      if (dataCID == null) {
-        console.log('no data when required')
-        return
-      }
-      await kubo.dag
-        .get(dataCID)
-        .then((d) => d.value)
-        .then(dataHandler<CplusProfile>(cesiumPlusProfile, irCID, ir, dataCID))
-        .catch((e) => {
-          console.log(e)
-          console.log('☁️  could not get data to index ' + dataCID)
-        })
+    // insert cesium plus profile
+    case CESIUM_PLUS_PROFILE_INSERT.toString():
+      handleIrWithNonNullData<CplusProfile>(irCID, ir, cesiumPlusProfile)
       break
-    }
 
     // insert cesium plus import
-    case CESIUM_PLUS_PROFILE_IMPORT.toString(): {
-      const dataCID = ir.data
-      if (dataCID == null) {
-        console.log('no data when required')
-        return
-      }
+    case CESIUM_PLUS_PROFILE_IMPORT.toString():
       // transform base58 pubkey to ss58 address with gdev prefix
       ir.pubkey = base58ToSS58(ir.pubkey, GDEV_PREFIX)
-      await kubo.dag
-        .get(dataCID)
-        .then((d) => d.value)
-        .then(dataHandler<CplusProfile>(cesiumPlusProfile, irCID, ir, dataCID))
+      handleIrWithNonNullData<CplusProfile>(irCID, ir, cesiumPlusProfile)
       break
-    }
 
-    // delete
-    case CESIUM_PLUS_PROFILE_DELETE.toString(): {
+    // delete cesium plus profile
+    case CESIUM_PLUS_PROFILE_DELETE.toString():
       await client.query(`DELETE FROM profiles WHERE pubkey = $1;`, [ir.pubkey])
       break
-    }
+
+    // insert transaction comment
+    case TRANSACTION_COMMENT.toString():
+      handleIrWithNonNullData<TxComment>(irCID, ir, txComment)
+      break
 
     // unimplemented
     default:
diff --git a/src/types.ts b/src/types.ts
index 628af26..46b4274 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -122,3 +122,10 @@ interface Geoloc {
   lat: number
   lon: number
 }
+
+// ================== tx comment
+
+export interface TxComment {
+  tx_id: string
+  comment: string
+}
-- 
GitLab