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

Improves support for upcasting lenses #925

Merged
merged 1 commit into from
Dec 6, 2024

Conversation

Lysander
Copy link
Collaborator

@Lysander Lysander commented Dec 4, 2024

Introduces a dedicated Lens-factory for upcasting lenses: lensForUpcasting

Its inner code will catch ClassCastExceptions, which can occur in nested Mountpoints, and throw a dedicated CollectionLensGetException. This solution is similar to the handling of false index access or access by keys for collections, we already have integrated.

This is necessary due to the fact, that fritz2 does not maintain any sort of Flow-hierarchy from the outermost to the innermost renderings. So the framework cannot control the sequence of collecting the involved flows, in order to prevent outdated data or - for this case - types.

This is a practical compromise, that will work very well for UIs, as the visual appearance is kind of dictated by the properties of the underlying type.

@Lysander Lysander self-assigned this Dec 4, 2024
@Lysander Lysander requested a review from haukesomm December 4, 2024 17:18
@Lysander Lysander added the enhancement New feature or request label Dec 4, 2024
@Lysander Lysander added this to the 1.0-RC20 milestone Dec 4, 2024
@Lysander
Copy link
Collaborator Author

Lysander commented Dec 4, 2024

You can use this code to reproduce the problem and to test the solution:

// some simple model; remember to put this into some `commonMain` sourceset!
import dev.fritz2.core.Lenses

@Lenses
sealed interface ConsultationModel {
    val stockNumber: String

    companion object
}

@Lenses
data class AgencyConsultation(
    override val stockNumber: String,
    val branch: String
) : ConsultationModel {
    companion object
}

@Lenses
data class PrivateConsultation(override val stockNumber: String) : ConsultationModel {
    companion object
}

// PoC that will produce the error before the PR and prevent any error after the PR.
fun main() {
    render {
        val storedAgency = storeOf<ConsultationModel?>(null)
        val storedStockNumber = storedAgency.map(ConsultationModel.stockNumber())
        val storedBranch = storedAgency.map(ConsultationModel.agencyConsultation().branch())

        section("m-4 p-4 bg-gray-100 space-y-4") {
            h1 { +"Consultation" }

            div("flex gap-4 flex-row mb-4") {
                button("p-2 bg-gray-300") {
                    +"Agency"
                    clicks.map { AgencyConsultation("123", "Bildung") } handledBy storedAgency.update
                }
                button("p-2 bg-gray-300") {
                    +"Private"
                    clicks.map { PrivateConsultation("123") } handledBy storedAgency.update
                }
            }

            div("flex gap-4 flex-col") {
                storedAgency.data.renderNotNull {
                    label {
                        +"Stocknumber"
                        input {
                            value(storedStockNumber.data)
                            changes.values() handledBy storedStockNumber.update
                        }
                    }
                }

                storedAgency.data.onEach { delay(500) }.renderIs(AgencyConsultation::class) {
		//                         ^^^^^^^^^^
		//                         this delay will relieably produce the 
		//                         ClassCastException before PR
                    label {
                        +"Branch"
                        input {
                            value(storedBranch.data)
                            changes.values() handledBy storedBranch.update
                        }
                    }
                }
            }

        }

        section("m-4 p-4 bg-gray-100") {
            pre {
                storedAgency.data.asString().renderText(into = this)
            }
        }

        portalRoot()
    }
}

@Lysander Lysander force-pushed the chausknecht/improve-upcasting-lens-generation branch from d2cec50 to ef9e089 Compare December 6, 2024 09:32
haukesomm
haukesomm previously approved these changes Dec 6, 2024
Introduces a dedicated `Lens`-factory fpr upcasting lenses:
`lensForUpcasting`

Its inner code will catch `ClassCastException`s, which can
occur in nested `Mountpoints`, and throw a dedicated `CollectionLensGetException`.
This solution is similar to the handling of false index access or
access by keys for collections, we already have integrated.

This is necessary due to the fact, that fritz2 does not maintain
any sort of `Flow`-hierarchie from the outermost to the innermost
renderings. So the framework cannot control the sequence of collecting
the involved flows, in order to prevent outdated data or - for this case - *types*.

This is a practical compromise, that will work very well for UIs,
as the visual appearance is kind of *dictated* by the properties of the underlying type.
@Lysander Lysander force-pushed the chausknecht/improve-upcasting-lens-generation branch from ef9e089 to e5d64d2 Compare December 6, 2024 12:40
@Lysander Lysander requested a review from haukesomm December 6, 2024 12:40
@Lysander Lysander merged commit c72db28 into master Dec 6, 2024
2 checks passed
@Lysander Lysander deleted the chausknecht/improve-upcasting-lens-generation branch December 6, 2024 14:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants