diff --git a/README.md b/README.md index 32b2f96898d81a191313d2e260e211fb3202a10b..b652c9c66db9d63f117558178b3b9715dd45629f 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 0000000000000000000000000000000000000000..3d50a6fddafa4a9e6a4005b150a755504709996a --- /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 0000000000000000000000000000000000000000..a1dde30a11bd6beb9000bfec7076da63cadba3e1 --- /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 58519d4bd3ef37f1eaa4c124c6493cf56a17ddaa..67e57bf8d51f3eab83861877a7fa8f5f6be195db 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 0000000000000000000000000000000000000000..60a04c45104c1fcd789feed8d077da282143634c --- /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 0000000000000000000000000000000000000000..ed9825af5839a334c6be016d45f306677be59ee6 --- /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 9262ec25be5044a590da56748cb7e89a19777a5f..7e3b4fec844a23a7d2c873b9b98aa16c92818dd4 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 38eb21488cea9bb2153d7440bbc71699564859e6..425939491fecdbc259f36589019e9245b069b048 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 335e62462ae9b7fe5913c36dae554907bf8180c7..aaaad2694026af4bcf9e94a192f7814e0401f36e 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 628af2660ec9bdc9863aaefd1b4162ce93dfd6f5..46b42749058911bb6dfcd74f5c7fd68a564e9438 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 +}