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

Support MySql driver #2356

Merged
merged 31 commits into from
Nov 17, 2022
Merged

Support MySql driver #2356

merged 31 commits into from
Nov 17, 2022

Conversation

victorshevtsov
Copy link
Contributor

@victorshevtsov victorshevtsov commented Aug 20, 2022

In "SIA Setupad" we have a huge need for MySQL supported by PBS-Go like PBS-Java does.
I’m submitting a pull request with an implementation of MySQL driver support for PBS-Go.

The changes affected the configuration keys. So, all the keys *.postgres.* renamed to *.database.*.
For example:
stored_requests.postgres.connection.dbname
renamed to:
stored_requests.database.connection.dbname

Also there is a new configuration key stored_requests.database.connection.driver to set the database driver: mysql or postgres

Please provide any missing requirements if any of them missing.

@holms
Copy link

holms commented Aug 22, 2022

@VeronikaSolovei9 could you please take a look at this mysql implementation? We have a huge pain with administering pgsql, also in the future we would like to contribute support for nosql databases like mongodb or similar.

@dimention

@bsardo
Copy link
Collaborator

bsardo commented Aug 22, 2022

@victorshevtsov Thank you for the PR. The team is a bit busy at the moment but we will definitely give this a look.

@holms
Copy link

holms commented Sep 5, 2022

@bsardo how long usually does it take to review a PR in here? Can our company do something about this?

@bsardo
Copy link
Collaborator

bsardo commented Sep 7, 2022

Hi @holms, @victorshevtsov, sorry for the delay. We'll start reviewing this today and will be in touch shortly with feedback.

@bsardo bsardo self-requested a review September 7, 2022 14:00
@bsardo bsardo self-assigned this Sep 7, 2022
Copy link
Contributor

@VeronikaSolovei9 VeronikaSolovei9 left a comment

Choose a reason for hiding this comment

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

Thank you for putting this PR up, you did a great job! Changes you made totally make sense with current fetchers architecture.
I even installed and set up local MySQL server to test and review your PR :)
I left some comments where I had hick ups while testing it, those are minor.

To make these changes to production we will need to reconfigure something on our side. We need to discuss it with the team.


var queryArgs []interface{}
if e.cfg.DBDriver == "mysql" {
queryArgs = append(queryArgs, e.lastUpdate, e.lastUpdate)
Copy link
Contributor

Choose a reason for hiding this comment

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

queryArgs expects 1 parameter, not 2. If I modify it to queryArgs = append(queryArgs, e.lastUpdate) all works good. There is no reason to pass two e.lastUpdate?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The reason of passing the same parameter twice (in case of MySql) is in the difference of how it processes the parameters. Here are poll_for_updates queries for both cases:
mysql:

SELECT id, requestData, 'request' AS type FROM stored_requests WHERE last_updated > ?
UNION ALL
SELECT id, impData, 'imp' AS type FROM stored_imps WHERE last_updated > ?

postgres:

SELECT id, requestData, 'request' AS type FROM stored_requests WHERE last_updated > $1
UNION ALL
SELECT id, impData, 'imp' AS type FROM stored_imps WHERE last_updated > $1

Postgres references parameter by its number in the array of passed parameters, so one is enough.
MySql takes parameter from the passed array based on the number of question marks in the query. In other words, the number of parameters passed must equal to the number of question marks in the query.

Copy link
Contributor

@VeronikaSolovei9 VeronikaSolovei9 Sep 13, 2022

Choose a reason for hiding this comment

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

I see the problem now.
May I discuss this with a team to get ideas how this can be solved and I'll get back to you.

Copy link

@holms holms Sep 27, 2022

Choose a reason for hiding this comment

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

@VeronikaSolovei9 maybe any progress? we need mysql support a lot in here. is there's anyway we could speed up a process?

if wildcard == "$" {
if !strings.Contains(cfg.Query, "$1") || strings.Contains(cfg.Query, "$3") {
errs = append(errs, fmt.Errorf("%s: database.poll_for_updates.query must contain exactly one wildcard", section))
}
Copy link
Contributor

Choose a reason for hiding this comment

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

This validation, specifically line 449 leads to error with a valid sql query. I don't think this condition should exist. For example my poll_for_updates.query looks like

"SELECT uuid AS id, config as data, 'request' as dataType FROM videoconfig_config WHERE updated_at > ?"

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The original validation at line #454 (for postgres) makes sure that the query has exactly one parameter.
The validation at line #449 does the same but for mysql but in this case the query should have two parameters.
See my notes here

I see here a mistake. Line #454 should be:

if !strings.Contains(cfg.Query, "$1") || strings.Contains(cfg.Query, "$2") {

I will change it and commit.

Copy link
Contributor

Choose a reason for hiding this comment

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

Agree, thank you for this fix

Fixed the change mistakenly made by the previous commit.
@victorshevtsov
Copy link
Contributor Author

victorshevtsov commented Sep 13, 2022

Hi @VeronikaSolovei9.
Thank you for your review.

There is a chance that I'm using wrong queries in poll_for_updates.query.
If it should select the data from a single table without a union, then I will apply corresponding changes.
Please confirm that.

@VeronikaSolovei9
Copy link
Contributor

VeronikaSolovei9 commented Sep 13, 2022

We have different poll for update queries based on data we want to fetch. We have union for strored_requests.poll_for_updates.query for stored requests and stored imps.
We also have video_requests.poll_for_updates.query and stored responses.poll_for_updates.query where it's just a simple select from one table that I mentioned before.

I understand the problem. Need discuss it with the team.

Comment on lines +60 to +63
// Database configures Fetchers and EventProducers which read from a Database.
// Fetchers are in stored_requests/backends/db_fetcher/fetcher.go
// EventProducers are in stored_requests/events/database
Database DatabaseConfig `mapstructure:"database"`
Copy link
Collaborator

Choose a reason for hiding this comment

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

This change looks good, however I think we need to be backwards compatible. Hosts with stored requests housed in a database will have the postgres configuration so this would be a breaking change as currently written.

I'd like to see an approach here that we've used quite a bit where we map the old field to the new field if the old field is present and the new field isn't defined. If both the old and new field are defined, we ignore the old field but issue a warning.

Take a look at config/config.go#migrateConfigPurposeOneTreatment or config/config.go#migrateConfigSpecialFeature1 for reference.

This approach will allow us to give hosts some time to make the necessary adjustments to their config. We will eventually remove the backwards compatibility logic.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good idea. I will follow the proposed approach.

@bsardo
Copy link
Collaborator

bsardo commented Sep 28, 2022

Sorry for the delay and thank you for your interest in contributing. The team has been busy and needed to discuss this internally. We’ve had a chance to review and these are what we consider to be the objectives of this PR:

  1. Add MySQL support
  2. Use named parameters in queries for each DB driver
  3. Allow any number of query parameters for each DB driver
  4. Lay foundation for support of other databases
  5. Make the host configuration backwards compatible

I’d like to preface this by pointing out that we intend to refactor fetchers in the future so we aren’t asking you to refactor the package, but rather make some design choices that are steps in the right direction as part of this PR.

Regarding items 2 and 3, PBS currently only supports a single query parameter, the last updated at timestamp, and by nature of how query parameters are expressed in a postgres query, it supports an unlimited number of occurrences of that query parameter.
Any newly supported database should be equally as flexible. Furthermore, in the future we will support multiple query parameters (e.g. account ID in addition to last updated at) so we should keep this in mind here as well.
I understand that MySQL does not support named parameters out-of-the-box so in order to work around this, we would like to see a pseudo-syntax introduced which is the same as MySQL’s standard SQL syntax but with named parameters (e.g. $lastUpdatedAt) instead of using ?. On start-up, we can parse the query creating some data structure (map/array) that captures the mapping from each argument position to one of the named parameters so we know how to substitute query values at run-time into the proper SQL query to be executed.
For example:

// host config poll_for_updates using mysql driver
SELECT id, requestData, 'request' AS type FROM stored_requests WHERE last_updated > $lastUpdatedAt
UNION ALL
SELECT id, impData, 'imp' AS type FROM stored_imps WHERE last_updated > $lastUpdatedAt

// converted to proper query to execute
SELECT id, requestData, 'request' AS type FROM stored_requests WHERE last_updated > ?
UNION ALL
SELECT id, impData, 'imp' AS type FROM stored_imps WHERE last_updated > ?

// and map of query parameter to position captured for proper run-time substitution:
arr[0] = “lastUpdatedAt”
arr[1] = “lastUpdatedAt”
len(arr) = 2

Regarding item 4, conceptually it might make sense here to create an interface implemented by a MySQL object and a Postgres object with the objects encapsulating any query parsing and construction, and potentially any other logic (IdListMaker?) that is driver-specific in it. Then we would only need a single conditional on start-up that instantiates the appropriate object based on the host-configured driver:

// NOTE: I'm not saying this has to be the design :)
// Very rough thoughts on approach just to illustrate the point:
SomeDriverInterface interface {
	ConnString()
	ParseQuery() // called on start-up, generates query param mapping and proper query
	IDListMaker()
}

MySQLConcreteImpl {
    PseudoQuery string    // query defined in host config with $lastUpdatedAt
    Params []string       // positional to query param mapping populated on start-up
    ProperQuery string    // query with ? substituted for $lastUpdatedAt
}
func (m *MySQLConcreteImpl) ConnString()
func (m *MySQLConcreteImpl) ParseQuery()
func (m *MySQLConcreteImpl) IDListMaker()

var obj SomeDriverInterface
if driver == “mysql” {
    obj = MySQLConcreteImpl
} else {
    obj = PostgresConcreteImpl
}

The instantiated object could then be used downstream in all database operations with no concern for which type of database it is interacting with under the hood. This approach should allow for heavy reuse of the core fetcher logic and is extensible as we would theoretically only need to implement the interface when adding support for other databases in the future.

I'd like to hear your thoughts. Thanks again for your patience.

Comment on lines 448 to 456
if wildcard == "?" {
if strings.Count(cfg.Query, "?") != 2 {
errs = append(errs, fmt.Errorf("%s: database.poll_for_updates.query must contain exactly two wildcards", section))
}
}
if wildcard == "$" {
if !strings.Contains(cfg.Query, "$1") || strings.Contains(cfg.Query, "$2") {
errs = append(errs, fmt.Errorf("%s: database.poll_for_updates.query must contain exactly one wildcard", section))
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think this introduces a lack of flexibility in how hosts are able to structure their data. Ideally the number of parameters would not be constrained based on the driver, much less at all.

Comment on lines 211 to 217
if cfg.Driver == "mysql" {
return cfg.connStringMySql()
}

if cfg.Driver == "postgres" {
return cfg.connStringPosgres()
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think a better approach that would limit the number of conditional checks on drivers would be to create a database connection interface that is implemented by a mysql object and a postgres object. These objects would then have driver-specific methods on them that build the connection string and build the ID list maker.

@bsardo
Copy link
Collaborator

bsardo commented Oct 5, 2022

@victorshevtsov I noticed you pulled from master and you're getting a test failure now due to a broken test. You can merge with master again to pick up the test fix.

@victorshevtsov
Copy link
Contributor Author

@bsardo I merged the with master and it fixed the failing test. Thank you.
Also, I pushed the migration of the database connection configuration as you proposed earlier.
Please take a look at it.

Copy link
Collaborator

@bsardo bsardo left a comment

Choose a reason for hiding this comment

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

The migration code looks good. Just a couple of minor comments on that.

config/config.go Outdated
Comment on lines 1190 to 1193
if !v.IsSet(driverField) {
glog.Warning(fmt.Sprintf("%s is not set, using default (postgres) ", driverField))
v.Set(driverField, "postgres")
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

Perhaps it makes sense to only ever show this warning if we believe the host intends to use a database for stored requests to reduce noise and confusion on startup. We could lean on the old postgres dbname config field to make that determination:

		if !v.IsSet(driverField) && v.IsSet("postgres.connection.dbname") {
			glog.Warning(fmt.Sprintf("%s is not set, using default (postgres) ", driverField))
			v.Set(driverField, "postgres")
		}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed

`),
}

storedReqestsTests := []struct {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Nitpick: typo - storedRequestsTests

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed

migrateConfigDatabaseConnection(v)

if len(tt.config) > 0 {
assert.Equal(t, tt.want_connection_dbname, v.Get("stored_requests.database.connection.dbname").(string), tt.description)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Nitpick: instead of using type assertions you can call the viper methods v.GetString and v.GetInt instead of v.Get with the type assertion.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed

1. Use named parameters in queries for each DB driver
2. Allow any number of query parameters for each DB driver
3. Lay foundation for support of other databases
@victorshevtsov
Copy link
Contributor Author

I pushed several commits including:

  • refactoring of dbFetcher as you suggested
  • small fixes mentioned in the review to database configuration migration

@bsardo please take a look.

@bsardo
Copy link
Collaborator

bsardo commented Oct 20, 2022

@victorshevtsov sorry for the delay. This is still on my radar. I'll give this a closer look tomorrow and come back with feedback.

@victorshevtsov
Copy link
Contributor Author

@bsardo, @VeronikaSolovei9 I've pushed all the required changes accordingly to the review and wrote some comments with explanations where no changes needed. I really appreciate your ideas for improvements.

Please take a look. Thank you,

@VeronikaSolovei9
Copy link
Contributor

@victorshevtsov thank you for the updates, you did a great work!
I tested new changes with my local set up for both Postgres and MySql DBs and found a little thing that needs to be fixed.
In function migrateConfigDatabaseConnection where you declare all the migrations, every migration (stored_requests, stored_video_req and stored_responses) should have these QueryMigration:

queries: []QueryMigration{
				{
					name: "fetcher.query",
					params: []QueryParamMigration{
						{
							old: "%REQUEST_ID_LIST%",
							new: "$REQUEST_ID_LIST",
						},
						{
							old: "%IMP_ID_LIST%",
							new: "$IMP_ID_LIST",
						},
					},
				},
				{
					name: "poll_for_updates.query",
					params: []QueryParamMigration{
						{
							old: "$1",
							new: "$LAST_UPDATED",
						},
					},
				},
			},

I think it makes sense to extract it to variable or constant and not to duplicate for every migration.
With this change everything works as expected.

config/config.go Outdated
Comment on lines 1194 to 1206
{
name: "fetcher.query",
params: []QueryParamMigration{
{
old: "%REQUEST_ID_LIST%",
new: "$REQUEST_ID_LIST",
},
{
old: "%IMP_ID_LIST%",
new: "$IMP_ID_LIST",
},
},
},
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think we also need to migrate fetcher.amp_query which should have the same parameters as fetcher.query.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Updated.

config/config.go Outdated
Comment on lines 1207 to 1215
{
name: "poll_for_updates.query",
params: []QueryParamMigration{
{
old: "$1",
new: "$LAST_UPDATED",
},
},
},
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think we also need to migrate poll_for_updates.amp_query which should have the same parameter as poll_for_updates.query.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Updated.

@@ -1607,6 +1607,587 @@ func TestMigrateConfigTCF2EnforcePurposeFlags(t *testing.T) {
}
}

func TestMigrateConfigDatabaseConnection(t *testing.T) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

The query migration strategy looks good to me. Can you please add test coverage for it? Maybe it makes sense to create another test that just focuses on that instead of mixing it into this test?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Test coverage add by a separate test TestMigrateConfigDatabaseQueryParams

Updated migration of:
- `fetcher.query`
- `fetcher.amp_query`
- `poll_for_updates.query`
- `poll_for_updates.amp_query`
for `stored_requests`, `stored_video_req`, `stored_responses` sections

Added tests for SQL queries migration
@victorshevtsov
Copy link
Contributor Author

All done. Please take a look.
@bsardo, @VeronikaSolovei9

Copy link
Collaborator

@bsardo bsardo left a comment

Choose a reason for hiding this comment

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

@victorshevtsov, this is looking good. Just a couple of additional comments regarding documentation, testing and a bug I found. Then I think we're good to go!

Comment on lines 10 to 11
const sampleQueryTemplate = "SELECT id, requestData, 'request' as type FROM stored_requests WHERE id in $REQUEST_ID_LIST UNION ALL SELECT id, impData, 'imp' as type FROM stored_requests WHERE id in $IMP_ID_LIST"
const sampleResponsesQueryTemplate = "SELECT id, responseData, 'response' as type FROM stored_responses WHERE id in $ID_LIST"
Copy link
Collaborator

Choose a reason for hiding this comment

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

I don't think these are being used. Can we delete them?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, that can be deleted.
Done.

Comment on lines 195 to 206
```yaml
stored_requests:
postgres:
host: localhost
port: 5432
user: db-username
dbname: database-name
query: SELECT id, requestData, 'request' as type FROM stored_requests WHERE id in %REQUEST_ID_LIST% UNION ALL SELECT id, impData, 'imp' as type FROM stored_imps WHERE id in %IMP_ID_LIST%;
database:
connection:
driver: postgres
host: localhost
port: 5432
user: db-username
dbname: database-name
fetcher:
query: SELECT id, requestData, 'request' as type FROM stored_requests WHERE id in $REQUEST_ID_LIST UNION ALL SELECT id, impData, 'imp' as type FROM stored_imps WHERE id in $IMP_ID_LIST;
```
Copy link
Collaborator

@bsardo bsardo Nov 15, 2022

Choose a reason for hiding this comment

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

I think we should add a note here about supported databases and query syntax. Something like:

Supported Databases

  • postgres
  • mysql

Query Syntax
All database queries should be expressed using the native SQL syntax of your supported database of choice with one caveat.
For all supported database drivers, wherever you need to specify a query parameter, you must not use the native syntax (e.g. $1, %%, ?, etc.), but rather a PBS-specific syntax to represent the parameter which is of the format $VARIABLE_NAME. PBS currently supports just four query parameters, each of which pertains to particular config queries, and here is how they should be specified in your queries:

  • last updated at timestamp --> $LAST_UPDATED
  • stored request ID list --> $REQUEST_ID_LIST
  • stored imp ID list --> $IMP_ID_LIST
  • stored response ID list --> $ID_LIST

See the query defined at stored_requests.database.connection.fetcher.query in the yaml config above as an example of how to mix these variables in with native SQL syntax.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

Comment on lines 29 to 37
dataSourceName := provider.ConnString()
assertStringsEqual(t, dataSourceName, "someuser:somepassword@tcp(somehost.com:20)/TestDB")
}

func assertStringsEqual(t *testing.T, actual string, expected string) {
if actual != expected {
t.Errorf("Strings did not match.\n\"%s\" -- expected\n\"%s\" -- actual", expected, actual)
}
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

Nitpick: I suggest using the testify package and shorting this to:

connString := provider.ConnString()
expectedConnString := "someuser:somepassword@tcp(somehost.com:20)/TestDB"
assert.Equal(t, expectedConnString, connString, "Strings did not match")

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

Comment on lines 31 to 62
dataSourceName := provider.ConnString()
paramList := strings.Split(dataSourceName, " ")
params := make(map[string]string, len(paramList))
for _, param := range paramList {
keyVals := strings.Split(param, "=")
if len(keyVals) != 2 {
t.Fatalf(`param "%s" must only have one equals sign`, param)
}
if _, ok := params[keyVals[0]]; ok {
t.Fatalf("found duplicate param at key %s", keyVals[0])
}
params[keyVals[0]] = keyVals[1]
}

assertHasValue(t, params, "dbname", db)
assertHasValue(t, params, "host", host)
assertHasValue(t, params, "port", strconv.Itoa(port))
assertHasValue(t, params, "user", username)
assertHasValue(t, params, "password", password)
assertHasValue(t, params, "sslmode", "disable")
}

func assertHasValue(t *testing.T, m map[string]string, key string, val string) {
t.Helper()
realVal, ok := m[key]
if !ok {
t.Errorf("Map missing required key: %s", key)
}
if val != realVal {
t.Errorf("Unexpected value at key %s. Expected %s, Got %s", key, val, realVal)
}
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

I know all of this was copied from config/stored_requests_test.go but I think a lot of it is unnecessary. I suggest simplifying the body of this test so it mirrors what you have in the postgres connection string function test.

Also, I suggest converting this and the mysql connection string tests to table based and then have test cases where each part that makes up the string is the only part set with a final test case where they are all set.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The reason why I put these tests into separate files is to completely separate the logic because different implementations of DbProvider can have different unique parameters that produce connection strings in a variety of formats. Keeping a unified test for all of them sounds reasonable but can turn into a mesh in future. For example, MongoDB can have multiple hosts with ports in a connection string for a replica set and a sharded cluster.

@bsardo, please confirm if you think I should make it more unified anyway.

Copy link
Collaborator

Choose a reason for hiding this comment

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

@victorshevtsov oh maybe we have a misunderstanding; sorry about that. I wasn't questioning your test organization nor suggesting that we merge the connection string tests for postgres and mysql. I was just suggesting two things:

  1. I think a lot of db_provider/postgres_dbprovider_test.go#TestConnStringPostgres can be deleted so that the test structure is similar to that of db_provider/mysql_dbprovider_test.go#TestConnStringMySql. That means the logic in TestConnStringPostgres that iterates over the paramList checking for equal sign occurrences and duplicate keys can be deleted and the calls to assertHasValue can be replaced with simpler assertion logic similar to that in TestConnStringMySql.
  2. I think both db_provider/postgres_dbprovider_test.go#TestConnStringPostgres and db_provider/mysql_dbprovider_test.go#TestConnStringMySql should maybe be converted to a table-based format, each with cases that set just one of the database connection fields (db, host, port, username, password) in isolation, with a final test case that has them all set as each test currently does.

Does that make sense?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah, I see now. Sorry for misunderstanding.
Yes, that makes sense.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

Comment on lines +74 to 76
if err := provider.Close(); err != nil {
glog.Errorf("Error closing DB connection: %v", err)
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

Before this if we need to add the following check so that we don't get a panic due to a nil pointer dereference when shutting down a server configured to use some means other than a database for stored requests/responses:

if provider == nil {
	return
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

config/config.go Outdated
Comment on lines 1252 to 1262
queries: []QueryMigration{
{
name: "fetcher.query",
params: []QueryParamMigration{
{
old: "%ID_LIST%",
new: "$ID_LIST",
},
},
},
},
Copy link
Collaborator

@bsardo bsardo Nov 15, 2022

Choose a reason for hiding this comment

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

We still need to migrate %ID_LIST%, which is a list of stored response IDS, for stored responses. Even though this only applies to stored responses, we could still migrate it for all fetcher.query and fetcher.amp_query occurrences to keep this migration simple. If a host specifies it for some other resource type like stored requests, the query wouldn't work anyway, which is the current behavior.

@VeronikaSolovei9 thoughts?

Copy link
Collaborator

Choose a reason for hiding this comment

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

@VeronikaSolovei9 and I spoke offline and she agreed with this approach.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

Copy link
Collaborator

@bsardo bsardo left a comment

Choose a reason for hiding this comment

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

LGTM!

Copy link
Contributor

@VeronikaSolovei9 VeronikaSolovei9 left a comment

Choose a reason for hiding this comment

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

Changes and local testing with both Postgres and MySql DBs look good. Thank you for your contribution!

@victorshevtsov
Copy link
Contributor Author

So... Is it ready to be merged to master ?

@bsardo bsardo merged commit f40f0c3 into prebid:master Nov 17, 2022
@bsardo
Copy link
Collaborator

bsardo commented Nov 17, 2022

@victorshevtsov thanks so much for all of your work on this!

@jarrettabello
Copy link

Nice work guys!!! Cant wait to attempt to implement.

@videoheroes videoheroes mentioned this pull request Jan 24, 2023
thebraveio pushed a commit to thebraveio/prebid-server that referenced this pull request Jan 24, 2023
shunj-nb pushed a commit to ParticleMedia/prebid-server that referenced this pull request Jan 31, 2023
@SyntaxNode
Copy link
Contributor

@victorshevtsov I'd like to share your contribution at the next Prebid Server Webinar. May I ask what company you work for / contributed this change on behalf of?

@victorshevtsov
Copy link
Contributor Author

I contributed this PR on behalf of "Setupad" company.
They are your partners, signed a contract this month.
Please feel free to use this PR in your webinar

@SyntaxNode
Copy link
Contributor

Fantastic. Thank you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants