I wonder if this library could be written even safer.

Open
#574 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
5/5
Estimated time
Over a week
Newbie friendliness
25/100
Issue type
Feature
Clarity
Mostly clear
Activity status
Stale
Tech stack
sqlite, swift

Research direction

Start by reviewing the current Expression, Table, and database access APIs described in the issue; no implementation file or test is identified. Establish whether the proposed column and table validation belongs in a future major version, then implement and test the agreed design so references are tied to valid database objects.

Written by the indexing model from the issue text.

Description

enhancement help wanted

One thing I love about this library is that you don't reference columns by string literals, but instead by variables that hold expressions. Like here:

let name = Expression<String?>("name")
users.insert(name <- "Alice")

And here:

for user in try db.prepare(users) {
    print(user[name])
}

However, these expressions are not necessarily tied to the table that you are using them on. You are just initializing them yourself and then using them on the table. There is no guarantee that the users table actually has a column named "name". One could also easily make a typo when writing the string literal "name".

So I was wondering, what if you made a new struct called Column or something, which has a private initializer, so only the library can initialize it. It would work a bit like this:

guard let name = users.columns["name"] else {
    throw AnError("the name column does not exist")
}

users.insert(name <- "Alice")
let user = users.first!
print(user[name])

You see this way we can at least 90% guarantee that the name column is actually a valid column for the users table. It's still not 100% of course, because a developer could still write the following and the compiler would not complain:

guard let name = users.columns["name"] else {
    throw AnError("the name column does not exist")
}

posts.insert(name <- "Alice") // note the incorrect table

However, I reckon this situation is far less likely than someone making a mistake in the current system.

I'd even want to go one step further and apply the same to tables. So right now you can just initialize a table (let users = Table("users")) and start using it, even if there is no such table in the database. You can make that much safer by doing something like this:

let users: Table

if let existingUsersTable = db.tables["users"] {
    users = existingUsersTable
} else {
    users = db.createTable("users") {
        // haven't thought this part out yet...
    }
}

What do you guys think? Of course this would be quite a big overhaul so this could only be implemented in the next major version if you actually like this change.

Dominant language
Swift
Stars
10.2k
Forks
1.6k
Avg merge
6d 2h
Merged PRs (30d)
2

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from stephencelis/SQLite.swift

All issues in stephencelis/SQLite.swift

Similar issues

More Swift issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.