Skip to content

Conversation

@whatadewitt
Copy link
Owner

changes to add additional data to tweets with team and player totals

Copy link

@jrivany jrivany left a comment

Choose a reason for hiding this comment

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

PR title and description need some work, not up to snuff.

godotenv.Load()

db, err := sql.Open("mysql",
fmt.Sprintf("%v:%v@tcp(%v:%v)/%v", os.Getenv("DB_USER"), os.Getenv("DB_PASS"), os.Getenv("DB_HOST"), os.Getenv("DB_PORT"), os.Getenv("DB_TABLE")))

Choose a reason for hiding this comment

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

Suggested change
fmt.Sprintf("%v:%v@tcp(%v:%v)/%v", os.Getenv("DB_USER"), os.Getenv("DB_PASS"), os.Getenv("DB_HOST"), os.Getenv("DB_PORT"), os.Getenv("DB_TABLE")))
fmt.Sprintf("%v:%v@tcp(%v:%v)/%v", os.Getenv("DB_USER"), os.Getenv("DB_PASS"), os.Getenv("DB_HOST"), os.Getenv("DB_PORT"), os.Getenv("DB_DATABASE_NAME")))

Choose a reason for hiding this comment

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

Naming wise, your connecting to a specific database hosted on that MySQL server and then running queries that have all the table data.

Copy link

@itsjamie itsjamie left a comment

Choose a reason for hiding this comment

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

https://go.dev/doc/database/sql-injection

Right now the fmt.Sprintf can be changed to use the positional argument syntax for your database driver, so in this case, you would use ? for the SQL.

log.Fatal(err)
}

return seasonTotal
Copy link

@jrivany jrivany Apr 14, 2023

Choose a reason for hiding this comment

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

So I think in a more idiomatic go world, you would return the err and the total (potentially nil) here and log fatal in the calling code.

Then all the exit points are clear from main

@itsjamie
Copy link

If you start to find building your tweets from fmt.Sprintf to get unwieldy you could look at using text/template.

https://gobyexample.com/text-templates


// grab the team total for the given code
var teamTotalType int
err = db.QueryRow(fmt.Sprintf("SELECT COUNT(*) FROM player_stats WHERE team_name = '%s' AND code = '%s'", team, code)).Scan(&teamTotalType)
Copy link

Choose a reason for hiding this comment

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

you can use prepared statements for these too ;)


func saveViolation(db *sql.DB, code string, p Player, team string, date string) (int, int, int, int) {
table := os.Getenv("DB_TABLE")
stmt, err := db.Prepare(fmt.Sprintf("INSERT INTO %s(player_id, player_name, team_name, code, date) VALUES(?, ?, ?, ?, ?)", table))
Copy link

@itsjamie itsjamie May 15, 2023

Choose a reason for hiding this comment

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

It doesn't really matter to the impact or quality of the code, but because you are using placeholders here, Go would automatically prepare the statement. It also doesn't change the performance at all. You could validate this by using Wireshark or something and watching the traffic to the database, it wouldn't change between the prepare + exec, versus an Exec with the statement with placeholders. The same network traffic will end up being sent.

See: https://dev.mysql.com/doc/refman/8.0/en/sql-prepared-statements.html

In particular...

A prepared statement is specific to the session in which it was created. If you terminate a session without deallocating a previously prepared statement, the server deallocates it automatically.

A prepared statement is also global to the session. If you create a prepared statement within a stored routine, it is not deallocated when the stored routine ends.

So that's what the server will do as Go when you are using the db API uses a connection pool, and will establish multiple connections.

Now, if you were to retrieve a connection, and run the same queries, you could use the Prepare API, and reuse the driver.Stmt that is returned to make sure you doesn't get automatic deallocations depending on if the driver you're using deallocates the automatic prepared statements immediately after use because perhaps they don't name the statements, and they are an unnamed prepared statement, which only stays prepared until the next statement. The Postgres driver lib/pq iirc does this.

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.

4 participants