Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(store-sync,store-indexer): add postgres support #1338

Merged
merged 38 commits into from
Sep 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
723ecfd
wip postgres
holic Aug 21, 2023
513755a
sorta works
holic Aug 21, 2023
5d4b73c
schema -> schemaName
holic Aug 22, 2023
45e6a50
update snapshots
holic Aug 22, 2023
cf88351
try setting up postgres in CI
holic Aug 22, 2023
e6ec79c
await async expect
holic Aug 22, 2023
091c25d
refactor to infer schema from table object
holic Aug 22, 2023
312e573
wip
holic Aug 23, 2023
5ac8ae2
refactor with namespaces/schemas
holic Aug 23, 2023
8ef9300
refactor table ID handling
holic Aug 23, 2023
4cb7758
refactor schema name transform so it's just a test mock
holic Aug 23, 2023
f280a7a
attempt to clean up what we can
holic Aug 23, 2023
8213907
rename
holic Aug 23, 2023
7b93807
postgres indexer
holic Aug 23, 2023
83abbdf
createTable -> buildTable
holic Aug 23, 2023
73c8ba6
clarify naming of storage adapter vs query adapter
holic Aug 23, 2023
d5c43fb
add note about bytes types
holic Aug 23, 2023
8a4b7ed
add TODOs
holic Aug 23, 2023
076a3e5
rework tests so we always clean up
holic Aug 23, 2023
6c8e90e
fiddling with binary type
holic Aug 24, 2023
fc3585d
clean up DB
holic Aug 24, 2023
0106b0e
remove unused tableToSql
holic Aug 24, 2023
1b4af0d
small tweaks
holic Aug 24, 2023
ff3ac7c
improve numeric, bytes column types
holic Aug 24, 2023
168ee40
refactor a bit
holic Aug 24, 2023
dcdef22
update test snapshots
holic Aug 24, 2023
bae01be
fix e2e postgres setup
holic Aug 24, 2023
2f5761c
ignore e2e worlds.json
holic Aug 25, 2023
c6d2074
rework e2e so we can run both sqlite and postgres
holic Aug 25, 2023
ea712f9
add a test:local command for ease
holic Aug 25, 2023
2a1fa97
describe.each is nicer
holic Aug 25, 2023
070cf28
Revert "ignore e2e worlds.json"
holic Aug 25, 2023
82500d1
add more logging
holic Aug 25, 2023
a94c074
missing env var, clean up
holic Aug 25, 2023
a2ee2ea
Merge remote-tracking branch 'origin/main' into holic/postgres-storag…
holic Sep 1, 2023
51944d8
swap BlockLogsToStorageOptions with StorageAdapter
holic Sep 1, 2023
3d7c62b
add HOST config option
holic Sep 1, 2023
03e5e69
zod to dev deps
holic Sep 1, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 5 additions & 10 deletions .github/workflows/e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,11 @@ jobs:
runs-on: ubuntu-latest
services:
postgres:
image: ghcr.io/latticexyz/postgres-wal-logical:latest
env:
POSTGRES_USER: runner
POSTGRES_DB: mode_ephemeral
POSTGRES_HOST_AUTH_METHOD: trust
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
image: postgres:12.1-alpine
ports:
- 5432:5432
# needed because the postgres container does not provide a healthcheck
options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5
steps:
- name: Checkout
uses: actions/checkout@v3
Expand Down Expand Up @@ -56,5 +49,7 @@ jobs:
uses: ./.github/actions/require-empty-diff

- name: Run sync tests
env:
DATABASE_URL: "postgres://postgres@localhost:5432/postgres"
working-directory: ./e2e/packages/sync-test
run: pnpm test
9 changes: 9 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,13 @@ jobs:
test:
name: Run tests
runs-on: ubuntu-latest
services:
postgres:
image: postgres:12.1-alpine
ports:
- 5432:5432
# needed because the postgres container does not provide a healthcheck
options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5
steps:
- name: Checkout
uses: actions/checkout@v3
Expand All @@ -21,6 +28,8 @@ jobs:
uses: ./.github/actions/build

- name: Run tests
env:
DATABASE_URL: "postgres://postgres@localhost:5432/postgres"
run: pnpm test

- name: Generate gas reports
Expand Down
22 changes: 20 additions & 2 deletions e2e/packages/sync-test/indexerSync.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,17 @@ import {
import { range } from "@latticexyz/utils";
import path from "node:path";
import { rpcHttpUrl } from "./setup/constants";
import { z } from "zod";

const env = z
.object({
DATABASE_URL: z.string().default("postgres://127.0.0.1/postgres"),
})
.parse(process.env, {
errorMap: (issue) => ({
message: `Missing or invalid environment variable: ${issue.path.join(".")}`,
}),
});

describe("Sync from indexer", async () => {
const asyncErrorHandler = createAsyncErrorHandler();
Expand Down Expand Up @@ -54,14 +65,21 @@ describe("Sync from indexer", async () => {
expect(asyncErrorHandler.getErrors()[0]).toContain("error fetching initial state from indexer");
});

describe("indexer online", () => {
describe.each([["sqlite"], ["postgres"]] as const)("%s indexer", (indexerType) => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

very cool 👍

let indexerIteration = 1;
let indexer: ReturnType<typeof startIndexer>;

beforeEach(async () => {
// Start indexer
const port = 3000 + indexerIteration++;
indexer = startIndexer(port, path.join(__dirname, `anvil-${port}.db`), rpcHttpUrl, asyncErrorHandler.reportError);
indexer = startIndexer({
port,
rpcHttpUrl,
reportError: asyncErrorHandler.reportError,
...(indexerType === "postgres"
? { indexer: "postgres", databaseUrl: env.DATABASE_URL }
: { indexer: "sqlite", sqliteFilename: path.join(__dirname, `anvil-${port}.db`) }),
});
await indexer.doneSyncing;
});

Expand Down
3 changes: 2 additions & 1 deletion e2e/packages/sync-test/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"typescript": "5.1.6",
"viem": "1.6.0",
"vite": "^4.2.1",
"vitest": "^0.31.0"
"vitest": "^0.31.0",
"zod": "^3.22.2"
}
}
55 changes: 35 additions & 20 deletions e2e/packages/sync-test/setup/startIndexer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,30 +3,43 @@ import { execa } from "execa";
import { rmSync } from "node:fs";
import path from "node:path";

export function startIndexer(
port: number,
sqliteFilename: string,
rpcUrl: string,
reportError: (error: string) => void
) {
type IndexerOptions =
| {
indexer: "sqlite";
sqliteFilename: string;
}
| {
indexer: "postgres";
databaseUrl: string;
};

type StartIndexerOptions = {
port: number;
rpcHttpUrl: string;
reportError: (error: string) => void;
} & IndexerOptions;

export function startIndexer(opts: StartIndexerOptions) {
let resolve: () => void;
let reject: (reason?: string) => void;
const doneSyncing = new Promise<void>((res, rej) => {
resolve = res;
reject = rej;
});

console.log(chalk.magenta("[indexer]:"), "start syncing");
const env = {
DEBUG: "mud:*",
PORT: opts.port.toString(),
CHAIN_ID: "31337",
RPC_HTTP_URL: opts.rpcHttpUrl,
SQLITE_FILENAME: opts.indexer === "sqlite" ? opts.sqliteFilename : undefined,
DATABASE_URL: opts.indexer === "postgres" ? opts.databaseUrl : undefined,
};
console.log(chalk.magenta("[indexer]:"), "starting indexer", env);

const proc = execa("pnpm", ["start"], {
const proc = execa("pnpm", opts.indexer === "postgres" ? ["start:postgres"] : ["start:sqlite"], {
cwd: path.join(__dirname, "..", "..", "..", "..", "packages", "store-indexer"),
env: {
DEBUG: "mud:*",
PORT: port.toString(),
CHAIN_ID: "31337",
RPC_HTTP_URL: rpcUrl,
SQLITE_FILENAME: sqliteFilename,
},
env,
});

proc.on("error", (error) => {
Expand Down Expand Up @@ -56,10 +69,12 @@ export function startIndexer(

function cleanUp() {
// attempt to clean up sqlite file
try {
rmSync(sqliteFilename);
} catch (error) {
console.log("could not delete", sqliteFilename, error);
if (opts.indexer === "sqlite") {
try {
rmSync(opts.sqliteFilename);
} catch (error) {
console.log("could not delete", opts.sqliteFilename, error);
}
}
}

Expand All @@ -70,7 +85,7 @@ export function startIndexer(
});

return {
url: `http://127.0.0.1:${port}/trpc`,
url: `http://127.0.0.1:${opts.port}/trpc`,
doneSyncing,
process: proc,
kill: () =>
Expand Down
19 changes: 13 additions & 6 deletions e2e/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions packages/common/src/utils/identity.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export function identity<T>(value: T): T {
return value;
}
1 change: 1 addition & 0 deletions packages/common/src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export * from "./bigIntMin";
export * from "./bigIntSort";
export * from "./chunk";
export * from "./curry";
export * from "./identity";
export * from "./isDefined";
export * from "./isNotNull";
export * from "./wait";
Expand Down
Loading