Comments (10)
@crimson-knight Here's my workaround:
enum Gender
UNSPECIFIED
FEMALE
MALE
def to_s
super.downcase
end
end
class User < Jennifer::Model::Base
with_timestamps
mapping(
{
id: Primary64,
name: String,
email: String,
lock_version: {type: Int64, default: 0_i64},
gender: {type: Gender, converter: Jennifer::Model::EnumConverter(Gender), default: Gender::UNSPECIFIED},
created_at: {type: Time, default: Time.utc},
updated_at: {type: Time, default: Time.utc},
},
false
)
end
pry(bin/console.cr)> u = User.new({name: "", email: ""}, false)
=> #<User:0x7fa6f7d932d0 id: nil, name: "", email: "", lock_version: 0, gender: unspecified, created_at: 2023-01-12 01:00:26.753184361 UTC, updated_at: 2023-01-12 01:00:26.753200496 UTC>
pry(bin/console.cr)> u.gender
=> unspecified
pry(bin/console.cr)> u.gender = :male
=> male
pry(bin/console.cr)> u.gender
=> male
pry(bin/console.cr)> u.gender.class
=> Gender
from jennifer.cr.
@cyangle that works if the db column is an integer, but I need to store the value as a string (to maintain existing functionality for now)
I ended up with this:
class ActiveRecordEnumConverter
def self.from_db(result_set : DB::ResultSet, options_tuple : NamedTuple)
result_value = result_set.read(String)
PollingPlace.available_types_hash.each do |key, value|
return key.to_s if value == result_value
end
end
def self.to_db(save_value : String | Nil, options) : String
save_value = "PS" if save_value.nil?
new_save_value = "PS"
PollingPlace.available_types_hash.each do |key, value|
new_save_value = value if key.to_s == save_value || value == save_value
end
new_save_value
end
def self.from_hash(hash : Hash(String, Jennifer::DBAny | T), column_name : String, named_tuple : NamedTuple)
hash[column_name]
end
end
class PollingPlace < ApplicationRecord
with_timestamps
mapping(
id: Primary64,
type: { type: String, converter: ActiveRecordEnumConverter, default: "PS" },
updated_at: Time,
created_at: Time
)
AVAILABLE_TYPES = {
"precinct_specific" => "PS",
"early_absentee" => "ES",
"vote_center" => "VC"
}
def self.available_types_hash
AVAILABLE_TYPES
end
end
I skipped the support for passing in symbols for now, but I could pretty easily mix that in.
I still think it would be nice to have this mixed into the core of the ORM to make adoption from existing Rails/ActiveRecord projects easier.
from jennifer.cr.
@crimson-knight It works with string column and postgres enum type column:
You can find more about creating string backed enum column in here
Here's the users schema:
debater_dev=# select * from users;
id | name | email | gender | lock_version | created_at | updated_at
----+------+------------------+-------------+--------------+----------------------------+----------------------------
1 | test | [email protected] | unspecified | 0 | 2023-01-14 03:05:38.738286 | 2023-01-14 03:05:38.738311
(1 row)
debater_dev=# \d users
Table "public.users"
Column | Type | Collation | Nullable | Default
--------------+-----------------------------+-----------+----------+-----------------------------------
id | bigint | | not null | nextval('users_id_seq'::regclass)
name | character varying(254) | | not null |
email | character varying(254) | | not null |
gender | character varying(254) | | not null | 'unspecified'::character varying
lock_version | bigint | | not null | 0
created_at | timestamp without time zone | | not null |
updated_at | timestamp without time zone | | not null |
Indexes:
"users_pkey" PRIMARY KEY, btree (id)
"lower_case_email" UNIQUE, btree (lower(email::text))
"users_created_at_idx" btree (created_at)
"users_updated_at_idx" btree (updated_at)
from jennifer.cr.
So, basically both postgresql and jennifer treat the column as string column.
You can use integer backed enum column by removing the enum converter from the model.
from jennifer.cr.
Thanks @cyangle but that doesn't help me here, I have an existing MySQL db using string values for this enum column. That's an existing pattern in Rails/ActiveRecord so I figured it would be a good idea to support it here as well
from jennifer.cr.
@crimson-knight You might find this useful: crystal-lang/crystal#10281 (comment)
enum PollingType
PRECINCT_SPECIFIC
EARLY_ABSENTEE
VOTE_CENTER
def self.parse(value) : self
case value.to_s.upcase
when "PS", "PRECINCT_SPECIFIC"
PRECINCT_SPECIFIC
when "ES", "EARLY_ABSENTEE"
EARLY_ABSENTEE
when "VC", "VOTE_CENTER"
VOTE_CENTER
else
raise "Unknown value for PollingType"
end
end
def to_s : String
case self
when PRECINCT_SPECIFIC
"PS"
when EARLY_ABSENTEE
"ES"
when VOTE_CENTER
"VC"
else
raise "Unknown value for PollingType"
end
end
end
Jennifer::Model::EnumConverter reads from db with parse
and writes to db with to_s
.
https://github.com/imdrasil/jennifer.cr/blob/master/src/jennifer/model/enum_converter.cr
from jennifer.cr.
Thanks, seeing multiple ways to accomplish something is great. But the question still remains, can we add this to Jennifer to make it native behavior? @imdrasil what are your thoughts?
from jennifer.cr.
Hm, it sounds that in your case you actually need to have a slightly complicated logic for a database value transformation rather than actual enum functionality. I see value converting string/integer value to crystal enum during runtime to restrict values that can be used. But I'm not sure is it a good idea to have a built-in utility to transform string value from one format to another. I'd rather use a combination of serialized/decorator and input data transformation to be able to use different value for front-end and back-end. What do you think?
from jennifer.cr.
@imdrasil yes that's right along the lines of what I was thinking. I'm mostly thinking of a nice easy DSL to use that would make utilizing the feature easier for someone coming from ActiveRecord.
from jennifer.cr.
I'm still working on this FYI, I'll post a PR with the idea as soon as I can
from jennifer.cr.
Related Issues (20)
- JSON columns with array values being updated is not recognized as "changed" & does not save HOT 3
- Password digest not created when using with_authentication directly via model build HOT 2
- Shard "inflector" version (0.1.8) doesn't match tag version (1.0.0)
- Empty seed task HOT 1
- Executing raw SQL directly through the connection HOT 5
- `load_dependencies "jennifer"` issue with Jennifer::QueryBuilder::Condition error HOT 4
- Slow performance when creating new records HOT 7
- PCRE2 compatibility HOT 1
- How i run a migrate without using sam? HOT 3
- How to configure database connection? HOT 3
- Column can't be casted from JSON::PullParser to it's type - (JSON::Any | Nil) HOT 2
- Error: expected argument #1 to 'Log#level=' to be Log::Severity, not Symbol HOT 2
- Having trouble getting up and running HOT 6
- Unable to silence logs with crystal builtin Log.setup {} pattern HOT 1
- There was a problem expanding macro 'common_mapping' HOT 2
- Add colour to logs HOT 4
- Migrations are not being run when running specs HOT 3
- Jennifer.cr is broken '-- Task not found.' HOT 2
- Severity cannot be changed based on environment once `master` branch HOT 6
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from jennifer.cr.