Are there any example projects where Exposed is us...
# exposed
m
Are there any example projects where Exposed is used without everything being statically defined? So instead of
object
tables and
(companion) object
EntityClasses, have classes that are instantiated e.g. in ktor module on app start, which would give the ability to properly pass in dependencies instead of relying on global variables? For example, for my own extensions of Exposed for handling jsonb columns, I need to pass in a Jackson
ObjectMapper
. Right now, I have a global object where I set a var on application start, but the Exposed part is the only part of my ktor application not having dependencies properly passed in via constructor params (I don’t use any DI framework).
It seems that using
referrersOn
,
backReferencedOn
etc. actual requires
EntityClass
to be used as objects. I tried the following:
Copy code
val manyRefs by application.entityClass<ManyRefEntityClass>().referrersOn(application.table<ManyRefTable>().example)
Where I build a function using reified types to get the entityClass dynamically via application, but the compiler does not recognize `referrersOn`in this example. Instead if I have any object: EntityClass defined, IntelliJ will try to import that objects
referrersOn
function.
r
Couple ideas: • Create custom subclass of the DAO and DSL classes that allows you to pass in an
ObjectMapper
• Use context receivers so a
ObjectMapper
is in scope What specific obstacle are you running into with the extensions you mention? Do you have a partial example to share?
Also, you can try not have your mapper instantiated in a ktor module. This feels like the mapper is now coupled to ktor instead of being a part of the application (or having separate mappers per layer - if you have different requirements on how to de/serialize for web requests/responses and database) A singleton instance isn't necessary a bad thing. Especially stuff without state. Having a consistent
ObjectMapper
across all classes is a godo thing
m
It is not really only the ObjectMapper. Its a little bit hard to explain, we use an internal library for our microservices written on top of Ktor and Exposed, and this library features something like a very opinionated auto-generated CRUD API, using lots of reflection magic (similar to Exposed itself). For example, in this context I need to be able to get access to a
Table
or
EntityClass
just by its name, or do http requests inside the saving logic of an entity. So really my requirement is, inside
Table
or
EntityClass
constructors or methods, I already need to have access to other objects that are only initialized in the application starting module, so it would be best if I can just initialize all the DB classes in the same manner rather than having to use singletons with lateinit vars for example. I think I found a solution that works well enough for now: • Create a class SchemaHandler that stores reference to all Table / EntityClass objects • Register this SchemaHandler with the application (now, everything with access to application can also access the schemaHandler) • Inside the app module / initialization, instantiate 1 instance of each EntityClass/Table and registering this with the SchemaHandler • Here, we need to ensure proper order, such that no table is created first that references another table that does not yet exist • To make Entity initialization work, create a common superclass to all EntityClasses overriding
entityCtor: ((EntityID<Long>) -> E)? = null
, which usually calls a 1 param constructor. Instead, we pass in the
table
here as a 2nd parameter (all implementations require to conform to this standard, having the table as 2nd param) • Instead of writing something like
val bookShop = reference("bookShop", BookShopTable)
, I now write
val bookShop = reference("bookShop", application.table<BookShops>())
because inside the table init, I have access to my application now • The only problem is that usage of Extension functions inside
EntityClass
seem to require static access to them, so I create 1 dummy object: EntityClass and import the extension functions from there Its not perfect but seems to work and from a library user perspective will hopefully be cleaner 😅 Sorry for wall of text its hard to explain
r
Sounds like a great workaround given the constraints of the library