Skip to content

Commit

Permalink
feat: add new dapps database connection (#118)
Browse files Browse the repository at this point in the history
  • Loading branch information
meelrossi committed Jun 24, 2024
1 parent 9769a50 commit 5511b2e
Show file tree
Hide file tree
Showing 15 changed files with 185 additions and 10 deletions.
3 changes: 2 additions & 1 deletion .env.default
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ WKC_METRICS_RESET_AT_NIGHT=false
WERT_PRIVATE_KEY='dummyKey'
WERT_PUBLICATION_FEES_PRIVATE_KEY='dummyKey2'
SEGMENT_WRITE_KEY='dummyKey3'
BUILDER_SERVER_DB_HOST='localhost'
BUILDER_SERVER_DB_USER='dummyUser'
BUILDER_SERVER_DB_PASSWORD='dummyPassword'

Expand All @@ -37,4 +38,4 @@ FAVORITES_PG_COMPONENT_PSQL_PORT=5432
FAVORITES_PG_COMPONENT_PSQL_DATABASE='favorites'
SNAPSHOT_URL=https://score.snapshot.org/
SNAPSHOT_NETWORK=1
SNAPSHOT_SPACE=snapshot.dcl.eth
SNAPSHOT_SPACE=snapshot.dcl.eth
6 changes: 4 additions & 2 deletions .env.spec
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
HTTP_SERVER_HOST=localhost

FAVORITES_PG_COMPONENT_PSQL_CONNECTION_STRING=postgres://testuser:testpassword@localhost:5432/marketplace
FAVORITES_PG_COMPONENT_PSQL_CONNECTION_STRING=postgres://marketplace_admin:marketplace_password@localhost:5432/marketplace
FAVORITES_PG_COMPONENT_PSQL_SCHEMA=favorites

DAPPS_PG_COMPONENT_PSQL_CONNECTION_STRING=postgres://dapps_admin:dapps_password@localhost:5433/dapps_test

SNAPSHOT_URL=https://score.snapshot.org/
SNAPSHOT_NETWORK=11155111
SNAPSHOT_SPACE=daotest.dcl.eth
SNAPSHOT_SPACE=daotest.dcl.eth
26 changes: 20 additions & 6 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,32 @@
version: '3.8'

services:
postgres:
marketplace_db:
image: postgres
restart: always
environment:
- POSTGRES_USER=admin
- POSTGRES_PASSWORD=password
- POSTGRES_USER=marketplace_admin
- POSTGRES_PASSWORD=marketplace_password
- POSTGRES_DB=marketplace
ports:
- 5432:5432
volumes:
- postgres_data:/var/lib/postgresql/data
- ./test/db/init-schema.sh:/docker-entrypoint-initdb.d/init-schema.sh
- marketplace_data:/var/lib/postgresql/data
- ./test/db/init-favorites-schema.sh:/docker-entrypoint-initdb.d/init-schema.sh
dapps_db:
image: postgres
restart: always
environment:
- POSTGRES_USER=dapps_admin
- POSTGRES_PASSWORD=dapps_password
- POSTGRES_DB=dapps_test
ports:
- 5433:5432
volumes:
- dapps_data:/var/lib/postgresql/data
- ./test/db/init-marketplace-schema.sh:/docker-entrypoint-initdb.d/init-schema.sh


volumes:
postgres_data:
marketplace_data:
dapps_data:
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"build": "tsc -p tsconfig.json",
"start": "node --trace-warnings --abort-on-uncaught-exception --unhandled-rejections=strict dist/index.js",
"migrate": "node-pg-migrate --database-url-var PG_COMPONENT_PSQL_CONNECTION_STRING --envPath .env -j ts --tsconfig tsconfig.json -m ./src/migrations",
"migrate:dapps": "node-pg-migrate --database-url-var DAPPS_PG_COMPONENT_PSQL_CONNECTION_STRING --envPath .env -j ts --tsconfig tsconfig.json -m ./src/migrations/dapps",
"lint": "eslint -c .eslintrc.json {src/**/*.ts,test/**/*.ts}",
"start:watch": "nodemon src/index.ts",
"check:code": "eslint -c .eslintrc.json {src,test}",
Expand Down
11 changes: 11 additions & 0 deletions src/components.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { createPicksComponent } from './ports/favorites/picks'
import { createSnapshotComponent } from './ports/favorites/snapshot'
import { createJobComponent } from './ports/job'
import { createSchemaValidatorComponent } from './ports/schema-validator'
import { createTradesComponent } from './ports/trades'
import { createWertSigner } from './ports/wert-signer/component'
import { AppComponents, GlobalContext } from './types'

Expand Down Expand Up @@ -53,6 +54,13 @@ export async function initComponents(): Promise<AppComponents> {
}
)

const dappsDatabase = await createPgComponent(
{ config, logs, metrics },
{
dbPrefix: 'DAPPS'
}
)

const SEGMENT_WRITE_KEY = await config.requireString('SEGMENT_WRITE_KEY')
const COVALENT_API_KEY = await config.getString('COVALENT_API_KEY')
const WERT_PRIVATE_KEY = await config.requireString('WERT_PRIVATE_KEY')
Expand All @@ -78,6 +86,7 @@ export async function initComponents(): Promise<AppComponents> {

// catalog
const catalog = await createCatalogComponent({ substreamsDatabase, picks }, SEGMENT_WRITE_KEY)
const trades = await createTradesComponent({ dappsDatabase })

await instrumentHttpServerWithMetrics({ metrics, server, config })

Expand All @@ -90,6 +99,7 @@ export async function initComponents(): Promise<AppComponents> {
metrics,
substreamsDatabase,
favoritesDatabase,
dappsDatabase,
catalog,
balances,
wertSigner,
Expand All @@ -99,6 +109,7 @@ export async function initComponents(): Promise<AppComponents> {
snapshot,
items,
lists,
trades,
access,
picks
}
Expand Down
23 changes: 23 additions & 0 deletions src/controllers/handlers/trades-handler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { DBTrade } from '../../ports/trades'
import { HTTPResponse, HandlerContextWithPath, StatusCode } from '../../types'

export async function getTradesHandler(
context: Pick<HandlerContextWithPath<'trades', '/v1/trades'>, 'components'>
): Promise<HTTPResponse<{ data: DBTrade[]; count: number }>> {
const {
components: { trades }
} = context

const { data, count } = await trades.getTrades()

return {
status: StatusCode.OK,
body: {
ok: true,
data: {
data,
count
}
}
}
}
3 changes: 3 additions & 0 deletions src/controllers/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { createCatalogHandler } from './handlers/catalog-handler'
import { createENSImageGeratorHandler } from './handlers/ens'
import { setupFavoritesRouter } from './handlers/favorites/routes'
import { pingHandler } from './handlers/ping-handler'
import { getTradesHandler } from './handlers/trades-handler'
import { createWertSignerHandler } from './handlers/wert-signer-handler'
import { validateAuthMetadataSigner } from './utils'

Expand Down Expand Up @@ -38,6 +39,8 @@ export async function setupRouter(globalContext: GlobalContext): Promise<Router<
router.get('/v1/ens/generate', createENSImageGeratorHandler)
router.get('/v1/:chainId/address/:wallet/balance', createBalanceHandler)

router.get('/v1/trades', getTradesHandler)

setupFavoritesRouter(router, { components })

return router
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/* eslint-disable @typescript-eslint/naming-convention */
import { MigrationBuilder, ColumnDefinitions } from 'node-pg-migrate'

export const SCHEMA = 'marketplace'

export const TRADES_TABLE = `${SCHEMA}.trades`
export const TRADE_ASSETS_TABLE = `${SCHEMA}.trade_assets`
export const TRADE_TYPE = `${SCHEMA}.trade_type`
export const ASSET_DIRECTION_TYPE = `${SCHEMA}.asset_direction_type`
export const shorthands: ColumnDefinitions | undefined = undefined

export async function up(pgm: MigrationBuilder): Promise<void> {
pgm.createType(TRADE_TYPE, ['bid', 'public_order'])

pgm.createTable(TRADES_TABLE, {
id: {
type: 'uuid',
notNull: true,
primaryKey: true,
unique: true,
default: pgm.func('public.uuid_generate_v4()')
},
network: { type: 'text', notNull: true },
chain_id: { type: 'integer', notNull: true },
signature: { type: 'text', notNull: true, unique: true },
checks: { type: 'jsonb', notNull: true },
signer: { type: 'varchar(42)', notNull: true },
type: { type: `"${TRADE_TYPE}"`, notNull: true },
expires_at: { type: 'timestamp', notNull: true },
effective_since: { type: 'timestamp', notNull: true },
created_at: { type: 'timestamp', notNull: true, default: pgm.func('now()') }
})

pgm.createType(ASSET_DIRECTION_TYPE, ['sent', 'received'])

pgm.createTable(TRADE_ASSETS_TABLE, {
id: {
type: 'uuid',
notNull: true,
primaryKey: true,
unique: true,
default: pgm.func('public.uuid_generate_v4()')
},
trade_id: {
type: 'uuid',
notNull: true,
references: `"${TRADES_TABLE}"(id)`,
onDelete: 'CASCADE'
},
direction: { type: `"${ASSET_DIRECTION_TYPE}"`, notNull: true },
asset_type: {
type: 'smallint' // (1: ERC20, 2: ERC721, 3: COLLECTION ITEM)
},
contract_address: { type: 'varchar(42)', notNull: true },
value: { type: 'numeric(78, 0)', notNull: true },
beneficiary: { type: 'varchar(42)', notNull: true },
extra: { type: 'text', notNull: true },
created_at: { type: 'timestamp', notNull: true, default: pgm.func('now()') }
})
}

export async function down(pgm: MigrationBuilder): Promise<void> {
pgm.dropTable(TRADES_TABLE)
pgm.dropTable(TRADE_ASSETS_TABLE)
pgm.dropType(ASSET_DIRECTION_TYPE)
}
16 changes: 16 additions & 0 deletions src/ports/trades/component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import SQL from 'sql-template-strings'
import { AppComponents } from '../../types'
import { DBTrade, ITradesComponent } from './types'

export function createTradesComponent(components: Pick<AppComponents, 'dappsDatabase'>): ITradesComponent {
const { dappsDatabase: pg } = components

async function getTrades() {
const result = await pg.query<DBTrade>(SQL`SELECT * FROM trades`)
return { data: result.rows, count: result.rowCount }
}

return {
getTrades
}
}
2 changes: 2 additions & 0 deletions src/ports/trades/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './types'
export * from './component'
10 changes: 10 additions & 0 deletions src/ports/trades/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export type ITradesComponent = {
getTrades(): Promise<{ data: DBTrade[]; count: number }>
}

export type DBTrade = {
signer: string
id: string
checks: Record<string, any>

Check warning on line 8 in src/ports/trades/types.ts

View workflow job for this annotation

GitHub Actions / install

Unexpected any. Specify a different type
signature: string
}
3 changes: 3 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { IPicksComponent } from './ports/favorites/picks'
import { ISnapshotComponent } from './ports/favorites/snapshot'
import { IJobComponent } from './ports/job'
import { ISchemaValidatorComponent } from './ports/schema-validator'
import { ITradesComponent } from './ports/trades'
import { IWertSignerComponent } from './ports/wert-signer/types'

export type GlobalContext = {
Expand All @@ -34,6 +35,7 @@ export type BaseComponents = {
metrics: IMetricsComponent<keyof typeof metricDeclarations>
substreamsDatabase: IPgComponent
favoritesDatabase: IPgComponent
dappsDatabase: IPgComponent
catalog: ICatalogComponent
balances: IBalanceComponent
wertSigner: IWertSignerComponent
Expand All @@ -45,6 +47,7 @@ export type BaseComponents = {
picks: IPicksComponent
access: IAccessComponent
items: IItemsComponent
trades: ITradesComponent
}

// components used in runtime
Expand Down
13 changes: 12 additions & 1 deletion test/components.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { IPicksComponent, createPicksComponent } from '../src/ports/favorites/pi
import { ISnapshotComponent, createSnapshotComponent } from '../src/ports/favorites/snapshot'
import { createJobComponent } from '../src/ports/job'
import { createSchemaValidatorComponent } from '../src/ports/schema-validator'
import { createTradesComponent } from '../src/ports/trades'
import { createWertSigner } from '../src/ports/wert-signer/component'
import { main } from '../src/service'
import { GlobalContext, TestComponents } from '../src/types'
Expand Down Expand Up @@ -63,6 +64,13 @@ async function initComponents(): Promise<TestComponents> {
}
)

const dappsDatabase = await createPgComponent(
{ config, logs, metrics },
{
dbPrefix: 'DAPPS'
}
)

const SEGMENT_WRITE_KEY = await config.requireString('SEGMENT_WRITE_KEY')
const COVALENT_API_KEY = await config.getString('COVALENT_API_KEY')
const WERT_PRIVATE_KEY = await config.requireString('WERT_PRIVATE_KEY')
Expand All @@ -84,6 +92,7 @@ async function initComponents(): Promise<TestComponents> {
const catalog = await createCatalogComponent({ substreamsDatabase, picks }, SEGMENT_WRITE_KEY)
const schemaValidator = await createSchemaValidatorComponent()
const balances = createBalanceComponent({ apiKey: COVALENT_API_KEY ?? '' })
const trades = createTradesComponent({ dappsDatabase })
// Mock the start function to avoid connecting to a local database
jest.spyOn(substreamsDatabase, 'start').mockResolvedValue(undefined)
jest.spyOn(catalog, 'updateBuilderServerItemsView').mockResolvedValue(undefined)
Expand All @@ -100,6 +109,7 @@ async function initComponents(): Promise<TestComponents> {
metrics,
substreamsDatabase,
favoritesDatabase,
dappsDatabase,
catalog,
balances,
wertSigner,
Expand All @@ -110,7 +120,8 @@ async function initComponents(): Promise<TestComponents> {
picks,
snapshot,
items,
schemaValidator
schemaValidator,
trades
}
}

Expand Down
File renamed without changes.
12 changes: 12 additions & 0 deletions test/db/init-marketplace-schema.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#!/bin/bash
set -e

psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<-EOSQL
CREATE SCHEMA marketplace;
-- CREATE THE ROLE AND ASSIGN IT TO THE PREVIOUSLY CREATED DB
CREATE ROLE testuser WITH LOGIN PASSWORD 'testpassword';
GRANT ALL PRIVILEGES ON SCHEMA marketplace TO testuser;
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
EOSQL

0 comments on commit 5511b2e

Please sign in to comment.