Skip to content

Commit

Permalink
feat!: add profile counters (#403)
Browse files Browse the repository at this point in the history
## Description

This PR adds a new `profile_counters` table that stores the counter for
various things related to a profile, such as relationships, blocks,
chain links and application links. This is done to allow the clients to
get such data without having to perform `COUNT` queries that are
notouriously costly from a performance perspective.

In order to have this code working properly, the following table needs
to be created:

```sql
CREATE TABLE profile_counters
(
    row_id                  SERIAL NOT NULL PRIMARY KEY,

    profile_address         TEXT   NOT NULL,
    relationships_count     BIGINT NOT NULL DEFAULT 0,
    blocks_count            BIGINT NOT NULL DEFAULT 0,
    chain_links_count       BIGINT NOT NULL DEFAULT 0,
    application_links_count BIGINT NOT NULL DEFAULT 0,
    CONSTRAINT unique_profile_counters UNIQUE (profile_address)
);
```

---

### Author Checklist

*All items are required. Please add a note to the item if the item is
not applicable and
please add links to any relevant follow up issues.*

I have...

- [x] included the correct [type
prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json)
in the PR title
- [x] added `!` to the type prefix if API or client breaking change
- [x] targeted the correct branch
- [ ] provided a link to the relevant issue or specification
- [x] added a changelog entry to `CHANGELOG.md`
- [x] included comments for [documenting Go
code](https://blog.golang.org/godoc)
- [x] updated the relevant documentation or specification
- [x] reviewed "Files changed" and left comments if necessary
- [x] confirmed all CI checks have passed

### Reviewers Checklist

*All items are required. Please add a note if the item is not applicable
and please add
your handle next to the items reviewed if you only reviewed selected
items.*

I have...

- [ ] confirmed the correct [type
prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json)
in the PR title
- [ ] confirmed `!` in the type prefix if API or client breaking change
- [ ] confirmed all author checklist items have been addressed
- [ ] reviewed API design and naming
- [ ] reviewed documentation is accurate
- [ ] reviewed tests and test coverage
- [ ] manually tested (if applicable)

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

- **Refactor**
- Improved transaction handling in database operations for saving and
deleting chain links, application links, relationships, and user blocks
to enhance data integrity and consistency.
- **New Features**
- Added a new SQL function to check if a user is following a specified
profile, improving user interaction capabilities.
- Introduced a `profile_counters` table to optimize performance by
precomputing counts related to profiles.
- **Tests**
- Expanded testing for profile, chain link, and relationship management
functionalities to ensure robustness and reliability of changes.
- **Chores**
- Removed redundant function for following profile check, streamlining
database schema.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
  • Loading branch information
RiccardoM authored Feb 2, 2024
1 parent 8932046 commit d7926cc
Show file tree
Hide file tree
Showing 10 changed files with 1,255 additions and 410 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
type: feat
module: none
pull_request: 403
description: Added support for profile counters
backward_compatible: false
date: 2024-02-02T13:12:01.044826647Z
10 changes: 5 additions & 5 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -73,15 +73,15 @@ coverage:
@echo "Viewing test coverage..."
@go tool cover --html=coverage.out

stop-docker-test:
@echo "Stopping Docker container..."
stop-test-db:
@echo "Stopping test database..."
@docker stop athena-test-db || true && docker rm athena-test-db || true

start-docker-test: stop-docker-test
@echo "Starting Docker container..."
start-test-db: stop-test-db
@echo "Starting test database..."
@docker run --name athena-test-db -e POSTGRES_USER=athena -e POSTGRES_PASSWORD=password -e POSTGRES_DB=athena -d -p 6432:5432 postgres

test-unit: start-docker-test
test-unit: start-test-db
@echo "Executing unit tests..."
@go test -mod=readonly -v -coverprofile coverage.txt ./...

Expand Down
61 changes: 54 additions & 7 deletions database/database_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,17 @@ package database_test

import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
"regexp"
"strings"
"testing"
"time"

sdk "github.com/cosmos/cosmos-sdk/types"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
"github.com/desmos-labs/desmos/v6/app"
profilestypes "github.com/desmos-labs/desmos/v6/x/profiles/types"
junodb "github.com/forbole/juno/v5/database"
junodbcfg "github.com/forbole/juno/v5/database/config"
"github.com/forbole/juno/v5/logging"
Expand All @@ -27,7 +31,11 @@ type DbTestSuite struct {
database *database.Db
}

func (suite *DbTestSuite) SetupTest() {
func TestDatabaseTestSuite(t *testing.T) {
suite.Run(t, new(DbTestSuite))
}

func (suite *DbTestSuite) SetupSuite() {
// Build the database
encodingConfig := app.MakeEncodingConfig()
databaseConfig := junodbcfg.DefaultDatabaseConfig().
Expand All @@ -43,18 +51,18 @@ func (suite *DbTestSuite) SetupTest() {
_, err = desmosDb.SQL.Exec(fmt.Sprintf(`DROP SCHEMA %s CASCADE;`, databaseConfig.GetSchema()))
suite.Require().NoError(err)

// Re-create the schema
// Create the schema
_, err = desmosDb.SQL.Exec(fmt.Sprintf(`CREATE SCHEMA %s;`, databaseConfig.GetSchema()))
suite.Require().NoError(err)

dirPath := "schema"
dir, err := ioutil.ReadDir(dirPath)
dir, err := os.ReadDir(dirPath)
for _, fileInfo := range dir {
if !strings.HasSuffix(fileInfo.Name(), ".sql") {
continue
}

file, err := ioutil.ReadFile(filepath.Join(dirPath, fileInfo.Name()))
file, err := os.ReadFile(filepath.Join(dirPath, fileInfo.Name()))
suite.Require().NoError(err)

commentsRegExp := regexp.MustCompile(`/\*.*\*/`)
Expand All @@ -65,9 +73,48 @@ func (suite *DbTestSuite) SetupTest() {
}
}

// Create the truncate function
stmt := fmt.Sprintf(`
CREATE OR REPLACE FUNCTION truncate_tables(username IN VARCHAR) RETURNS void AS $$
DECLARE
statements CURSOR FOR
SELECT tablename FROM pg_tables
WHERE tableowner = username AND schemaname = '%s';
BEGIN
FOR stmt IN statements LOOP
EXECUTE 'TRUNCATE TABLE ' || quote_ident(stmt.tablename) || ' CASCADE;';
END LOOP;
END;
$$ LANGUAGE plpgsql;`, databaseConfig.GetSchema())
_, err = desmosDb.SQL.Exec(stmt)
suite.Require().NoError(err)

suite.database = desmosDb
}

func TestDatabaseTestSuite(t *testing.T) {
suite.Run(t, new(DbTestSuite))
func (suite *DbTestSuite) SetupTest() {
_, err := suite.database.SQL.Exec(`SELECT truncate_tables('athena')`)
suite.Require().NoError(err)
}

// -------------------------------------------------------------------------------------------------------------------

func (suite *DbTestSuite) buildProfile(address string) *profilestypes.Profile {
addr, err := sdk.AccAddressFromBech32(address)
suite.Require().NoError(err)

profile, err := profilestypes.NewProfile(
"TestUser",
"Test User",
"This is a test user",
profilestypes.NewPictures(
"https://example.com/profile.png",
"https://example.com/cover.png",
),
time.Date(2023, 1, 1, 0, 0, 0, 0, time.UTC),
authtypes.NewBaseAccountWithAddress(addr),
)
suite.Require().NoError(err)

return profile
}
Loading

0 comments on commit d7926cc

Please sign in to comment.