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

Lazily evaluate WHERE clause #148

Closed
vestrel00 opened this issue Dec 23, 2021 · 3 comments
Closed

Lazily evaluate WHERE clause #148

vestrel00 opened this issue Dec 23, 2021 · 3 comments
Assignees
Labels
refactor This may involve a refactor

Comments

@vestrel00
Copy link
Owner

vestrel00 commented Dec 23, 2021

In order to complete #147 and fix #142, the Where statement needs to be lazily evaluated so that it can retain typed information that can be mutated.

Problem

Currently, Where is defined as...

sealed class Where<out T : Field>(private val whereString: String) {
    override fun toString(): String = whereString
}

Any instance of it holds a reference to the evaluated WHERE clause via the whereString. So, for example,

val emailContains = Fields.Email.Address contains "veronica"

At this point, the WHERE clause has already been evaluated to something like (pseudocode to keep things simple),

Where {
    whereString  = "address LIKE 'veronica'"
}

If we redact the entire whereString, it will evaluate to...

"***********************"

This certainly does uphold privacy laws but it doesn't help us debug the issues in production when we look at logs from crashes or analytics. Furthermore, this will just produce an exception when executing the query 😓

Then comes the question, how do we maintain the WHERE clause structure and integrity? How can we redact only "veronica" from this raw String?

Solution

Lazily evaluate the the WHERE clause. In the above example, the ideal output would be...

"address LIKE '********'"

The redaction will be done in #147. This issue simply enables that.

This will require us to refactor the Where class to hold a reference to the actual left-hand-side, operator, and right-hand-side values. Then lazily evaluate (combined) them when toString is invoked.

So, something like this...

data class Where<out T : Field> (
    private val lhs: LeftHandSide<T>,
    private val operator: Operator,
    private val rhs: RightHandSide<T>
) {

    private val evaluatedWhereString: String by unsafeLazy {
        "$lhs $operator $rhs"
    }

    override fun toString(): String = evaluatedWhereString
}

/**
 * Each element in a where statement has the structure; LHS OPERATOR RHS.
 *
 * The left hand side (lhs) can either be another where element OR it can be a field.
 */
internal sealed interface LeftHandSide<out T> {
    class WhereHolder<out T : Field>(val where: Where<T>) : LeftHandSide<T>
    class FieldHolder<out T : Field>(val field: T) : LeftHandSide<T>
}

/**
 * Each element in a where statement has the structure; LHS OPERATOR RHS.
 *
 * The right hand side (rhs) can either be another where element OR it can be any value.
 */
internal sealed interface RightHandSide<out T> {
    class WhereHolder<out T : Field>(val where: Where<T>) : RightHandSide<T>
    class ValueHolder<out T : Field>(val value: Any) : RightHandSide<T>
}

/**
 * Each element in a where statement has the structure; LHS OPERATOR RHS.
 *
 * The operator is an SQL operator.
 */
internal enum class Operator(val operator: String) {

    AND("AND"),
    OR("OR"),

    EQUAL("="),
    NOT_EQUAL("!="),

    GREATER_THAN(">"),
    GREATER_THAN_OR_EQUAL(">="),

    LESS_THAN("<"),
    LESS_THAN_OR_EQUAL("<="),

    IS("IS"),
    IS_NOT("IS NOT"),

    IN("IN"),
    NOT_IN("NOT IN"),

    LIKE("LIKE"),
    NOT_LIKE("NOT LIKE")
}
@vestrel00 vestrel00 added the refactor This may involve a refactor label Dec 23, 2021
@vestrel00 vestrel00 self-assigned this Dec 23, 2021
@vestrel00 vestrel00 pinned this issue Dec 23, 2021
@vestrel00
Copy link
Owner Author

This issue is actually fun to work on!

@vestrel00
Copy link
Owner Author

The actual implementation ended up being a little bit different. I ended up building a binary tree 🤣 See the code changes in #149 !

@vestrel00 vestrel00 unpinned this issue Dec 25, 2021
@vestrel00
Copy link
Owner Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
refactor This may involve a refactor
Projects
None yet
Development

No branches or pull requests

1 participant