Skip to content

Commit e88c138

Browse files
authored
refactor(indexer/postgres)!: use schema/indexer API and hide types/methods (#21363)
1 parent fb7775a commit e88c138

File tree

17 files changed

+266
-144
lines changed

17 files changed

+266
-144
lines changed

indexer/postgres/base_sql.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package postgres
22

3-
// BaseSQL is the base SQL that is always included in the schema.
4-
const BaseSQL = `
3+
// baseSQL is the base SQL that is always included in the schema.
4+
const baseSQL = `
55
CREATE OR REPLACE FUNCTION nanos_to_timestamptz(nanos bigint) RETURNS timestamptz AS $$
66
SELECT to_timestamp(nanos / 1000000000) + (nanos / 1000000000) * INTERVAL '1 microsecond'
77
$$ LANGUAGE SQL IMMUTABLE;

indexer/postgres/column.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import (
88
)
99

1010
// createColumnDefinition writes a column definition within a CREATE TABLE statement for the field.
11-
func (tm *ObjectIndexer) createColumnDefinition(writer io.Writer, field schema.Field) error {
11+
func (tm *objectIndexer) createColumnDefinition(writer io.Writer, field schema.Field) error {
1212
_, err := fmt.Fprintf(writer, "%q ", field.Name)
1313
if err != nil {
1414
return err
@@ -110,7 +110,7 @@ func simpleColumnType(kind schema.Kind) string {
110110
// updatableColumnName is the name of the insertable/updatable column name for the field.
111111
// This is the field name in most cases, except for time columns which are stored as nanos
112112
// and then converted to timestamp generated columns.
113-
func (tm *ObjectIndexer) updatableColumnName(field schema.Field) (name string, err error) {
113+
func (tm *objectIndexer) updatableColumnName(field schema.Field) (name string, err error) {
114114
name = field.Name
115115
if field.Kind == schema.TimeKind {
116116
name = fmt.Sprintf("%s_nanos", name)

indexer/postgres/conn.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ import (
55
"database/sql"
66
)
77

8-
// DBConn is an interface that abstracts the *sql.DB, *sql.Tx and *sql.Conn types.
9-
type DBConn interface {
8+
// dbConn is an interface that abstracts the *sql.DB, *sql.Tx and *sql.Conn types.
9+
type dbConn interface {
1010
ExecContext(ctx context.Context, query string, args ...interface{}) (sql.Result, error)
1111
PrepareContext(ctx context.Context, query string) (*sql.Stmt, error)
1212
QueryContext(ctx context.Context, query string, args ...interface{}) (*sql.Rows, error)

indexer/postgres/create_table.go

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,25 +7,25 @@ import (
77
"strings"
88
)
99

10-
// CreateTable creates the table for the object type.
11-
func (tm *ObjectIndexer) CreateTable(ctx context.Context, conn DBConn) error {
10+
// createTable creates the table for the object type.
11+
func (tm *objectIndexer) createTable(ctx context.Context, conn dbConn) error {
1212
buf := new(strings.Builder)
13-
err := tm.CreateTableSql(buf)
13+
err := tm.createTableSql(buf)
1414
if err != nil {
1515
return err
1616
}
1717

1818
sqlStr := buf.String()
19-
if tm.options.Logger != nil {
20-
tm.options.Logger(fmt.Sprintf("Creating table %s", tm.TableName()), sqlStr)
19+
if tm.options.logger != nil {
20+
tm.options.logger.Debug("Creating table %s", "table", tm.tableName(), "sql", sqlStr)
2121
}
2222
_, err = conn.ExecContext(ctx, sqlStr)
2323
return err
2424
}
2525

26-
// CreateTableSql generates a CREATE TABLE statement for the object type.
27-
func (tm *ObjectIndexer) CreateTableSql(writer io.Writer) error {
28-
_, err := fmt.Fprintf(writer, "CREATE TABLE IF NOT EXISTS %q (\n\t", tm.TableName())
26+
// createTableSql generates a CREATE TABLE statement for the object type.
27+
func (tm *objectIndexer) createTableSql(writer io.Writer) error {
28+
_, err := fmt.Fprintf(writer, "CREATE TABLE IF NOT EXISTS %q (\n\t", tm.tableName())
2929
if err != nil {
3030
return err
3131
}
@@ -53,7 +53,7 @@ func (tm *ObjectIndexer) CreateTableSql(writer io.Writer) error {
5353
}
5454

5555
// add _deleted column when we have RetainDeletions set and enabled
56-
if !tm.options.DisableRetainDeletions && tm.typ.RetainDeletions {
56+
if !tm.options.disableRetainDeletions && tm.typ.RetainDeletions {
5757
_, err = fmt.Fprintf(writer, "_deleted BOOLEAN NOT NULL DEFAULT FALSE,\n\t")
5858
if err != nil {
5959
return err
@@ -87,7 +87,7 @@ func (tm *ObjectIndexer) CreateTableSql(writer io.Writer) error {
8787
// we GRANT SELECT on the table to PUBLIC so that the table is automatically available
8888
// for querying using off-the-shelf tools like pg_graphql, Postgrest, Postgraphile, etc.
8989
// without any login permissions
90-
_, err = fmt.Fprintf(writer, "GRANT SELECT ON TABLE %q TO PUBLIC;", tm.TableName())
90+
_, err = fmt.Fprintf(writer, "GRANT SELECT ON TABLE %q TO PUBLIC;", tm.tableName())
9191
if err != nil {
9292
return err
9393
}

indexer/postgres/create_table_test.go

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,10 @@ import (
55

66
"cosmossdk.io/indexer/postgres/internal/testdata"
77
"cosmossdk.io/schema"
8+
"cosmossdk.io/schema/logutil"
89
)
910

10-
func ExampleObjectIndexer_CreateTableSql_allKinds() {
11+
func Example_objectIndexer_createTableSql_allKinds() {
1112
exampleCreateTable(testdata.AllKindsObject)
1213
// Output:
1314
// CREATE TABLE IF NOT EXISTS "test_all_kinds" (
@@ -40,7 +41,7 @@ func ExampleObjectIndexer_CreateTableSql_allKinds() {
4041
// GRANT SELECT ON TABLE "test_all_kinds" TO PUBLIC;
4142
}
4243

43-
func ExampleObjectIndexer_CreateTableSql_singleton() {
44+
func Example_objectIndexer_createTableSql_singleton() {
4445
exampleCreateTable(testdata.SingletonObject)
4546
// Output:
4647
// CREATE TABLE IF NOT EXISTS "test_singleton" (
@@ -53,7 +54,7 @@ func ExampleObjectIndexer_CreateTableSql_singleton() {
5354
// GRANT SELECT ON TABLE "test_singleton" TO PUBLIC;
5455
}
5556

56-
func ExampleObjectIndexer_CreateTableSql_vote() {
57+
func Example_objectIndexer_createTableSql_vote() {
5758
exampleCreateTable(testdata.VoteObject)
5859
// Output:
5960
// CREATE TABLE IF NOT EXISTS "test_vote" (
@@ -66,7 +67,7 @@ func ExampleObjectIndexer_CreateTableSql_vote() {
6667
// GRANT SELECT ON TABLE "test_vote" TO PUBLIC;
6768
}
6869

69-
func ExampleObjectIndexer_CreateTableSql_vote_no_retain_delete() {
70+
func Example_objectIndexer_createTableSql_vote_no_retain_delete() {
7071
exampleCreateTableOpt(testdata.VoteObject, true)
7172
// Output:
7273
// CREATE TABLE IF NOT EXISTS "test_vote" (
@@ -83,11 +84,11 @@ func exampleCreateTable(objectType schema.ObjectType) {
8384
}
8485

8586
func exampleCreateTableOpt(objectType schema.ObjectType, noRetainDelete bool) {
86-
tm := NewObjectIndexer("test", objectType, Options{
87-
Logger: func(msg, sql string, params ...interface{}) {},
88-
DisableRetainDeletions: noRetainDelete,
87+
tm := newObjectIndexer("test", objectType, options{
88+
logger: logutil.NoopLogger{},
89+
disableRetainDeletions: noRetainDelete,
8990
})
90-
err := tm.CreateTableSql(os.Stdout)
91+
err := tm.createTableSql(os.Stdout)
9192
if err != nil {
9293
panic(err)
9394
}

indexer/postgres/enum.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ import (
1010
"cosmossdk.io/schema"
1111
)
1212

13-
// CreateEnumType creates an enum type in the database.
14-
func (m *ModuleIndexer) CreateEnumType(ctx context.Context, conn DBConn, enum schema.EnumType) error {
13+
// createEnumType creates an enum type in the database.
14+
func (m *moduleIndexer) createEnumType(ctx context.Context, conn dbConn, enum schema.EnumType) error {
1515
typeName := enumTypeName(m.moduleName, enum)
1616
row := conn.QueryRowContext(ctx, "SELECT 1 FROM pg_type WHERE typname = $1", typeName)
1717
var res interface{}
@@ -25,21 +25,21 @@ func (m *ModuleIndexer) CreateEnumType(ctx context.Context, conn DBConn, enum sc
2525
}
2626

2727
buf := new(strings.Builder)
28-
err := CreateEnumTypeSql(buf, m.moduleName, enum)
28+
err := createEnumTypeSql(buf, m.moduleName, enum)
2929
if err != nil {
3030
return err
3131
}
3232

3333
sqlStr := buf.String()
34-
if m.options.Logger != nil {
35-
m.options.Logger("Creating enum type", sqlStr)
34+
if m.options.logger != nil {
35+
m.options.logger.Debug("Creating enum type", "sql", sqlStr)
3636
}
3737
_, err = conn.ExecContext(ctx, sqlStr)
3838
return err
3939
}
4040

41-
// CreateEnumTypeSql generates a CREATE TYPE statement for the enum definition.
42-
func CreateEnumTypeSql(writer io.Writer, moduleName string, enum schema.EnumType) error {
41+
// createEnumTypeSql generates a CREATE TYPE statement for the enum definition.
42+
func createEnumTypeSql(writer io.Writer, moduleName string, enum schema.EnumType) error {
4343
_, err := fmt.Fprintf(writer, "CREATE TYPE %q AS ENUM (", enumTypeName(moduleName, enum))
4444
if err != nil {
4545
return err

indexer/postgres/enum_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ import (
66
"cosmossdk.io/indexer/postgres/internal/testdata"
77
)
88

9-
func ExampleCreateEnumTypeSql() {
10-
err := CreateEnumTypeSql(os.Stdout, "test", testdata.MyEnum)
9+
func Example_createEnumTypeSql() {
10+
err := createEnumTypeSql(os.Stdout, "test", testdata.MyEnum)
1111
if err != nil {
1212
panic(err)
1313
}

indexer/postgres/indexer.go

Lines changed: 58 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,11 @@ package postgres
33
import (
44
"context"
55
"database/sql"
6+
"encoding/json"
67
"errors"
7-
"fmt"
88

9-
"cosmossdk.io/schema/appdata"
9+
"cosmossdk.io/schema/indexer"
10+
"cosmossdk.io/schema/logutil"
1011
)
1112

1213
type Config struct {
@@ -22,9 +23,28 @@ type Config struct {
2223

2324
type SqlLogger = func(msg, sql string, params ...interface{})
2425

25-
func StartIndexer(ctx context.Context, logger SqlLogger, config Config) (appdata.Listener, error) {
26+
type indexerImpl struct {
27+
ctx context.Context
28+
db *sql.DB
29+
tx *sql.Tx
30+
opts options
31+
modules map[string]*moduleIndexer
32+
logger logutil.Logger
33+
}
34+
35+
func StartIndexer(params indexer.InitParams) (indexer.InitResult, error) {
36+
config, err := decodeConfig(params.Config.Config)
37+
if err != nil {
38+
return indexer.InitResult{}, err
39+
}
40+
41+
ctx := params.Context
42+
if ctx == nil {
43+
ctx = context.Background()
44+
}
45+
2646
if config.DatabaseURL == "" {
27-
return appdata.Listener{}, errors.New("missing database URL")
47+
return indexer.InitResult{}, errors.New("missing database URL")
2848
}
2949

3050
driver := config.DatabaseDriver
@@ -34,48 +54,51 @@ func StartIndexer(ctx context.Context, logger SqlLogger, config Config) (appdata
3454

3555
db, err := sql.Open(driver, config.DatabaseURL)
3656
if err != nil {
37-
return appdata.Listener{}, err
57+
return indexer.InitResult{}, err
3858
}
3959

4060
tx, err := db.BeginTx(ctx, nil)
4161
if err != nil {
42-
return appdata.Listener{}, err
62+
return indexer.InitResult{}, err
4363
}
4464

4565
// commit base schema
46-
_, err = tx.Exec(BaseSQL)
66+
_, err = tx.Exec(baseSQL)
4767
if err != nil {
48-
return appdata.Listener{}, err
68+
return indexer.InitResult{}, err
69+
}
70+
71+
moduleIndexers := map[string]*moduleIndexer{}
72+
opts := options{
73+
disableRetainDeletions: config.DisableRetainDeletions,
74+
logger: params.Logger,
4975
}
5076

51-
moduleIndexers := map[string]*ModuleIndexer{}
52-
opts := Options{
53-
DisableRetainDeletions: config.DisableRetainDeletions,
54-
Logger: logger,
77+
idx := &indexerImpl{
78+
ctx: ctx,
79+
db: db,
80+
tx: tx,
81+
opts: opts,
82+
modules: moduleIndexers,
83+
logger: params.Logger,
5584
}
5685

57-
return appdata.Listener{
58-
InitializeModuleData: func(data appdata.ModuleInitializationData) error {
59-
moduleName := data.ModuleName
60-
modSchema := data.Schema
61-
_, ok := moduleIndexers[moduleName]
62-
if ok {
63-
return fmt.Errorf("module %s already initialized", moduleName)
64-
}
65-
66-
mm := NewModuleIndexer(moduleName, modSchema, opts)
67-
moduleIndexers[moduleName] = mm
68-
69-
return mm.InitializeSchema(ctx, tx)
70-
},
71-
Commit: func(data appdata.CommitData) (completionCallback func() error, err error) {
72-
err = tx.Commit()
73-
if err != nil {
74-
return nil, err
75-
}
76-
77-
tx, err = db.BeginTx(ctx, nil)
78-
return nil, err
79-
},
86+
return indexer.InitResult{
87+
Listener: idx.listener(),
8088
}, nil
8189
}
90+
91+
func decodeConfig(rawConfig map[string]interface{}) (*Config, error) {
92+
bz, err := json.Marshal(rawConfig)
93+
if err != nil {
94+
return nil, err
95+
}
96+
97+
var config Config
98+
err = json.Unmarshal(bz, &config)
99+
if err != nil {
100+
return nil, err
101+
}
102+
103+
return &config, nil
104+
}

indexer/postgres/listener.go

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package postgres
2+
3+
import (
4+
"fmt"
5+
6+
"cosmossdk.io/schema/appdata"
7+
)
8+
9+
func (i *indexerImpl) listener() appdata.Listener {
10+
return appdata.Listener{
11+
InitializeModuleData: func(data appdata.ModuleInitializationData) error {
12+
moduleName := data.ModuleName
13+
modSchema := data.Schema
14+
_, ok := i.modules[moduleName]
15+
if ok {
16+
return fmt.Errorf("module %s already initialized", moduleName)
17+
}
18+
19+
mm := newModuleIndexer(moduleName, modSchema, i.opts)
20+
i.modules[moduleName] = mm
21+
22+
return mm.initializeSchema(i.ctx, i.tx)
23+
},
24+
StartBlock: func(data appdata.StartBlockData) error {
25+
_, err := i.tx.Exec("INSERT INTO block (number) VALUES ($1)", data.Height)
26+
return err
27+
},
28+
Commit: func(data appdata.CommitData) (func() error, error) {
29+
err := i.tx.Commit()
30+
if err != nil {
31+
return nil, err
32+
}
33+
34+
i.tx, err = i.db.BeginTx(i.ctx, nil)
35+
return nil, err
36+
},
37+
}
38+
}

0 commit comments

Comments
 (0)