Skip to content

Commit

Permalink
Merge pull request #1619 from lindseysimple/issue-1618
Browse files Browse the repository at this point in the history
fix: Use service key as table schema name in Postgres
  • Loading branch information
cloudxxx8 authored Oct 8, 2024
2 parents 5119c5b + 868da77 commit cb66fce
Show file tree
Hide file tree
Showing 6 changed files with 39 additions and 18 deletions.
2 changes: 1 addition & 1 deletion internal/app/storeforward.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ func (svc *Service) createStoreClient(database bootstrapConfig.Database, credent
case db.RedisDB:
return redis.NewClient(database, credentials)
case db.Postgres:
return postgres.NewClient(svc.ctx.appCtx, database, credentials, baseScriptPath, "", svc.lc)
return postgres.NewClient(svc.ctx.appCtx, database, credentials, baseScriptPath, "", svc.lc, svc.serviceKey)
default:
if factory, found := svc.customStoreClientFactories[strings.ToUpper(database.Type)]; found {
return factory(database, credentials)
Expand Down
9 changes: 6 additions & 3 deletions internal/store/db/postgres/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,12 @@ var dc *Client
type Client struct {
connPool *pgxpool.Pool
loggingClient logger.LoggingClient
appServiceKey string
}

// NewClient returns a pointer to the Postgres client
func NewClient(ctx context.Context, config bootstrapConfig.Database, credentials bootstrapConfig.Credentials, baseScriptPath, extScriptPath string, lc logger.LoggingClient) (*Client, errors.EdgeX) {
func NewClient(ctx context.Context, config bootstrapConfig.Database, credentials bootstrapConfig.Credentials,
baseScriptPath, extScriptPath string, lc logger.LoggingClient, serviceKey string) (*Client, errors.EdgeX) {
// Get the database name from the environment variable
databaseName := os.Getenv("EDGEX_DBNAME")
if databaseName == "" {
Expand All @@ -50,6 +52,7 @@ func NewClient(ctx context.Context, config bootstrapConfig.Database, credentials
dc = &Client{
connPool: dbPool,
loggingClient: lc,
appServiceKey: serviceKey,
}
})
if edgeXerr != nil {
Expand All @@ -64,15 +67,15 @@ func NewClient(ctx context.Context, config bootstrapConfig.Database, credentials
lc.Info("Successfully connect to Postgres database")

// execute base DB scripts
if edgeXerr = executeDBScripts(ctx, dc.connPool, baseScriptPath); edgeXerr != nil {
if edgeXerr = executeDBScripts(ctx, dc.connPool, baseScriptPath, serviceKey); edgeXerr != nil {
return nil, errors.NewCommonEdgeX(errors.Kind(edgeXerr), "failed to execute Postgres base DB scripts", edgeXerr)
}
if baseScriptPath != "" {
lc.Info("Successfully execute Postgres base DB scripts")
}

// execute extension DB scripts
if edgeXerr = executeDBScripts(ctx, dc.connPool, extScriptPath); edgeXerr != nil {
if edgeXerr = executeDBScripts(ctx, dc.connPool, extScriptPath, serviceKey); edgeXerr != nil {
return nil, errors.NewCommonEdgeX(errors.Kind(edgeXerr), "failed to execute Postgres extension DB scripts", edgeXerr)
}

Expand Down
2 changes: 1 addition & 1 deletion internal/store/db/postgres/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ func TestClient_NewClient(t *testing.T) {
lc := logger.NewMockClient()
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
_, err := NewClient(context.Background(), test.config, TestCredential, "", "", lc)
_, err := NewClient(context.Background(), test.config, TestCredential, "", "", lc, "svcKey")

if test.expectedError {
require.Error(t, err)
Expand Down
26 changes: 16 additions & 10 deletions internal/store/db/postgres/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,18 @@ import (
)

const (
// constants relate to the postgres db schema names
appSvcSchema = "app_svc"
// constants relate to the postgres db table names
storeTableName = appSvcSchema + ".store"
storeTableName = "store"

// constants relate to the storeObject fields
appServiceKeyField = "appServiceKey"
)

// getFullStoreTableName returns the table name with schema as prefix
func (c Client) getFullStoreTableName() string {
return fmt.Sprintf(`"%s".%s`, c.appServiceKey, storeTableName)
}

// Store persists a stored object to the store table and returns the assigned UUID
func (c Client) Store(o interfaces.StoredObject) (string, error) {
err := o.ValidateContract(false)
Expand All @@ -36,24 +40,26 @@ func (c Client) Store(o interfaces.StoredObject) (string, error) {

var exists bool
ctx := context.Background()
err = c.connPool.QueryRow(ctx, sqlCheckExistsById(storeTableName), o.ID).Scan(&exists)

fullTableName := c.getFullStoreTableName()
err = c.connPool.QueryRow(ctx, sqlCheckExistsById(fullTableName), o.ID).Scan(&exists)
if err != nil {
return "", wrapDBError("failed to query app svc store record job by id", err)
}

var model models.StoredObject
model.FromContract(o)

json, err := model.MarshalJSON()
jsonBytes, err := model.MarshalJSON()
if err != nil {
return "", err
}

_, err = c.connPool.Exec(
ctx,
sqlInsertContent(storeTableName),
sqlInsertContent(fullTableName),
model.ID,
json,
jsonBytes,
)
if err != nil {
return "", wrapDBError("failed to insert app svc store record", err)
Expand All @@ -78,7 +84,7 @@ func (c Client) RetrieveFromStore(appServiceKey string) ([]interfaces.StoredObje
}

// query from the store table with content contains {"appServiceKey": appServiceKey}
rows, err := c.connPool.Query(ctx, sqlQueryContentByJSONField(storeTableName), queryBytes)
rows, err := c.connPool.Query(ctx, sqlQueryContentByJSONField(c.getFullStoreTableName()), queryBytes)
if err != nil {
return nil, wrapDBError(fmt.Sprintf("failed to query app svc store record with key '%s'", appServiceKey), err)
}
Expand Down Expand Up @@ -117,7 +123,7 @@ func (c Client) Update(o interfaces.StoredObject) error {

_, err = c.connPool.Exec(
context.Background(),
sqlUpdateContentById(storeTableName),
sqlUpdateContentById(c.getFullStoreTableName()),
json,
o.ID,
)
Expand All @@ -137,7 +143,7 @@ func (c Client) RemoveFromStore(o interfaces.StoredObject) error {

_, err = c.connPool.Exec(
context.Background(),
sqlDeleteById(storeTableName),
sqlDeleteById(c.getFullStoreTableName()),
o.ID,
)
if err != nil {
Expand Down
7 changes: 6 additions & 1 deletion internal/store/db/postgres/store_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ var postgresClient *Client
// setupPostgresClient is called before the tests run
func setupPostgresClient() {
lc := logger.NewMockClient()
client, _ := NewClient(context.Background(), TestValidNoAuthConfig, TestCredential, "", "", lc)
client, _ := NewClient(context.Background(), TestValidNoAuthConfig, TestCredential, "", "", lc, "svcKey")
postgresClient = client
}

Expand Down Expand Up @@ -346,3 +346,8 @@ func TestClient_RemoveFromStore(t *testing.T) {
})
}
}

func TestClient_getFullStoreTableName(t *testing.T) {
result := postgresClient.getFullStoreTableName()
require.Equal(t, `"svcKey".store`, result)
}
11 changes: 9 additions & 2 deletions internal/store/db/postgres/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"path/filepath"
"regexp"
"sort"
"strings"

"github.com/edgexfoundry/go-mod-core-contracts/v3/errors"

Expand All @@ -22,6 +23,8 @@ import (
"github.com/jackc/pgx/v5/pgxpool"
)

const serviceKeyPlaceholder = "<serviceKey>"

var sqlFileNameRegexp = regexp.MustCompile(`([[:digit:]]+)-[[:word:]]+.sql`)

type sqlFileName struct {
Expand Down Expand Up @@ -52,7 +55,7 @@ func (sf sqlFileNames) getSortedNames() []string {
return result
}

func executeDBScripts(ctx context.Context, connPool *pgxpool.Pool, scriptsPath string) errors.EdgeX {
func executeDBScripts(ctx context.Context, connPool *pgxpool.Pool, scriptsPath string, serviceKey string) errors.EdgeX {
if len(scriptsPath) == 0 {
// skip script execution when the path is empty
return nil
Expand All @@ -79,7 +82,11 @@ func executeDBScripts(ctx context.Context, connPool *pgxpool.Pool, scriptsPath s
if err != nil {
return errors.NewCommonEdgeX(errors.KindServerError, fmt.Sprintf("failed to read sql file %s", sqlFile), err)
}
_, err = tx.Exec(ctx, string(sqlContent))

// replace the <serviceKey> placeholder text with the actual service key name
updatedSqlContent := strings.Replace(string(sqlContent), serviceKeyPlaceholder, serviceKey, -1)

_, err = tx.Exec(ctx, updatedSqlContent)
if err != nil {
return wrapDBError(fmt.Sprintf("failed to execute sql file %s", sqlFile), err)
}
Expand Down

0 comments on commit cb66fce

Please sign in to comment.