diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,6 @@
+# Revision history for eventlog-splittable-ipe
+
+## 0.1.0.0 -- 2026.03.02
+
+* Allows to index and query `.eventlog` files
+* First version. Released on an unsuspecting world.
diff --git a/app/Main.hs b/app/Main.hs
new file mode 100644
--- /dev/null
+++ b/app/Main.hs
@@ -0,0 +1,6 @@
+module Main (main) where
+
+import IpeDb.Main (defaultMain)
+
+main :: IO ()
+main = defaultMain
diff --git a/ipedb.cabal b/ipedb.cabal
new file mode 100644
--- /dev/null
+++ b/ipedb.cabal
@@ -0,0 +1,86 @@
+cabal-version: 3.6
+name: ipedb
+version: 0.1.0.0
+license: BSD-3-Clause
+author: Hannes Siebenhandl, Matthew Pickering
+synopsis: Generate a database for IPE data.
+description: Tool and library to index an `.eventlog` file and query IPE data.
+maintainer: hannes@well-typed.com
+build-type: Simple
+extra-doc-files: CHANGELOG.md
+category: Development
+tested-with:
+  ghc ==9.10.3
+  ghc ==9.12.2
+  ghc ==9.14.1
+
+extra-source-files:
+  test/data/*.eventlog
+
+common warnings
+  ghc-options:
+    -Wall
+    -Wunused-packages
+
+common defaults
+  default-language: GHC2021
+  default-extensions:
+    BangPatterns
+    DeriveAnyClass
+    DeriveGeneric
+    DerivingStrategies
+    GeneralizedNewtypeDeriving
+    LambdaCase
+    NamedFieldPuns
+    NoFieldSelectors
+    OverloadedRecordDot
+    TypeApplications
+
+library
+  import: warnings, defaults
+  exposed-modules:
+    IpeDb.Eventlog.Index
+    IpeDb.InfoProv
+    IpeDb.Main
+    IpeDb.Options
+    IpeDb.Query
+    IpeDb.Table
+    IpeDb.Types
+
+  build-depends:
+    base >=4.20 && <4.23,
+    ghc-events >=0.18 && <0.22,
+    optparse-applicative >=0.16.1 && <0.20,
+    sqlite-simple ^>=0.4.19.0,
+    text ^>=2.1.2,
+
+  hs-source-dirs: src
+  default-language: Haskell2010
+
+executable ipedb
+  import: warnings, defaults
+  main-is: Main.hs
+  build-depends:
+    base >=4.20 && <4.23,
+    ipedb,
+
+  hs-source-dirs: app
+  default-language: Haskell2010
+
+test-suite ipedb-test
+  import: warnings, defaults
+  type: exitcode-stdio-1.0
+  hs-source-dirs: test
+  main-is: Main.hs
+  build-depends:
+    base >=4.20 && <4.23,
+    directory >=1.3.8.5 && <1.4,
+    filepath >=1.4.300.1 && <1.6,
+    ipedb,
+    tasty ^>=1.5.3,
+    tasty-hunit ^>=0.10.2,
+    temporary ^>=1.3,
+
+source-repository head
+  type: git
+  location: https://github.com/well-typed/ipedb.git
diff --git a/src/IpeDb/Eventlog/Index.hs b/src/IpeDb/Eventlog/Index.hs
new file mode 100644
--- /dev/null
+++ b/src/IpeDb/Eventlog/Index.hs
@@ -0,0 +1,148 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+module IpeDb.Eventlog.Index (
+  -- * High level API for interacting with the database
+  withDatabase,
+  generateInfoProvDb,
+  findOneInfoProv,
+  findAllInfoProvs,
+
+  -- * Low level API for interacting with the database
+  setupDb,
+  setupTables,
+  setupIndexing,
+  insertInfoProv,
+  upsertInfoProvStrings,
+
+  -- * ghc-events specific helpers
+  insertInfoProvData,
+)
+where
+
+import Data.Foldable (traverse_)
+import qualified Database.SQLite.Simple as Sqlite
+import Database.SQLite.Simple.Types (Only (..))
+import qualified GHC.RTS.Events as GhcEvents
+import IpeDb.InfoProv as Ipe
+import IpeDb.Table as Table
+import Data.Text (Text)
+import qualified Data.Text as Text
+
+findOneInfoProv :: Sqlite.Connection -> IpeId -> IO (Maybe InfoProv)
+findOneInfoProv conn ipeId = do
+  r <- Sqlite.query conn findInfoTableQuery (Only ipeId)
+  case r of
+    [ipe] -> pure $ Just ipe
+    _ -> pure $ Nothing
+
+findAllInfoProvs :: Sqlite.Connection -> IO [InfoProv]
+findAllInfoProvs conn = do
+  Sqlite.query conn findAllInfoTablesQuery ()
+
+generateInfoProvDb :: Sqlite.Connection -> FilePath -> IO ()
+generateInfoProvDb conn fp = do
+  setupDb conn
+  GhcEvents.readEventLogFromFile fp >>= \case
+    Left err -> fail err
+    Right (GhcEvents.EventLog _h (GhcEvents.Data es)) -> Sqlite.withExclusiveTransaction conn $ do
+      insertInfoProvData conn es
+
+setupDb :: Sqlite.Connection -> IO ()
+setupDb conn = do
+  Sqlite.withExclusiveTransaction conn $ setupTables conn
+  setupIndexing conn
+
+withDatabase :: FilePath -> (Sqlite.Connection -> IO a) -> IO a
+withDatabase fp act = Sqlite.withConnection fp $ \conn ->
+  act conn
+
+-- ----------------------------------------------------------------------------
+-- Low Level Sqlite api
+-- ----------------------------------------------------------------------------
+
+setupTables :: Sqlite.Connection -> IO ()
+setupTables conn = do
+  Sqlite.execute_ conn dropStringTableStmt
+  Sqlite.execute_ conn dropInfoProvTableStmt
+  Sqlite.execute_ conn dropInfoProvTableViewStmt
+  Sqlite.execute_ conn stringTableStmt
+  Sqlite.execute_ conn infoProvTableStmt
+  Sqlite.execute_ conn infoProvTableViewStmt
+
+setupIndexing :: Sqlite.Connection -> IO ()
+setupIndexing conn = do
+  Sqlite.execute_ conn "PRAGMA synchronous = OFF;"
+  Sqlite.execute_ conn "PRAGMA journal_mode = OFF;"
+  Sqlite.execute_ conn "PRAGMA temp_store = MEMORY;"
+  Sqlite.execute_ conn "PRAGMA locking_mode = EXCLUSIVE;"
+
+insertInfoProv :: Sqlite.Connection -> InfoProv -> IO ()
+insertInfoProv conn prov = do
+  row <- upsertInfoProvStrings conn prov
+  _ <- Sqlite.execute conn insertInfoTableQuery row
+  pure ()
+
+upsertInfoProvStrings :: Sqlite.Connection -> InfoProv -> IO InfoProvRow
+upsertInfoProvStrings conn prov = do
+  let
+    (srcLocFile, srcLocRange) = splitGhcSrcLoc prov.srcLoc
+  Sqlite.executeMany
+    conn
+    insertOrIgnoreString
+    [ Only prov.tableName
+    , Only prov.typeDesc
+    , Only prov.label
+    , Only prov.moduleName
+    , Only srcLocFile
+    ]
+  [(taId, tyId, labelId, modId, srcLocId)] <-
+    Sqlite.query
+      conn
+      getIpeStrings
+      ( prov.typeDesc
+      , prov.label
+      , prov.moduleName
+      , srcLocFile
+      , prov.tableName
+      )
+  pure
+    InfoProvRow
+      { Table.infoId = prov.infoId
+      , Table.tableName = taId
+      , Table.closureDesc = prov.closureDesc
+      , Table.typeDesc = tyId
+      , Table.label = labelId
+      , Table.moduleName = modId
+      , Table.srcLoc = srcLocId
+      , Table.srcLocRange = srcLocRange
+      }
+
+splitGhcSrcLoc :: Text -> (Text, Text)
+splitGhcSrcLoc srcLoc = Text.break (== ':') srcLoc
+
+-- ----------------------------------------------------------------------------
+-- Eventlog processing
+-- ----------------------------------------------------------------------------
+
+insertInfoProvData :: (Foldable t) => Sqlite.Connection -> t GhcEvents.Event -> IO ()
+insertInfoProvData conn es = traverse_ (processIpeEvents conn) es
+
+processIpeEvents :: Sqlite.Connection -> GhcEvents.Event -> IO ()
+processIpeEvents conn ev = case eventInfoToInfoProv (GhcEvents.evSpec ev) of
+  Nothing -> pure ()
+  Just infoProv -> insertInfoProv conn infoProv
+
+eventInfoToInfoProv :: GhcEvents.EventInfo -> Maybe InfoProv
+eventInfoToInfoProv ev = case ev of
+  it@GhcEvents.InfoTableProv{} ->
+    Just
+      InfoProv
+        { Ipe.infoId = IpeId $ GhcEvents.itInfo it
+        , Ipe.tableName = GhcEvents.itTableName it
+        , Ipe.closureDesc = fromIntegral $ GhcEvents.itClosureDesc it
+        , Ipe.typeDesc = GhcEvents.itTyDesc it
+        , Ipe.label = GhcEvents.itLabel it
+        , Ipe.moduleName = GhcEvents.itModule it
+        , Ipe.srcLoc = GhcEvents.itSrcLoc it
+        }
+  _ -> Nothing
diff --git a/src/IpeDb/InfoProv.hs b/src/IpeDb/InfoProv.hs
new file mode 100644
--- /dev/null
+++ b/src/IpeDb/InfoProv.hs
@@ -0,0 +1,42 @@
+module IpeDb.InfoProv (
+  InfoProv (..),
+  IpeId (..),
+  prettyIpeId,
+) where
+
+import Data.Int
+import Data.Text (Text)
+import qualified Data.Text as Text
+import Data.Word
+import qualified Database.SQLite.Simple as Sqlite
+import qualified Database.SQLite.Simple.FromField as Sqlite
+import qualified Database.SQLite.Simple.ToField as Sqlite
+import GHC.Generics (Generic)
+import qualified Numeric
+
+data InfoProv = InfoProv
+  { infoId :: !IpeId
+  , tableName :: !Text
+  , closureDesc :: !Int64
+  , typeDesc :: !Text
+  , label :: !Text
+  , moduleName :: !Text
+  , srcLoc :: !Text
+  }
+  deriving (Show, Eq, Ord, Generic)
+  deriving anyclass (Sqlite.FromRow, Sqlite.ToRow)
+
+newtype IpeId = IpeId
+  { id :: Word64
+  }
+  deriving (Eq, Ord)
+  deriving newtype (Sqlite.FromField, Sqlite.ToField)
+
+instance Show IpeId where
+  show ipeId = "IpeId {id = " <> showAsHex (ipeId.id) <> "}"
+
+showAsHex :: (Integral a) => a -> String
+showAsHex n = "0x" <> Numeric.showHex n ""
+
+prettyIpeId :: IpeId -> Text
+prettyIpeId = Text.pack . showAsHex . (.id)
diff --git a/src/IpeDb/Main.hs b/src/IpeDb/Main.hs
new file mode 100644
--- /dev/null
+++ b/src/IpeDb/Main.hs
@@ -0,0 +1,33 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+module IpeDb.Main (defaultMain) where
+
+import Data.Text (Text)
+import qualified Data.Text as Text
+import qualified Data.Text.IO as Text
+import IpeDb.InfoProv
+import qualified IpeDb.Options as Opts
+import IpeDb.Query
+
+defaultMain :: IO ()
+defaultMain = do
+  opts <- Opts.parseOptions
+  case opts.command of
+    Opts.Query query -> withInfoProvDb opts.databaseFp $ \db -> do
+      lookupInfoProv db query.ipeId >>= \case
+        Nothing -> Text.putStrLn $ "No Info Prov found for " <> Text.show query.ipeId
+        Just prov -> Text.putStrLn $ prettyInfoProv prov
+    Opts.Index index -> withInfoProvDb opts.databaseFp $ \db -> do
+      populateFromEventlog db index.eventlog
+
+prettyInfoProv :: InfoProv -> Text
+prettyInfoProv prov =
+  Text.unlines
+    [ "Info Table  " <> prettyIpeId prov.infoId
+    , "  Table Name:      " <> prov.tableName
+    , "  Closure Desc:    " <> Text.show prov.closureDesc
+    , "  Type Desc:       " <> prov.typeDesc
+    , "  Label:           " <> prov.label
+    , "  Modulename:      " <> prov.moduleName
+    , "  Source Location: " <> prov.srcLoc
+    ]
diff --git a/src/IpeDb/Options.hs b/src/IpeDb/Options.hs
new file mode 100644
--- /dev/null
+++ b/src/IpeDb/Options.hs
@@ -0,0 +1,74 @@
+module IpeDb.Options (
+  Options (..),
+  Command (..),
+  IndexOptions (..),
+  QueryOptions (..),
+  parseOptions,
+  options,
+  commands,
+  queryCommand,
+  indexCommand,
+) where
+
+import IpeDb.InfoProv (IpeId (..))
+import Options.Applicative
+
+data Options = Options
+  { databaseFp :: FilePath
+  , command :: Command
+  }
+  deriving (Show, Eq, Ord)
+
+data Command
+  = Index IndexOptions
+  | Query QueryOptions
+  deriving (Show, Eq, Ord)
+
+data IndexOptions = IndexOptions
+  { eventlog :: FilePath
+  }
+  deriving (Show, Eq, Ord)
+
+data QueryOptions = QueryOptions
+  { ipeId :: IpeId
+  }
+  deriving (Show, Eq, Ord)
+
+parseOptions :: IO Options
+parseOptions = execParser opts
+ where
+  opts =
+    info
+      (options <**> helper)
+      ( fullDesc
+          <> progDesc "Index for Info Provenance entries"
+          <> header "ipedb - A database for info provenance entries"
+      )
+
+options :: Parser Options
+options =
+  Options
+    <$> strArgument
+      ( metavar "FILENAME"
+          <> help "Database location"
+      )
+    <*> commands
+
+commands :: Parser Command
+commands =
+  hsubparser
+    ( command "index" (info (Index <$> indexCommand) (progDesc "Add a file to the repository"))
+        <> command "query" (info (Query <$> queryCommand) (progDesc "Add a file to the repository"))
+    )
+
+queryCommand :: Parser QueryOptions
+queryCommand =
+  QueryOptions
+    <$> ( IpeId
+            <$> argument auto (help "Find the info table provenance information for the given key" <> metavar "INT")
+        )
+
+indexCommand :: Parser IndexOptions
+indexCommand =
+  IndexOptions
+    <$> strArgument (help "Eventlog location to index" <> metavar "FILENAME")
diff --git a/src/IpeDb/Query.hs b/src/IpeDb/Query.hs
new file mode 100644
--- /dev/null
+++ b/src/IpeDb/Query.hs
@@ -0,0 +1,40 @@
+module IpeDb.Query (
+  withInfoProvDb,
+  setupInfoProvDb,
+  populateFromEventlog,
+  lookupInfoProv,
+  insertInfoProv,
+  listInfoProvs,
+) where
+
+import qualified IpeDb.Eventlog.Index as Index
+import IpeDb.InfoProv
+import IpeDb.Types
+
+-- ----------------------------------------------------------------------------
+-- High Level API
+-- ----------------------------------------------------------------------------
+
+withInfoProvDb :: FilePath -> (InfoProvDb -> IO a) -> IO a
+withInfoProvDb fp act =
+  Index.withDatabase fp (\conn -> act InfoProvDb{conn})
+
+setupInfoProvDb :: InfoProvDb -> IO ()
+setupInfoProvDb db =
+  Index.setupDb db.conn
+
+populateFromEventlog :: InfoProvDb -> FilePath -> IO ()
+populateFromEventlog db fp =
+  Index.generateInfoProvDb db.conn fp
+
+lookupInfoProv :: InfoProvDb -> IpeId -> IO (Maybe InfoProv)
+lookupInfoProv db ipeId = do
+  Index.findOneInfoProv db.conn ipeId
+
+insertInfoProv :: InfoProvDb -> InfoProv -> IO ()
+insertInfoProv db ipe = do
+  Index.insertInfoProv db.conn ipe
+
+listInfoProvs :: InfoProvDb -> IO [InfoProv]
+listInfoProvs db = do
+  Index.findAllInfoProvs db.conn
diff --git a/src/IpeDb/Table.hs b/src/IpeDb/Table.hs
new file mode 100644
--- /dev/null
+++ b/src/IpeDb/Table.hs
@@ -0,0 +1,121 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+module IpeDb.Table (
+  InfoProvRow (..),
+  dropStringTableStmt,
+  dropInfoProvTableStmt,
+  dropInfoProvTableViewStmt,
+  stringTableStmt,
+  infoProvTableStmt,
+  infoProvTableViewStmt,
+  findInfoTableQuery,
+  findAllInfoTablesQuery,
+  insertInfoTableQuery,
+  insertOrIgnoreString,
+  getStringEntry,
+  getIpeStrings,
+) where
+
+import Data.Int
+import qualified Database.SQLite.Simple as Sqlite
+import IpeDb.InfoProv
+import GHC.Generics (Generic)
+import Data.Text (Text)
+
+data InfoProvRow = InfoProvRow
+  { infoId :: !IpeId
+  , tableName :: !Int64
+  , closureDesc :: !Int64
+  , typeDesc :: !Int64
+  , label :: !Int64
+  , moduleName :: !Int64
+  , srcLoc :: !Int64
+  , srcLocRange :: !Text
+  }
+  deriving (Show, Eq, Ord, Generic)
+  deriving anyclass (Sqlite.FromRow, Sqlite.ToRow)
+
+dropStringTableStmt :: Sqlite.Query
+dropStringTableStmt = "DROP TABLE IF EXISTS strings;"
+
+dropInfoProvTableStmt :: Sqlite.Query
+dropInfoProvTableStmt = "DROP TABLE IF EXISTS info_prov;"
+
+dropInfoProvTableViewStmt :: Sqlite.Query
+dropInfoProvTableViewStmt = "DROP VIEW IF EXISTS view_info_prov;"
+
+stringTableStmt :: Sqlite.Query
+stringTableStmt =
+  "\
+  \ CREATE TABLE strings (                        \
+  \    id INTEGER PRIMARY KEY,                    \
+  \    value TEXT NOT NULL UNIQUE                 \
+  \);"
+
+infoProvTableStmt :: Sqlite.Query
+infoProvTableStmt =
+  "\
+  \ CREATE TABLE info_prov (                                \
+  \    info_id         INTEGER PRIMARY KEY,                    \
+  \    table_name      INTEGER NOT NULL REFERENCES strings(id),\
+  \    closure_desc    INTEGER NOT NULL,                       \
+  \    type_desc       INTEGER NOT NULL REFERENCES strings(id),\
+  \    label           INTEGER NOT NULL REFERENCES strings(id),\
+  \    module_name     INTEGER NOT NULL REFERENCES strings(id),\
+  \    src_loc         INTEGER NOT NULL REFERENCES strings(id),\
+  \    src_loc_range   TEXT NOT NULL                           \
+  \);"
+
+infoProvTableViewStmt :: Sqlite.Query
+infoProvTableViewStmt =
+  "\
+  \ CREATE VIEW view_info_prov AS                                  \
+  \ SELECT                                                         \
+  \   i.info_id,                                                   \
+  \   table_name.value AS table_name,                              \
+  \   i.closure_desc,                                              \
+  \   type_desc.value AS type_desc,                                \
+  \   label.value AS label,                                        \
+  \   module_name.value AS module_name,                            \
+  \   concat(src_loc.value, i.src_loc_range) AS src_loc            \
+  \ FROM info_prov i                                               \
+  \ JOIN strings AS table_name   ON i.table_name = table_name.id   \
+  \ JOIN strings AS type_desc    ON i.type_desc = type_desc.id     \
+  \ JOIN strings AS label        ON i.label = label.id             \
+  \ JOIN strings AS module_name  ON i.module_name = module_name.id \
+  \ JOIN strings AS src_loc      ON i.src_loc = src_loc.id;"
+
+findInfoTableQuery :: Sqlite.Query
+findInfoTableQuery = "SELECT * FROM view_info_prov WHERE info_id = ?;"
+
+findAllInfoTablesQuery :: Sqlite.Query
+findAllInfoTablesQuery = "SELECT * FROM view_info_prov;"
+
+insertInfoTableQuery :: Sqlite.Query
+insertInfoTableQuery =
+  "\
+  \ INSERT INTO info_prov\
+  \   (info_id, table_name, closure_desc, type_desc, label, module_name, src_loc, src_loc_range)\
+  \ VALUES (?, ?, ?, ?, ?, ?, ?, ?);"
+
+insertOrIgnoreString :: Sqlite.Query
+insertOrIgnoreString = "INSERT OR IGNORE INTO strings(value) VALUES (?);"
+
+getIpeStrings :: Sqlite.Query
+getIpeStrings =
+  "\
+  \ SELECT                                             \
+  \   table_name.id AS table_name,                     \
+  \   type_desc.id AS type_desc,                       \
+  \   label.id AS label,                               \
+  \   module_name.id AS module_name,                   \
+  \   src_loc.id AS src_loc                            \
+  \ FROM strings AS table_name    \
+  \ JOIN strings AS type_desc    ON ? = type_desc.value   \
+  \ JOIN strings AS label        ON ? = label.value       \
+  \ JOIN strings AS module_name  ON ? = module_name.value \
+  \ JOIN strings AS src_loc      ON ? = src_loc.value     \
+  \  WHERE ? = table_name.value ;"
+
+getStringEntry :: Sqlite.Query
+getStringEntry = "SELECT id, value FROM strings WHERE value = ?;"
diff --git a/src/IpeDb/Types.hs b/src/IpeDb/Types.hs
new file mode 100644
--- /dev/null
+++ b/src/IpeDb/Types.hs
@@ -0,0 +1,14 @@
+module IpeDb.Types
+  ( InfoProvDb (..),
+  )
+where
+
+import qualified Database.SQLite.Simple as Sqlite
+
+-- ----------------------------------------------------------------------------
+-- Db type
+-- ----------------------------------------------------------------------------
+
+data InfoProvDb = InfoProvDb
+  { conn :: Sqlite.Connection
+  }
diff --git a/test/Main.hs b/test/Main.hs
new file mode 100644
--- /dev/null
+++ b/test/Main.hs
@@ -0,0 +1,82 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+module Main (main) where
+
+import IpeDb.InfoProv
+import IpeDb.Query qualified as Query
+import System.Directory (doesFileExist)
+import System.FilePath
+import System.IO.Temp
+import Test.Tasty
+import Test.Tasty.HUnit
+
+main :: IO ()
+main = defaultMain tests
+
+testdataDir :: FilePath
+testdataDir = "test" </> "data"
+
+tests :: TestTree
+tests =
+  testGroup
+    "ipedb"
+    [ integrationTests
+    ]
+
+integrationTests :: TestTree
+integrationTests =
+  testGroup
+    "integration"
+    [ testGroup
+        "index"
+        [ testCase "ipedb.eventlog" $
+            withSystemTempDirectory "ipedb" $ \tempDir -> do
+              let
+                db_loc = tempDir </> "ipedb.db"
+                eventlog_log = testdataDir </> "ipedb.eventlog"
+
+              exists_start <- doesFileExist db_loc
+              assertBool "Database must not exist before generating it" (not exists_start)
+
+              Query.withInfoProvDb db_loc $ \db ->
+                Query.populateFromEventlog db eventlog_log
+
+              exists <- doesFileExist db_loc
+              assertBool "Database exists after generating it" exists
+        ]
+    , testGroup
+        "query"
+        [ testCase "can insert and find info prov" $
+            withSystemTempDirectory "ipedb" $ \tempDir -> do
+              let
+                db_loc = tempDir </> "ipedb.db"
+
+              Query.withInfoProvDb db_loc $ \db -> do
+                Query.setupInfoProvDb db
+                let
+                  dummyIpe =
+                    InfoProv
+                      { infoId = IpeId 0xdeadb33f
+                      , tableName = "DummyInfo"
+                      , closureDesc = 42
+                      , typeDesc = "Dummy"
+                      , label = "This is a dummy IPE info"
+                      , moduleName = "Dummy"
+                      , srcLoc = "Dummy.hs:45"
+                      }
+                Query.insertInfoProv db dummyIpe
+                ipe <- Query.lookupInfoProv db dummyIpe.infoId
+
+                ipe @?= Just dummyIpe
+        , testCase "list ipedb.eventlog info provs" $
+            withSystemTempDirectory "ipedb" $ \tempDir -> do
+              let
+                db_loc = tempDir </> "ipedb.db"
+                eventlog_log = testdataDir </> "ipedb.eventlog"
+              Query.withInfoProvDb db_loc $ \db -> do
+                Query.populateFromEventlog db eventlog_log
+                info_provs <- Query.listInfoProvs db
+
+                assertBool "There must be at least 500 info provs in the table" (length info_provs > 500)
+        ]
+    ]
diff --git a/test/data/ipedb.eventlog b/test/data/ipedb.eventlog
new file mode 100644
# file too large to diff: test/data/ipedb.eventlog
