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

[ADP-2565] Implement Table database schema type and basic SQL operations #4689

Merged
merged 2 commits into from
Jul 23, 2024

Conversation

HeinrichApfelmus
Copy link
Contributor

@HeinrichApfelmus HeinrichApfelmus commented Jul 18, 2024

This pull request

  • Implements a type Table that represents the schema of a table in a database.
  • Implements a basic set of database operations on top sqlite-simple that work with this Table schema type. A demonstration can be found in Demo.Database.

Comments

  • The SqlM monad, more precisely the runSqlM function, currently makes no attempt at handling exceptions or concurrency correctly. It doesn't look like this will turn out to be a good idea, I will fix this in a future pull request.
  • I have skipped extensive property testing for now, as I want to stabilize the API first. The module Demo.Database provides a basic functionality check.

Issue Number

ADP-2565

@HeinrichApfelmus HeinrichApfelmus self-assigned this Jul 18, 2024
Copy link
Member

@Anviking Anviking left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👌 looks neat

createTable proxy =
CreateTable
(getTableName proxy)
(zip (getColNames proxy) (getColumnTypes proxy))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was wondering why you didn't have a single getColumns :: ... -> [(ColumnName, SqlType)] to ensure the right column is paired with the right type (e.g. that one list hasn't been reversed) I suspect you did this to keep Database.Table.Schema separate from any notion of SQL/Sqlite though.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suspect you did this to keep Database.Table.Schema separate from any notion of SQL/Sqlite though.

Indeed.

I also would have liked the module Database.Table.SQL.Column to not depend on specific types from sqlite-simple, because the SQL language is, in principle, independent of any particular backend such as SQLite. But that would have meant duplicating the types, and I left it at this.

Comment on lines 78 to 80
getColumnTypesD _ =
getColumnTypesD (Proxy :: Proxy t)
`append` singleton (getSqlType (Proxy :: Proxy a))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm guessing this is the faster version of

-- FIXME? O(n^2) when getting names
instance (IsTable t, KnownSymbol name) => IsTable (t :. Col name a) where
getTableName _ = getTableName (Proxy :: Proxy t)
getColNames _ =
getColNames (Proxy :: Proxy t)
++ [T.pack $ symbolVal (Proxy :: Proxy name)]

why not use the same approach in both cases?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not use the same approach in both cases?

Laziness on my part — it was quick enough to write. 😂 I'll use Data.Sequence for both.

lib/delta-table/src/Demo/Database.hs Show resolved Hide resolved
Comment on lines 81 to 82
newtype Primary = Primary { getPrimary :: Int }
deriving (Eq,Ord,Show)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess we'll likely need to support both non-int and multi-column primary keys though?

Primary poolOwnerPoolId poolOwnerSlot poolOwnerSlotInternalIndex poolOwnerOwner poolOwnerIndex

... which would make it more like

type TablePerson =
    Table "person"
        :. Col "name" Text
        :. Col "birthyear" Int
        :. PrimaryKey ["name", "birthyear"]

? (modulo exact syntax of :. PrimaryKey )

Also foreign keys...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess we'll likely need to support both non-int and multi-column primary keys though?

After some thinking, I have come to the conclusion that I don't want to support primary keys — the simplest for semantics for Table is the semantics where the rows are not required to satisfy additional uniqueness constraints. 🤓

These constraints provide only marginal value for us anyway — when writing code that writes to the table, we have to ensure uniqueness as an invariant, and the only thing that the SQLite uniques constraint gives us is a dynamic error message when this invariant is violated — meh.

Foreign keys are relevant for the interaction of multiple tables — which is also out of scope for Table at the moment.

The Primary type was a small concession to the possibility of having uniqueness constraint in SQLite — but I think that we are better off removing it.

@HeinrichApfelmus HeinrichApfelmus force-pushed the HeinrichApfelmus/ADP-2565/sql-without-where branch 2 times, most recently from bd58f76 to 4b589c4 Compare July 23, 2024 10:36
@HeinrichApfelmus HeinrichApfelmus force-pushed the HeinrichApfelmus/ADP-2565/sql-without-where branch from 4b589c4 to 07ee1ed Compare July 23, 2024 10:57
@HeinrichApfelmus HeinrichApfelmus added this pull request to the merge queue Jul 23, 2024
Merged via the queue into master with commit 4618d90 Jul 23, 2024
3 checks passed
@HeinrichApfelmus HeinrichApfelmus deleted the HeinrichApfelmus/ADP-2565/sql-without-where branch July 23, 2024 13:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants