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

Named columns and convenience SQL query interface #6543

Merged
merged 1 commit into from
Aug 7, 2020

Conversation

shlomi-noach
Copy link
Contributor

@shlomi-noach shlomi-noach commented Aug 6, 2020

This PR offers a more modern interface to SQL query results based on named columns, as well as convenience methods for casting result values into popular types. Some breakdown:

Convenience methods in Value

Previously, after selecting an integer column, the process to convert it to int64 was:

	tm, err := conn.Exec(ctx, "SELECT UNIX_TIMESTAMP()", 1, false)
	if err != nil { /* ... */ }
	if len(tm.Rows) != 1 || len(tm.Rows[0]) != 1 || tm.Rows[0][0].IsNull() { /* ... */ }
	i, err := evalengine.ToInt64(tm.Rows[0][0])
	if err != nil { /* ... */ }

New convenience methods support the following:

	tm, err := conn.Exec(ctx, "SELECT UNIX_TIMESTAMP()", 1, false)
	if err != nil { /* ... */ }
	if len(tm.Rows) != 1 || len(tm.Rows[0]) != 1 || tm.Rows[0][0].IsNull() { /* ... */ }
	i, err := tm.Rows[0][0].ToInt64()
	if err != nil { /* ... */ }

There is no longer a need to call an external evalengine function.

supported convenience methods are:

  • ToInt64()
  • ToUint64()
  • ToBool()
  • ToString() pre-existed.

A new type: NamedResult

Result type now has a Named() method that returns a NamedResult type. It has same fields, insert ID, rows affected as Result. It has same Rows data, but the data is an array of maps, where value is found by column name as opposed to ordinal position.

Again iterating on the above example:

	tm, err := conn.Exec(ctx, "SELECT UNIX_TIMESTAMP() as ts", 1, true)
	if err != nil { /* ... */ }
	named := tm.Named()
	if len(named.Rows) != 1 || len(named.Rows[0]) != 1 { /* ... */ }
	i, err := tm.Rows[0]["ts"].ToInt64()
	if err != nil { /* ... */ }

Note:

  • You must pass true in conn.Exec() to get field names
  • tm.Rows[0]["ts"] means "column ts in first row", and now the ordinal of the column is unimportant. In this particular example we return a single column, so maybe this example is underwhelming, but in a result set with 10 columns, names are a safer approach to access columns than ordinals.

Convenience methods in NamedResult:

We further make access more convenient like so:

	i, err := tm.Rows[0].ToInt64("ts")
	if err != nil { /* ... */ }

or

	i := tm.Rows[0].AsInt64("ts", 0)
  • .ToInt64("ts") is a syntactic sugar shortcut
  • .AsInt64("ts", 0) provides default value (0 in this case) and returns with no error. If column does not exist, or if there's a casting error, the function returns the default value silently.

We likewise have ToString, AsString, ToUint64, AsUint64, ToBool, AsBool functions.

Single Row()

Single row queries are common. Examples:

  • SELECT UNIX_TIMESTAMP()
  • SELECT @@global.read_only, @@global.gtid_mode
  • SELECT COUNT(*) FROM my_table WHERE status=1

The Row() function returns the first and single row in a result set, or nil if this isn't a single row result set.

Again iterating on our example:

	tm, err := conn.Exec(ctx, "SELECT UNIX_TIMESTAMP() as ts", 1, true)
	if err != nil { /* ... */ }
	row := tm.Named().Row()
	if row == nil { /* ... */ }
	i, err := row.ToInt64("ts")
	if err != nil { /* ... */ }

Optimistic example

When we SELECT UNIX_TIMESTAMP() it is safe to assume that the query either returns with an error, or returns with a single row that has a single integer column. Therefore, we can cleanup the above code to read:

	tm, err := conn.Exec(ctx, "SELECT UNIX_TIMESTAMP() as ts", 1, true)
	if err != nil { /* ... */ }
	i := tm.Named().Row().AsInt64("ts", 0)

Signed-off-by: Shlomi Noach <2607934+shlomi-noach@users.noreply.github.com>
Copy link
Contributor

@sougou sougou left a comment

Choose a reason for hiding this comment

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

💯

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.

3 participants