+86
README.md
+86
README.md
···
1
+
# repodb
2
+
3
+
An Ecto-inspired database toolkit for OCaml.
4
+
5
+
repodb brings the elegance of Elixir's Ecto to OCaml: type-safe queries, composable changesets, and clean separation between your domain and the database.
6
+
7
+
## Features
8
+
9
+
- **Schemas** - Define your data structures with typed fields
10
+
- **Changesets** - Validate and track changes before persisting
11
+
- **Query DSL** - Build type-safe queries with a composable API
12
+
- **Repo** - Clean abstraction over database operations
13
+
- **Associations** - Define relationships (has_many, belongs_to, many_to_many)
14
+
- **Preloading** - Efficiently load associations, avoiding N+1 queries
15
+
- **Multi** - Compose multiple operations in a single transaction
16
+
- **Migrations** - Version your database schema
17
+
18
+
## Quick Example
19
+
20
+
```ocaml
21
+
(* Define a schema *)
22
+
let users_table = Schema.table "users"
23
+
24
+
type user = { id : int; name : string; email : string; age : int }
25
+
26
+
let name_field =
27
+
Field.make ~table_name:"users" ~name:"name" ~ty:Types.string
28
+
~get:(fun u -> u.name) ~set:(fun v u -> { u with name = v }) ()
29
+
30
+
(* Create and validate a changeset *)
31
+
let empty_user = { id = 0; name = ""; email = ""; age = 0 }
32
+
33
+
let changeset =
34
+
Changeset.create empty_user
35
+
|> Changeset.cast [("name", "Alice"); ("email", "alice@example.com")]
36
+
~fields:[name_field; email_field]
37
+
|> Changeset.validate_required [name_field; email_field]
38
+
|> Changeset.validate_format email_field ~pattern:"^[^@]+@[^@]+$"
39
+
40
+
(* Build and execute queries *)
41
+
let query =
42
+
Query.(from users_table
43
+
|> where Expr.(raw "age" > int 18)
44
+
|> order_by ~direction:Desc (Expr.raw "created_at")
45
+
|> limit 10)
46
+
47
+
let users = Repo.all_query conn query ~decode:decode_user
48
+
```
49
+
50
+
## Documentation
51
+
52
+
- [Getting Started](docs/getting-started.md) - Installation and basic setup
53
+
- [Schemas](docs/schemas.md) - Defining tables and columns
54
+
- [Changesets](docs/changesets.md) - Data validation and change tracking
55
+
- [Queries](docs/queries.md) - Building and executing queries
56
+
- [Repo](docs/repo.md) - Database operations
57
+
- [Associations](docs/associations.md) - Relationships and preloading
58
+
- [Transactions](docs/transactions.md) - Multi and transaction handling
59
+
- [Migrations](docs/migrations.md) - Database schema versioning
60
+
61
+
## Packages
62
+
63
+
| Package | Description |
64
+
|---------|-------------|
65
+
| `repodb` | Core library with schemas, changesets, queries |
66
+
| `repodb-sqlite` | SQLite driver |
67
+
| `repodb-postgresql` | PostgreSQL driver |
68
+
69
+
## Installation
70
+
71
+
```bash
72
+
opam install repodb repodb-sqlite # or repodb-postgresql
73
+
```
74
+
75
+
## Philosophy
76
+
77
+
repodb follows Ecto's philosophy:
78
+
79
+
1. **Explicit over implicit** - No magic, every operation is visible
80
+
2. **Composable** - Small functions that combine well
81
+
3. **Separation of concerns** - Domain logic separate from persistence
82
+
4. **Fail fast** - Validate early with changesets
83
+
84
+
## License
85
+
86
+
ISC License
-5
bin/dune
-5
bin/dune
-1
bin/main.ml
-1
bin/main.ml
···
1
-
let () = print_endline "repodb - Ecto-like database toolkit for OCaml"
+1
-1
docs/repo.md
+1
-1
docs/repo.md
···
394
394
| Error (Error.Query_failed msg) -> Printf.printf "Query error: %s\n" msg
395
395
| Error (Error.Constraint_violation { constraint_name; message }) ->
396
396
Printf.printf "Constraint %s violated: %s\n" constraint_name message
397
-
| Error e -> Printf.printf "Error: %s\n" (Error.to_string e)
397
+
| Error e -> Printf.printf "Error: %s\n" (Error.show_db_error e)
398
398
```
399
399
400
400
## Next Steps
+2
-2
docs/transactions.md
+2
-2
docs/transactions.md
···
80
80
let user : user = Multi.get_exn results "user" in
81
81
Printf.printf "Created user with ID: %d\n" user.id
82
82
| Error { failed_operation; error; _ } ->
83
-
Printf.printf "Failed at %s: %s\n" failed_operation (Error.to_string error)
83
+
Printf.printf "Failed at %s: %s\n" failed_operation (Error.show_db_error error)
84
84
```
85
85
86
86
### Dependent Operations
···
245
245
246
246
| Error { failed_operation; error; completed } ->
247
247
Printf.printf "Failed at operation: %s\n" failed_operation;
248
-
Printf.printf "Error: %s\n" (Error.to_string error);
248
+
Printf.printf "Error: %s\n" (Error.show_db_error error);
249
249
(* completed contains results from operations that succeeded before failure *)
250
250
let partial_user : user option = Multi.get completed "user" in
251
251
...
+1
-1
dune-project
+1
-1
dune-project
+1
repodb-postgresql.opam
+1
repodb-postgresql.opam
+1
repodb-sqlite.opam
+1
repodb-sqlite.opam
+1
repodb.opam
+1
repodb.opam
···
1
1
# This file is generated by dune, edit dune-project instead
2
2
opam-version: "2.0"
3
+
version: "0.1.0"
3
4
synopsis: "Ecto-like database toolkit for OCaml"
4
5
description:
5
6
"repodb is a database toolkit inspired by Elixir's Ecto. It provides type-safe query building, schema definitions, changesets for data validation, and database migrations."