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

Strongly type queries #139

Open
miroslavkovac opened this issue Nov 20, 2021 · 3 comments
Open

Strongly type queries #139

miroslavkovac opened this issue Nov 20, 2021 · 3 comments
Labels
enhancement New feature or request

Comments

@miroslavkovac
Copy link

Is there a way to write strongly typed queries?

For example, instead of:

db.select()
    .column("size")
    .from("planets")
    .where("name", .equal, "Earth")

I would like to write something like this:

db.select()
    .column(\Plant.$size)
    .from(Planets.self)
    .where(\Planet.$name, .equal, "Earth")

I am migrating the project form Vapor 3 to Vapor 4 and couldn't find a way of doing this, while it was previously possible. Thank you.

@miroslavkovac miroslavkovac added the enhancement New feature or request label Nov 20, 2021
@0xTim
Copy link
Member

0xTim commented Jan 13, 2022

@miroslavkovac which bits aren't working?

@madsodgaard you showed something in Discord that looked like this should work

@madsodgaard
Copy link

@0xTim @miroslavkovac is right in that is not supported natively by SQL-Kit. I added some extensions to my code to help with using Fluent models in SQLKit code

This won't work if you use @Group in Fluent

Here are the helpers:

// From https://github.com/vapor/fluent-kit/pull/343
extension FieldKey: SQLExpression {
    /// See `SQLExpression`.
    public func serialize(to serializer: inout SQLSerializer) {
        SQLIdentifier(self.string(for: serializer.dialect))
            .serialize(to: &serializer)
    }

    // Converts `FieldKey` to a string.
    //
    // `.description` is not used here since that isn't
    // _necessarily_ a SQL compatible value.
    //
    // SQLDialect is passed in case a specific dialect may
    // need to have special values for id / aggregate.
    private func string(for dialect: SQLDialect) -> String {
        switch self {
        case .id:
            return "id"
        case .aggregate:
            return "aggregate"
        case .prefix(let prefix, let key):
            return prefix.string(for: dialect) + key.string(for: dialect)
        case .string(let string):
            return string
        }
    }
}

extension KeyPath: SQLExpression where Root: Fields, Value: AnyQueryableProperty {
    /// See `SQLExpression`.
    public func serialize(to serializer: inout SQLSerializer) {
        Root()[keyPath: self].path.first!.serialize(to: &serializer)
    }
}

extension SQLPredicateBuilder {
    @discardableResult
    func `where`<E>(_ lhs: SQLExpression, _ op: SQLBinaryOperator, _ rhs: E) -> Self
        where E: Encodable
    {
        return self.where(lhs, op, SQLBind(rhs))
    }
}

This allows you to write the code you specified in your issue.

@0xTim
Copy link
Member

0xTim commented Jan 13, 2022

@gwynne this going to be pushed into Fluent 5?

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

No branches or pull requests

3 participants