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

Encode Crystal enum args as integers #286

Merged
merged 1 commit into from
Jul 24, 2024
Merged

Conversation

jgaskins
Copy link
Contributor

Decoding enum values is already supported in DB, but encoding still requires explicitly specifying enum.value in query args. This PR uses the value property implicitly.

An argument could be made that it would be easier to understand the query if we use the string representations of the Crystal enums instead, but I'm proposing the numeric values for three reasons:

  1. An int4 values takes up less space than a text
  2. Storing the text representation makes @[Flags] enums painful to parse, but the integer representation makes them trivial
  3. The enum is an Int32

Example:

require "pg"

struct User
  include DB::Serializable

  getter id : UUID
  getter name : String
  getter role : Role
  getter created_at : Time

  @[Flags]
  enum Role
    Admin      = 0x01
    Moderator  = 0x02
    Subscriber = 0x04
    Member     = 0x08
    Guest      = 0x10
  end
end

pg = DB.open("postgres:///")

sql = "SELECT $1::uuid id, $2 name, $3::int4 role, now() created_at"
args = {
  UUID.v7,                        # $1 id
  "jgaskins",                     # $2 name
  User::Role[:admin, :moderator], # $3 role
}
pp pg.query_one sql, *args, as: User
# User(
#  @created_at=2024-07-21 12:10:33.400016000 -05:00 America/Chicago,
#  @id=UUID(0190d646-0cb7-7d60-82f0-18074e861a46),
#  @name="jgaskins",
#  @role=User::Role[Admin, Moderator])

Decoding enum values is already supported in DB, but encoding has still
required explicitly specifying `enum.value` in query args. This commit
uses the `value` property implicitly.
Comment on lines -13 to -15
# Read without casting the value
actual_value = PG_DB.query_one "select v from test_table", &.read
actual_value.should eq(value)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I removed this section because it assumes the value will be used in its raw form when retrieved. That assumption holds for data types that both Crystal and Postgres share but it breaks here.

@will will merged commit 2629629 into will:master Jul 24, 2024
1 check passed
@will
Copy link
Owner

will commented Jul 24, 2024

Thanks!

@jgaskins jgaskins deleted the encode-enums branch July 27, 2024 20:19
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