-
-
Notifications
You must be signed in to change notification settings - Fork 727
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
Generic Column #183
Comments
A design flaw in SQLite.swift, you mean? You're right: the rigidity of typed expressions has unfortunate consequences:
Shiny typed expressions could be introduced in GRDB, along untyped expressions. But they have an insidious and poisonous seduction to the unaware developers. "Type safety" is all the rage, with Swift. Everybody would rush on typed columns. And when a developer gets the kiss of the spider (the two caveats listed above), it's too much work to refactor the app with saner, untyped, columns. That's why I have decided not to introduce them in GRDB. Does it mean that GRDB has no type safety? Of course not! GRDB is a SQLite library with a focus on application development. That's why it walks on two equally important legs: SQL, and Records. SQL because we're professionals. Records because no developper likes to deal with raw database rows. The type-safety of GRDB lies in the types of records' properties: class User : RowConvertible {
var id: Int64 // here
var email: String // here
var registrationDate: Date // and here
init(row: Row) {
id = row.value(named: "id")
email = row.value(named: "email")
registrationDate = row.value(named: "registrationDate")
}
}
let users = try User.fetchAll(db, "SELECT * FROM users") Type-safe expressions have no purpose in the example above. And yet GRDB manages to be quite safe, and prevents data loss or corruption. Now, the Query Interface has introduced the let user = try User.filter(Column("email") == "[email protected]").fetchOne(db) That class User : RowConvertible {
var id: Int64
var email: String
var registrationDate: Date
static let idCol = Column("id")
static let emailCol = Column("email")
static let registrationDateCol = Column("registrationDate")
init(row: Row) {
id = row.value(User.idCol)
email = row.value(User.emailCol)
registrationDate = row.value(User.registrationDateCol)
}
}
let user = try User.filter(User.emailCol == "[email protected]").fetchOne(db) Now, I agree that many parts of GRDB are still "stringly typed", and could be improved. Suggestions are welcome. But typed expressions are not part of these improvements. |
I consider the I don't like code snippets like the following: // Nothing really happens here
let idCol = Column("id")
let emailCol = Column("email")
let registrationDateCol = Column("registrationDate") It pleases masochistic personalities who enjoy feeding the monster (their database library), instead of taking advantages from the library: // Each line has an effect
class User : RowConvertible {
var id: Int64
var email: String
var registrationDate: Date
init(row: Row) {
id = row.value(named: "id")
email = row.value(named: "email")
registrationDate = row.value(named: "registrationDate")
}
} Now the query interface needs to build expressions, and to build expressions we need columns: let wines = try Wine
.filter(originCol == "Burgundy")
.order(priceCol)
.fetchAll(db) So the That was the price of the query builder. |
Another design flaw in SQLite.swift is that the same type (generic Consequence: users use the same expressions for both table definition and consumption, in the name of DRY: // Look, ma! I don't repeat myself!
let users = Table("users")
let id = Expression<Int64>("id")
let email = Expression<String>("email")
let name = Expression<String>("name")
try db.run(users.create { t in
t.column(id, primaryKey: true)
t.column(email, unique: true)
t.column(name)
})
for user in try db.prepare(users) {
print("id: \(user[id]), email: \(user[email]), name: \(user[name])")
} Why is it a problem? Because database schemas evolve over time. Quoting this comment:
This was another example of the poison that inherently lies in typed expressions. |
I admit that some flaws that I have attributed above to typed columns are more flaws in SQLite.swift itself. Some of them could be fixed, with more of less difficulties. It remains that typed columns belong to the "cathedral" type of libraries, when I prefer GRDB to belong to the "screwdriver" family of libraries. I value straightforward and to-the-point code over pretty abstract constructions that lose touch with reality. It has well served GRDB and its users so far. |
@groue Thanks again for taking the time to explain your design desisions. It really shows how well designed and thought out GRDB is 👍 |
Thanks for asking, because writing things down help a lot! |
I was looking at SQLite.swift and one thing they have which is pretty sweet is a generic/typed
Expression
, the equivalent of GRDB'sColumn
. It should allow more robust, type-checked expressions for the query language. I guess this must has already been discussed. Is there a reason is hasn't been implemented? Lack of time? Design flaw?The text was updated successfully, but these errors were encountered: