-
-
Notifications
You must be signed in to change notification settings - Fork 4k
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
Replacer interface for more flexible NamingStrategy #4042
Conversation
Hello @joelnordell I think the globally Could you make the change accordingly? Thank you. |
Hi @jinzhu, yes I can make that change. |
@jinzhu - I've implemented it. I ran into a couple of issues, though:
Given the above constraints, and wanting to not change the public API at all, I had to do something a bit strange:
It is a little bit ugly for Your thoughts? |
This maintains backward compatibility by making the smap optional - the NamingStrategy still works if it is nil. gorm.Open activates it by calling Init() if the given Namer is a schema.NamingStrategy. Also, this changes the key stored in the smap to be the original name, instead of the replaced name.
…en Replacers get called.
Change |
I thought about that, but it would be a breaking API change. |
Yes, sounds not good, but sounds like a better choice then currently... Or maybe we should just remove the name caches, I don't think this helped the performance much if any. As we already cached the model's schema, which has the table/column name already, so seems not necessary to have a second level caches. |
Removing the name cache sounds like a good plan. I'll make that change. I'll also check the benchmark tests to see if it actually does make a difference or not. (Update: running the benchmark tests before and after removing the name cache shows no difference.) |
@jinzhu - is this good to merge? |
* Change NameReplacer to an interface, allowing custom Replacers. * Add NoLowerCase option to skip the snake_casing of names. * Move sync.Map from global variable into member of NamingStrategy. This maintains backward compatibility by making the smap optional - the NamingStrategy still works if it is nil. gorm.Open activates it by calling Init() if the given Namer is a schema.NamingStrategy. Also, this changes the key stored in the smap to be the original name, instead of the replaced name. * Refactor NamingStrategy tests to add more assertions about how and when Replacers get called. * Remove the name cache from NamingStrategy.
* Change NameReplacer to an interface, allowing custom Replacers. * Add NoLowerCase option to skip the snake_casing of names. * Move sync.Map from global variable into member of NamingStrategy. This maintains backward compatibility by making the smap optional - the NamingStrategy still works if it is nil. gorm.Open activates it by calling Init() if the given Namer is a schema.NamingStrategy. Also, this changes the key stored in the smap to be the original name, instead of the replaced name. * Refactor NamingStrategy tests to add more assertions about how and when Replacers get called. * Remove the name cache from NamingStrategy.
What did this pull request do?
This pull request makes
NamingStrategy
more flexible by allowing the user to provide a customReplacer
with an arbitrary implementation ofReplace()
. This change is fully backwards compatible:strings.NewReplacer
continues to work as before.Additionally, there is a new field named
NoLowerCase
which, when settrue
, will cause theNamingStrategy
to skip converting names to snake_case. This is also backwards compatible: the default, when unspecified, is to keep the existing behavior. Definitely open to suggestions for naming that field if you prefer something different!User Case Description
I am using GORM to interface with an existing sqlite database schema (Apple's Photos.app library) which uses naming conventions like
ZGENERICASSET
andZFILENAME
for its tables and fields. I would like to define my structs very simply like this, without requiringgorm
tags to specify table or column names:With this change, I can achieve the above by using a simple
NamingStrategy
and no need to re-implement the fullNamer
interface: