Skip to content

Commit

Permalink
Make Contextual provided DataModels more secure by letting them work …
Browse files Browse the repository at this point in the history
…with DataModelReferences so they can be checked on resolving. This saves you from stack overflows.
  • Loading branch information
jurmous committed Feb 17, 2024
1 parent 09a6060 commit 378d20b
Show file tree
Hide file tree
Showing 8 changed files with 26 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ class EmbeddedObjectDefinition<DO : Any, DM : IsTypedObjectDataModel<DO, *, CXI,
contextualResolver = { context: ModelContext?, name ->
context?.definitionsContext?.let {
@Suppress("UNCHECKED_CAST")
it.dataModels[name]?.get as? Unit.() -> IsTypedObjectDataModel<*, *, *, *>
it.dataModels[name] as? IsDataModelReference<IsTypedObjectDataModel<*, *, *, *>>
?: throw DefNotFoundException("ObjectDataModel of name $name not found on dataModels")
} ?: throw ContextNotFoundException()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import maryk.core.properties.definitions.contextual.DataModelReference
import maryk.core.properties.definitions.contextual.IsDataModelReference
import maryk.core.properties.definitions.contextual.ModelContext
import maryk.core.properties.definitions.contextual.embedContextual
import maryk.core.properties.definitions.wrapper.ContextualDefinitionWrapper
import maryk.core.properties.definitions.wrapper.DefinitionWrapperDelegateLoader
import maryk.core.properties.definitions.wrapper.EmbeddedValuesDefinitionWrapper
import maryk.core.properties.definitions.wrapper.IsDefinitionWrapper
Expand Down Expand Up @@ -156,7 +155,7 @@ class EmbeddedValuesDefinition<DM : IsValuesDataModel>(
) {
val required by boolean(1u, EmbeddedValuesDefinition<*>::required, default = true)
val final by boolean(2u, EmbeddedValuesDefinition<*>::final, default = false)
val dataModel: ContextualDefinitionWrapper<IsDataModelReference<IsValuesDataModel>, Unit.() -> IsValuesDataModel, ModelContext, ContextualModelReferenceDefinition<IsValuesDataModel, ModelContext, ContainsDefinitionsContext>, EmbeddedValuesDefinition<*>> by contextual(
val dataModel by contextual(
index = 3u,
definition = ContextualModelReferenceDefinition(
contextTransformer = { context: ModelContext? ->
Expand All @@ -165,7 +164,7 @@ class EmbeddedValuesDefinition<DM : IsValuesDataModel>(
contextualResolver = { context: ContainsDefinitionsContext?, name ->
context?.let {
@Suppress("UNCHECKED_CAST")
it.dataModels[name]?.get as? Unit.() -> IsValuesDataModel
it.dataModels[name] as? IsDataModelReference<IsValuesDataModel>
?: throw DefNotFoundException("ObjectDataModel of name $name not found on dataModels")
} ?: throw ContextNotFoundException()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ class ReferenceDefinition<DM : IsRootDataModel>(
contextualResolver = { context: ContainsDefinitionsContext?, name ->
context?.let {
@Suppress("UNCHECKED_CAST")
it.dataModels[name]?.get as? (Unit.() -> IsRootDataModel)?
it.dataModels[name] as? IsDataModelReference<IsRootDataModel>
?: throw DefNotFoundException("ObjectDataModel of name $name not found on dataModels")
} ?: throw ContextNotFoundException()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import maryk.core.properties.definitions.contextual.ContextualModelReferenceDefi
import maryk.core.properties.definitions.contextual.DataModelReference
import maryk.core.properties.definitions.contextual.IsDataModelReference
import maryk.core.properties.definitions.contextual.ModelContext
import maryk.core.properties.definitions.wrapper.ContextualDefinitionWrapper
import maryk.core.properties.definitions.wrapper.DefinitionWrapperDelegateLoader
import maryk.core.properties.definitions.wrapper.FixedBytesDefinitionWrapper
import maryk.core.properties.definitions.wrapper.IsDefinitionWrapper
Expand Down Expand Up @@ -127,14 +126,14 @@ data class ValueObjectDefinition<DO : ValueDataObject, DM : IsValueDataModel<DO,
val required by boolean(1u, ValueObjectDefinition<*, *>::required, default = true)
val final by boolean(2u, ValueObjectDefinition<*, *>::final, default = false)
val unique by boolean(3u, ValueObjectDefinition<*, *>::unique, default = false)
val dataModel: ContextualDefinitionWrapper<IsDataModelReference<IsValueDataModel<*, *>>, IsValueDataModel<*, *>, ModelContext, ContextualModelReferenceDefinition<IsValueDataModel<*, *>, ModelContext, ModelContext>, ValueObjectDefinition<*, *>> by contextual(
val dataModel by contextual(
index = 4u,
getter = ValueObjectDefinition<*, *>::dataModel,
definition = ContextualModelReferenceDefinition(
contextualResolver = { context, name ->
context?.definitionsContext?.let {
@Suppress("UNCHECKED_CAST")
it.dataModels[name]?.get as? (Unit.() -> IsValueDataModel<*, *>)?
it.dataModels[name] as? IsDataModelReference<IsValueDataModel<*, *>>
?: throw DefNotFoundException("DataModel with name $name not found on dataModels")
} ?: throw ContextNotFoundException()
}
Expand All @@ -147,15 +146,15 @@ data class ValueObjectDefinition<DO : ValueDataObject, DM : IsValueDataModel<DO,
fromSerializable = {
it?.get?.invoke(Unit)
},
capturer = { context, dataModel ->
capturer = { context, dataModelRef ->
context.let {
context.definitionsContext?.let { modelContext ->
if (!modelContext.dataModels.containsKey(dataModel.name)) {
modelContext.dataModels[dataModel.name] = dataModel
if (!modelContext.dataModels.containsKey(dataModelRef.name)) {
modelContext.dataModels[dataModelRef.name] = dataModelRef
}
} ?: throw ContextNotFoundException()

context.model = dataModel.get
context.model = dataModelRef.get
}
}
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import maryk.lib.exceptions.ParseException

/** Definition for a reference to another DataObject resolved from context by [contextualResolver]. */
fun <DM : IsDataModel, CX : IsPropertyContext> ContextualModelReferenceDefinition(
contextualResolver: Unit.(context: CX?, name: String) -> Unit.() -> DM
contextualResolver: Unit.(context: CX?, name: String) -> IsDataModelReference<DM>
) = ContextualModelReferenceDefinition<DM, CX, CX>(contextualResolver) {
it
}
Expand All @@ -28,7 +28,7 @@ fun <DM : IsDataModel, CX : IsPropertyContext> ContextualModelReferenceDefinitio
* Has a [contextTransformer] to transform context.
*/
data class ContextualModelReferenceDefinition<DM : IsDataModel, in CX : IsPropertyContext, CXI : IsPropertyContext>(
val contextualResolver: Unit.(context: CXI?, name: String) -> Unit.() -> DM,
val contextualResolver: Unit.(context: CXI?, name: String) -> IsDataModelReference<DM>,
val contextTransformer: Unit.(CX?) -> CXI?
) : IsValueDefinition<IsDataModelReference<DM>, CX>, IsContextualEncodable<IsDataModelReference<DM>, CX> {
override val required = true
Expand Down Expand Up @@ -78,12 +78,14 @@ data class ContextualModelReferenceDefinition<DM : IsDataModel, in CX : IsProper

private fun resolveContext(context: CXI?, name: String): IsDataModelReference<DM> {
try {
this.contextualResolver(Unit, context, name).let {
return DataModelReference(name, it)
}
return this.contextualResolver(Unit, context, name)
} catch (e: DefNotFoundException) {
return LazyDataModelReference(name) {
this.contextualResolver(Unit, context, name)
this.contextualResolver(Unit, context, name).also {
if (it is LazyDataModelReference<*>) {
throw DefNotFoundException("Could not resolve DataModel $name, was it processed before or provided in dependents in the context?")
}
}.get
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import maryk.core.models.IsObjectDataModel
import maryk.core.models.IsRootDataModel
import maryk.core.properties.definitions.contextual.ContextualModelReferenceDefinition
import maryk.core.properties.definitions.contextual.DataModelReference
import maryk.core.properties.definitions.contextual.IsDataModelReference
import maryk.core.properties.definitions.wrapper.contextual
import maryk.core.query.RequestContext
import maryk.core.query.responses.IsResponse
Expand All @@ -24,7 +25,7 @@ internal fun <DM : IsStoreRequest<*, *>> IsObjectDataModel<DM>.addDataModel(
contextualResolver = { context, modelName ->
context?.let {
@Suppress("UNCHECKED_CAST")
it.dataModels[modelName]?.get as? (Unit.() -> IsRootDataModel)?
it.dataModels[modelName] as? IsDataModelReference<IsRootDataModel>
?: throw DefNotFoundException("DataModel of name $modelName not found on dataModels")
} ?: throw ContextNotFoundException()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import maryk.core.properties.definitions.EmbeddedObjectDefinition
import maryk.core.properties.definitions.InternalMultiTypeDefinition
import maryk.core.properties.definitions.contextual.ContextualModelReferenceDefinition
import maryk.core.properties.definitions.contextual.DataModelReference
import maryk.core.properties.definitions.contextual.IsDataModelReference
import maryk.core.properties.definitions.wrapper.contextual
import maryk.core.query.RequestContext
import maryk.core.query.responses.statuses.AddSuccess
Expand Down Expand Up @@ -45,7 +46,7 @@ internal fun <DM : IsDataModelResponse<*>> IsObjectDataModel<DM>.addDataModel(
contextualResolver = { context, name ->
context?.let {
@Suppress("UNCHECKED_CAST")
it.dataModels[name]?.get as? (Unit.() -> IsRootDataModel)?
it.dataModels[name] as? IsDataModelReference<IsRootDataModel>
?: throw DefNotFoundException("ObjectDataModel of name $name not found on dataModels")
} ?: throw ContextNotFoundException()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,10 @@ class ContextualModelReferenceDefinitionTest {
)

private val def = ContextualModelReferenceDefinition<IsDataModel, RequestContext>(
contextualResolver = { context, name -> context!!.dataModels[name]?.get as Unit.() -> IsDataModel }
contextualResolver = { context, name ->
@Suppress("UNCHECKED_CAST")
context!!.dataModels[name] as IsDataModelReference<IsDataModel>
}
)

private val context = RequestContext(
Expand Down

0 comments on commit 378d20b

Please sign in to comment.