Format code with fourmolu
This commit is contained in:
@@ -0,0 +1,76 @@
|
|||||||
|
# AGENTS.md
|
||||||
|
|
||||||
|
## Project Overview
|
||||||
|
|
||||||
|
`orville-sqlite` is a Haskell library providing a type-safe SQLite API modeled after the [Flipstone Orville](https://github.com/flipstone/orville/) PostgreSQL library. It maps Haskell data types to SQLite tables with compile-time schema guarantees.
|
||||||
|
|
||||||
|
## Development Environment
|
||||||
|
|
||||||
|
**All development happens inside Docker.** No local Haskell tools should be installed directly on the host machine.
|
||||||
|
|
||||||
|
Use the `./hs` wrapper script for all Haskell tooling:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./hs stack build
|
||||||
|
./hs stack test
|
||||||
|
./hs stack ghci
|
||||||
|
./hs fourmolu -i src/
|
||||||
|
./hs hlint src/
|
||||||
|
```
|
||||||
|
|
||||||
|
The script builds a Docker image based on `ghcr.io/flipstone/haskell-tools:debian-ghc-9.10.3-5d6640d` with `libsqlite3-dev` installed. A named Docker volume (`orville-sqlite-stack-root`) caches GHC and dependencies across worktrees.
|
||||||
|
|
||||||
|
## Build System
|
||||||
|
|
||||||
|
- **GHC**: 9.10.3
|
||||||
|
- **Build tool**: Stack (via the `hs` wrapper)
|
||||||
|
- **Formatter**: fourmolu
|
||||||
|
- **Linter**: hlint
|
||||||
|
|
||||||
|
## Dependencies
|
||||||
|
|
||||||
|
- **Base SQLite library**: [direct-sqlite](https://github.com/IreneKnapp/direct-sqlite) — the low-level FFI binding to SQLite
|
||||||
|
- This library builds type-safe marshalling, auto-migration, and query execution on top of `direct-sqlite`
|
||||||
|
|
||||||
|
## Target API
|
||||||
|
|
||||||
|
The library should provide APIs analogous to three key modules from `orville-postgresql`:
|
||||||
|
|
||||||
|
1. **`Orville.PostgreSQL.Marshall.SqlMarshaller`** — Type-safe mapping between Haskell records and SQL table columns
|
||||||
|
2. **`Orville.PostgreSQL.AutoMigration`** — Schema migration: create tables if they don't exist, alter tables to match expected schema
|
||||||
|
3. **`Orville.PostgreSQL.Execution`** — Query execution: SELECT, INSERT, UPDATE against typed tables
|
||||||
|
|
||||||
|
### Example Usage (Target API)
|
||||||
|
|
||||||
|
Given a Haskell type:
|
||||||
|
|
||||||
|
```haskell
|
||||||
|
data Person = Person
|
||||||
|
{ firstName :: Text
|
||||||
|
, lastName :: Text
|
||||||
|
, age :: Int
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
It should map to a table:
|
||||||
|
|
||||||
|
```sql
|
||||||
|
CREATE TABLE person (
|
||||||
|
first_name VARCHAR(100) NOT NULL,
|
||||||
|
last_name VARCHAR(100) NOT NULL,
|
||||||
|
age INT
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
And support:
|
||||||
|
- Creating the table if it doesn't exist
|
||||||
|
- Altering the table to match the schema when columns differ
|
||||||
|
- Querying rows as `Person` values
|
||||||
|
- Inserting `Person` values
|
||||||
|
- Updating rows from `Person` values
|
||||||
|
|
||||||
|
## Design Principles
|
||||||
|
|
||||||
|
- Haskell types to SQLite schema — not a direct port of the PostgreSQL implementation
|
||||||
|
- Follow the spirit and API shape of Orville, adapted to SQLite's type system and SQL dialect
|
||||||
|
- Favor type safety and compile-time guarantees over runtime flexibility
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
# orville-sqlite
|
||||||
|
|
||||||
|
This library is intended to be a SQLite Haskell API similar in spirit to https://github.com/flipstone/orville/
|
||||||
|
|
||||||
|
The goal of this library is to provide a type safe approach to mapping Haskell types to SQLite data. We aim for type-safe queries and migrations.
|
||||||
|
|
||||||
|
The Flipstone orville library is robust and deep. This library aspires to the same but realizes it's unlikely to get there anytime soon.
|
||||||
|
|
||||||
|
## Goal
|
||||||
|
|
||||||
|
This library intends to provide a similar API for describing the database schema and executing queries as the Flipstone Orville library.
|
||||||
|
|
||||||
|
We will not port the PostgreSQL implementation directly but instead target a similar API.
|
||||||
|
|
||||||
|
The APIs that concern us the most are:
|
||||||
|
|
||||||
|
- Orville.PostgreSQL.Marshall.SqlMarshaller
|
||||||
|
- Orville.PostgreSQL.AutoMigration as AutoMigration
|
||||||
|
- Orville.PostgreSQL.Execution
|
||||||
|
|
||||||
|
and even for those, we only what's strictly necessary to define a way to take a Haskell data type like
|
||||||
|
|
||||||
|
```haskell
|
||||||
|
|
||||||
|
data Person =
|
||||||
|
Person
|
||||||
|
{ firstName :: Text
|
||||||
|
, lastName :: Text
|
||||||
|
, age :: Int
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
and map it to a table of schema
|
||||||
|
|
||||||
|
```sql
|
||||||
|
CREATE TABLE person (
|
||||||
|
first_name VARCHAR(100) NOT NULL,
|
||||||
|
last_name VARCHAR(100) NOT NULL,
|
||||||
|
age INT
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
and then give us an API for marshalling that Haskell type to that table definition
|
||||||
|
|
||||||
|
then using that marshaller we should have APIs that can;
|
||||||
|
|
||||||
|
- create the table if it does not exist
|
||||||
|
- alter the table to match the schema if the table does exist but its columns don't match
|
||||||
|
- query the table and retrieve Person values
|
||||||
|
- insert Person values into the table
|
||||||
|
- update the table from Person values.
|
||||||
|
|
||||||
|
## Development environment
|
||||||
|
|
||||||
|
The development environment should be entirely inside of Docker - no local
|
||||||
|
tools should be installed on the machine directly. use the `hs` wrapper script
|
||||||
|
to execute Haskell tooling inside of Docker.
|
||||||
|
|
||||||
|
## Base SQLite library
|
||||||
|
|
||||||
|
Our base library for interacting with SQLite should be direct-sqlite - https://github.com/IreneKnapp/direct-sqlite
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Thin wrapper to run Haskell tooling (stack, hpack, fourmolu, hlint, ...)
|
||||||
|
# inside a Docker image with our system dependencies pre-installed.
|
||||||
|
# Usage: ./hs <cmd> [args]
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
PROJECT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
|
||||||
|
# Build a custom image on top of flipstone/haskell-tools that includes
|
||||||
|
# the C libraries our Haskell packages need (e.g. libsqlite3-dev).
|
||||||
|
IMAGE="orville-sqlite-haskell-tools"
|
||||||
|
|
||||||
|
docker build \
|
||||||
|
--quiet \
|
||||||
|
-t "${IMAGE}" \
|
||||||
|
-f - \
|
||||||
|
"${PROJECT_DIR}" << DOCKERFILE
|
||||||
|
FROM ghcr.io/flipstone/haskell-tools:debian-ghc-9.10.3-5d6640d
|
||||||
|
RUN apt-get update -qq && apt-get install -y -qq libsqlite3-dev
|
||||||
|
DOCKERFILE
|
||||||
|
|
||||||
|
# Named Docker volume shared across all worktrees so cached
|
||||||
|
# GHC/dependencies don't need rebuilding per worktree.
|
||||||
|
STACK_ROOT_VOLUME="orville-sqlite-stack-root"
|
||||||
|
|
||||||
|
docker volume inspect "${STACK_ROOT_VOLUME}" > /dev/null 2>&1 || \
|
||||||
|
docker volume create "${STACK_ROOT_VOLUME}" > /dev/null
|
||||||
|
|
||||||
|
exec docker run --rm -i $([ -t 0 ] && printf -- -t) \
|
||||||
|
-v "${PROJECT_DIR}:/work" \
|
||||||
|
-v "${STACK_ROOT_VOLUME}:/stack-root" \
|
||||||
|
-e STACK_ROOT=/stack-root \
|
||||||
|
-w /work/orville-sqlite \
|
||||||
|
"${IMAGE}" \
|
||||||
|
"$@"
|
||||||
@@ -3,16 +3,16 @@
|
|||||||
{-# LANGUAGE LambdaCase #-}
|
{-# LANGUAGE LambdaCase #-}
|
||||||
{-# LANGUAGE OverloadedStrings #-}
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
|
|
||||||
module Orville.SQLite.AutoMigration
|
module Orville.SQLite.AutoMigration (
|
||||||
( MigrationOptions (..)
|
MigrationOptions (..),
|
||||||
, defaultOptions
|
defaultOptions,
|
||||||
, SchemaItem (..)
|
SchemaItem (..),
|
||||||
, schemaTable
|
schemaTable,
|
||||||
, dropColumns
|
dropColumns,
|
||||||
, autoMigrateSchema
|
autoMigrateSchema,
|
||||||
, MigrationStep (..)
|
MigrationStep (..),
|
||||||
, generateMigrationPlan
|
generateMigrationPlan,
|
||||||
, executeMigrationPlan
|
executeMigrationPlan,
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import Control.Monad (when)
|
import Control.Monad (when)
|
||||||
@@ -23,12 +23,12 @@ import qualified Data.Text as T
|
|||||||
import qualified Database.SQLite3 as SQLite3
|
import qualified Database.SQLite3 as SQLite3
|
||||||
import Orville.SQLite.FieldDefinition (fieldColumnName)
|
import Orville.SQLite.FieldDefinition (fieldColumnName)
|
||||||
import Orville.SQLite.Monad (OrvilleM)
|
import Orville.SQLite.Monad (OrvilleM)
|
||||||
import Orville.SQLite.SqlMarshaller
|
import Orville.SQLite.SqlMarshaller (
|
||||||
( FieldInfo (..)
|
FieldInfo (..),
|
||||||
, SqlMarshaller
|
SqlMarshaller,
|
||||||
, marshallerFieldInfo
|
marshallerFieldInfo,
|
||||||
)
|
)
|
||||||
import Orville.SQLite.TableDefinition (TableDefinition (..), PrimaryKey (..))
|
import Orville.SQLite.TableDefinition (PrimaryKey (..), TableDefinition (..))
|
||||||
|
|
||||||
data MigrationOptions = MigrationOptions
|
data MigrationOptions = MigrationOptions
|
||||||
{ runSchemaChanges :: Bool
|
{ runSchemaChanges :: Bool
|
||||||
@@ -47,7 +47,8 @@ data SchemaItemRep where
|
|||||||
, schemaItemMarshaller :: SqlMarshaller w r
|
, schemaItemMarshaller :: SqlMarshaller w r
|
||||||
, schemaItemPkName :: String
|
, schemaItemPkName :: String
|
||||||
, schemaItemDropColumns :: [String]
|
, schemaItemDropColumns :: [String]
|
||||||
} -> SchemaItemRep
|
} ->
|
||||||
|
SchemaItemRep
|
||||||
|
|
||||||
schemaTable ::
|
schemaTable ::
|
||||||
TableDefinition key writeEntity readEntity ->
|
TableDefinition key writeEntity readEntity ->
|
||||||
|
|||||||
@@ -2,12 +2,12 @@
|
|||||||
{-# LANGUAGE OverloadedStrings #-}
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
{-# LANGUAGE ScopedTypeVariables #-}
|
{-# LANGUAGE ScopedTypeVariables #-}
|
||||||
|
|
||||||
module Orville.SQLite.Execution
|
module Orville.SQLite.Execution (
|
||||||
( insertEntity
|
insertEntity,
|
||||||
, findEntity
|
findEntity,
|
||||||
, findAll
|
findAll,
|
||||||
, updateEntity
|
updateEntity,
|
||||||
, deleteEntity
|
deleteEntity,
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import Control.Monad.IO.Class (liftIO)
|
import Control.Monad.IO.Class (liftIO)
|
||||||
@@ -18,12 +18,12 @@ import qualified Database.SQLite3 as SQLite3
|
|||||||
import Database.SQLite3.Direct (columnCount)
|
import Database.SQLite3.Direct (columnCount)
|
||||||
import Orville.SQLite.FieldDefinition (fieldColumnName, fieldToSqlValue)
|
import Orville.SQLite.FieldDefinition (fieldColumnName, fieldToSqlValue)
|
||||||
import Orville.SQLite.Monad (OrvilleM)
|
import Orville.SQLite.Monad (OrvilleM)
|
||||||
import Orville.SQLite.SqlMarshaller
|
import Orville.SQLite.SqlMarshaller (
|
||||||
( marshallerDerivedColumns
|
marshallerDecodeRow,
|
||||||
, marshallerEncodeWrite
|
marshallerDerivedColumns,
|
||||||
, marshallerDecodeRow
|
marshallerEncodeWrite,
|
||||||
)
|
)
|
||||||
import Orville.SQLite.TableDefinition (TableDefinition (..), PrimaryKey (..))
|
import Orville.SQLite.TableDefinition (PrimaryKey (..), TableDefinition (..))
|
||||||
|
|
||||||
insertEntity ::
|
insertEntity ::
|
||||||
TableDefinition key writeEntity readEntity ->
|
TableDefinition key writeEntity readEntity ->
|
||||||
|
|||||||
@@ -3,37 +3,37 @@
|
|||||||
{-# LANGUAGE KindSignatures #-}
|
{-# LANGUAGE KindSignatures #-}
|
||||||
{-# LANGUAGE LambdaCase #-}
|
{-# LANGUAGE LambdaCase #-}
|
||||||
|
|
||||||
module Orville.SQLite.FieldDefinition
|
module Orville.SQLite.FieldDefinition (
|
||||||
( Nullability (..)
|
Nullability (..),
|
||||||
, FieldDefinition (..)
|
FieldDefinition (..),
|
||||||
, integerField
|
integerField,
|
||||||
, textField
|
textField,
|
||||||
, realField
|
realField,
|
||||||
, blobField
|
blobField,
|
||||||
, nullableField
|
nullableField,
|
||||||
, convertField
|
convertField,
|
||||||
, fieldToSqlValue
|
fieldToSqlValue,
|
||||||
, fieldFromSqlValue
|
fieldFromSqlValue,
|
||||||
, fieldColumnName
|
fieldColumnName,
|
||||||
, fieldSqlTypeName
|
fieldSqlTypeName,
|
||||||
, fieldIsNullable
|
fieldIsNullable,
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import Data.Kind (Type)
|
|
||||||
import qualified Data.ByteString as BS
|
import qualified Data.ByteString as BS
|
||||||
import Data.Int (Int64)
|
import Data.Int (Int64)
|
||||||
|
import Data.Kind (Type)
|
||||||
import qualified Data.Text as T
|
import qualified Data.Text as T
|
||||||
import qualified Database.SQLite3 as SQLite3
|
import qualified Database.SQLite3 as SQLite3
|
||||||
import Orville.SQLite.SqlType
|
import Orville.SQLite.SqlType (
|
||||||
( SqlType
|
SqlType,
|
||||||
, convertSqlType
|
blobType,
|
||||||
, integerType
|
convertSqlType,
|
||||||
, realType
|
integerType,
|
||||||
, blobType
|
realType,
|
||||||
, sqlTypeFromSql
|
sqlTypeFromSql,
|
||||||
, sqlTypeName
|
sqlTypeName,
|
||||||
, sqlTypeToSql
|
sqlTypeToSql,
|
||||||
, textType
|
textType,
|
||||||
)
|
)
|
||||||
|
|
||||||
data Nullability = NotNull | Nullable
|
data Nullability = NotNull | Nullable
|
||||||
@@ -42,11 +42,13 @@ data FieldDefinition (nullability :: Nullability) :: Type -> Type where
|
|||||||
NotNullField ::
|
NotNullField ::
|
||||||
{ notNullFieldName :: String
|
{ notNullFieldName :: String
|
||||||
, notNullFieldSqlType :: SqlType a
|
, notNullFieldSqlType :: SqlType a
|
||||||
} -> FieldDefinition 'NotNull a
|
} ->
|
||||||
|
FieldDefinition 'NotNull a
|
||||||
NullableField ::
|
NullableField ::
|
||||||
{ nullableFieldName :: String
|
{ nullableFieldName :: String
|
||||||
, nullableFieldSqlType :: SqlType a
|
, nullableFieldSqlType :: SqlType a
|
||||||
} -> FieldDefinition 'Nullable a
|
} ->
|
||||||
|
FieldDefinition 'Nullable a
|
||||||
|
|
||||||
fieldColumnName :: FieldDefinition null a -> String
|
fieldColumnName :: FieldDefinition null a -> String
|
||||||
fieldColumnName = \case
|
fieldColumnName = \case
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
|
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
|
||||||
{-# LANGUAGE OverloadedStrings #-}
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
|
|
||||||
module Orville.SQLite.Monad
|
module Orville.SQLite.Monad (
|
||||||
( OrvilleM
|
OrvilleM,
|
||||||
, withConnection
|
withConnection,
|
||||||
, openConnection
|
openConnection,
|
||||||
, closeConnection
|
closeConnection,
|
||||||
, runOrvilleM
|
runOrvilleM,
|
||||||
, withTransaction
|
withTransaction,
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import Control.Monad.IO.Class (MonadIO (liftIO))
|
import Control.Monad.IO.Class (MonadIO (liftIO))
|
||||||
import Control.Monad.Reader (ReaderT, runReaderT, ask, MonadReader)
|
import Control.Monad.Reader (MonadReader, ReaderT, ask, runReaderT)
|
||||||
import qualified Data.Text as T
|
import qualified Data.Text as T
|
||||||
import qualified Database.SQLite3 as SQLite3
|
import qualified Database.SQLite3 as SQLite3
|
||||||
|
|
||||||
|
|||||||
@@ -1,16 +1,16 @@
|
|||||||
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
|
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
|
||||||
|
|
||||||
module Orville.SQLite.RawSql
|
module Orville.SQLite.RawSql (
|
||||||
( RawSql (..)
|
RawSql (..),
|
||||||
, fromString
|
fromString,
|
||||||
, toRawSql
|
toRawSql,
|
||||||
, intercalate
|
intercalate,
|
||||||
, fromText
|
fromText,
|
||||||
, space
|
space,
|
||||||
, comma
|
comma,
|
||||||
, leftParen
|
leftParen,
|
||||||
, rightParen
|
rightParen,
|
||||||
, equals
|
equals,
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import qualified Data.Text as T
|
import qualified Data.Text as T
|
||||||
|
|||||||
@@ -3,27 +3,27 @@
|
|||||||
{-# LANGUAGE LambdaCase #-}
|
{-# LANGUAGE LambdaCase #-}
|
||||||
{-# LANGUAGE ScopedTypeVariables #-}
|
{-# LANGUAGE ScopedTypeVariables #-}
|
||||||
|
|
||||||
module Orville.SQLite.SqlMarshaller
|
module Orville.SQLite.SqlMarshaller (
|
||||||
( SqlMarshaller
|
SqlMarshaller,
|
||||||
, FieldInfo (..)
|
FieldInfo (..),
|
||||||
, marshallField
|
marshallField,
|
||||||
, marshallReadOnlyField
|
marshallReadOnlyField,
|
||||||
, marshallMaybe
|
marshallMaybe,
|
||||||
, marshallerFieldInfo
|
marshallerFieldInfo,
|
||||||
, marshallerDerivedColumns
|
marshallerDerivedColumns,
|
||||||
, marshallerEncodeWrite
|
marshallerEncodeWrite,
|
||||||
, marshallerDecodeRow
|
marshallerDecodeRow,
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import qualified Database.SQLite3 as SQLite3
|
import qualified Database.SQLite3 as SQLite3
|
||||||
import Orville.SQLite.FieldDefinition
|
import Orville.SQLite.FieldDefinition (
|
||||||
( FieldDefinition (..)
|
FieldDefinition (..),
|
||||||
, Nullability (..)
|
Nullability (..),
|
||||||
, fieldColumnName
|
fieldColumnName,
|
||||||
, fieldToSqlValue
|
fieldFromSqlValue,
|
||||||
, fieldFromSqlValue
|
fieldIsNullable,
|
||||||
, fieldIsNullable
|
fieldSqlTypeName,
|
||||||
, fieldSqlTypeName
|
fieldToSqlValue,
|
||||||
)
|
)
|
||||||
|
|
||||||
data FieldInfo = FieldInfo
|
data FieldInfo = FieldInfo
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
{-# LANGUAGE LambdaCase #-}
|
{-# LANGUAGE LambdaCase #-}
|
||||||
|
|
||||||
module Orville.SQLite.SqlType
|
module Orville.SQLite.SqlType (
|
||||||
( SqlType (..)
|
SqlType (..),
|
||||||
, integerType
|
integerType,
|
||||||
, textType
|
textType,
|
||||||
, realType
|
realType,
|
||||||
, blobType
|
blobType,
|
||||||
, convertSqlType
|
convertSqlType,
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import qualified Data.ByteString as BS
|
import qualified Data.ByteString as BS
|
||||||
|
|||||||
@@ -2,19 +2,19 @@
|
|||||||
{-# LANGUAGE GADTs #-}
|
{-# LANGUAGE GADTs #-}
|
||||||
{-# LANGUAGE ScopedTypeVariables #-}
|
{-# LANGUAGE ScopedTypeVariables #-}
|
||||||
|
|
||||||
module Orville.SQLite.TableDefinition
|
module Orville.SQLite.TableDefinition (
|
||||||
( PrimaryKey (..)
|
PrimaryKey (..),
|
||||||
, primaryKey
|
primaryKey,
|
||||||
, TableDefinition (..)
|
TableDefinition (..),
|
||||||
, mkTableDefinition
|
mkTableDefinition,
|
||||||
, mkTableDefinitionWithoutKey
|
mkTableDefinitionWithoutKey,
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import Orville.SQLite.FieldDefinition
|
import Orville.SQLite.FieldDefinition (
|
||||||
( FieldDefinition
|
FieldDefinition,
|
||||||
, Nullability (..)
|
Nullability (..),
|
||||||
, integerField
|
convertField,
|
||||||
, convertField
|
integerField,
|
||||||
)
|
)
|
||||||
import Orville.SQLite.SqlMarshaller (SqlMarshaller)
|
import Orville.SQLite.SqlMarshaller (SqlMarshaller)
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
# This file was autogenerated by Stack.
|
||||||
|
# You should not edit this file by hand.
|
||||||
|
# For more information, please see the documentation at:
|
||||||
|
# https://docs.haskellstack.org/en/stable/topics/lock_files
|
||||||
|
|
||||||
|
packages:
|
||||||
|
- completed:
|
||||||
|
hackage: direct-sqlite-2.3.29@sha256:6ff3969a6eae383c8a9ab093abfee7f7b0ed76dab045c984a1497b7e1d71279d,4180
|
||||||
|
pantry-tree:
|
||||||
|
sha256: 794455a2e32dc749ff32d8907bc51d810f79b963d5e21c42bc8555bc34bbd625
|
||||||
|
size: 770
|
||||||
|
original:
|
||||||
|
hackage: direct-sqlite-2.3.29
|
||||||
|
snapshots:
|
||||||
|
- completed:
|
||||||
|
sha256: 3c412a7c13dba6d3d808455a458e0776c58b6cf99b8a7961a2f5e55589d6f1d6
|
||||||
|
size: 729011
|
||||||
|
url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/24/43.yaml
|
||||||
|
original: lts-24.43
|
||||||
+1
-1
@@ -6,8 +6,8 @@ module Main where
|
|||||||
import Control.Monad.IO.Class (liftIO)
|
import Control.Monad.IO.Class (liftIO)
|
||||||
import Data.Int (Int64)
|
import Data.Int (Int64)
|
||||||
import Data.Text (Text)
|
import Data.Text (Text)
|
||||||
import Test.Hspec
|
|
||||||
import Orville.SQLite
|
import Orville.SQLite
|
||||||
|
import Test.Hspec
|
||||||
|
|
||||||
data Person = Person
|
data Person = Person
|
||||||
{ personId :: Int64
|
{ personId :: Int64
|
||||||
|
|||||||
Reference in New Issue
Block a user