metal-orm 1.0.43 β†’ 1.0.44

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. package/README.md +173 -30
  2. package/dist/index.cjs +896 -476
  3. package/dist/index.cjs.map +1 -1
  4. package/dist/index.d.cts +1146 -275
  5. package/dist/index.d.ts +1146 -275
  6. package/dist/index.js +896 -474
  7. package/dist/index.js.map +1 -1
  8. package/package.json +1 -1
  9. package/src/core/ast/adapters.ts +8 -2
  10. package/src/core/ast/builders.ts +105 -81
  11. package/src/core/ast/expression-builders.ts +430 -390
  12. package/src/core/ast/expression-visitor.ts +47 -8
  13. package/src/core/ast/helpers.ts +23 -0
  14. package/src/core/ast/join-node.ts +17 -1
  15. package/src/core/ddl/dialects/base-schema-dialect.ts +7 -1
  16. package/src/core/ddl/dialects/index.ts +1 -0
  17. package/src/core/ddl/dialects/mssql-schema-dialect.ts +1 -0
  18. package/src/core/ddl/dialects/mysql-schema-dialect.ts +1 -0
  19. package/src/core/ddl/dialects/postgres-schema-dialect.ts +1 -0
  20. package/src/core/ddl/dialects/sqlite-schema-dialect.ts +1 -0
  21. package/src/core/ddl/introspect/catalogs/index.ts +1 -0
  22. package/src/core/ddl/introspect/catalogs/postgres.ts +2 -0
  23. package/src/core/ddl/introspect/context.ts +6 -0
  24. package/src/core/ddl/introspect/functions/postgres.ts +13 -0
  25. package/src/core/ddl/introspect/mssql.ts +11 -0
  26. package/src/core/ddl/introspect/mysql.ts +2 -0
  27. package/src/core/ddl/introspect/postgres.ts +14 -0
  28. package/src/core/ddl/introspect/registry.ts +14 -0
  29. package/src/core/ddl/introspect/run-select.ts +13 -0
  30. package/src/core/ddl/introspect/sqlite.ts +22 -0
  31. package/src/core/ddl/introspect/utils.ts +18 -0
  32. package/src/core/ddl/naming-strategy.ts +6 -0
  33. package/src/core/ddl/schema-dialect.ts +19 -6
  34. package/src/core/ddl/schema-diff.ts +22 -0
  35. package/src/core/ddl/schema-generator.ts +22 -0
  36. package/src/core/ddl/schema-plan-executor.ts +6 -0
  37. package/src/core/ddl/schema-types.ts +6 -0
  38. package/src/core/dialect/abstract.ts +2 -2
  39. package/src/core/execution/pooling/pool.ts +12 -7
  40. package/src/core/functions/datetime.ts +57 -33
  41. package/src/core/functions/numeric.ts +95 -30
  42. package/src/core/functions/standard-strategy.ts +35 -0
  43. package/src/core/functions/text.ts +83 -22
  44. package/src/core/functions/types.ts +23 -8
  45. package/src/decorators/bootstrap.ts +16 -4
  46. package/src/decorators/column.ts +17 -0
  47. package/src/decorators/decorator-metadata.ts +27 -0
  48. package/src/decorators/entity.ts +8 -0
  49. package/src/decorators/index.ts +3 -0
  50. package/src/decorators/relations.ts +32 -0
  51. package/src/orm/als.ts +34 -9
  52. package/src/orm/entity-context.ts +54 -0
  53. package/src/orm/entity-metadata.ts +122 -9
  54. package/src/orm/execute.ts +15 -0
  55. package/src/orm/lazy-batch.ts +68 -98
  56. package/src/orm/relations/has-many.ts +44 -0
  57. package/src/query/index.ts +74 -0
  58. package/src/query/target.ts +46 -0
  59. package/src/query-builder/delete-query-state.ts +30 -0
  60. package/src/query-builder/delete.ts +64 -19
  61. package/src/query-builder/hydration-manager.ts +46 -0
  62. package/src/query-builder/insert-query-state.ts +30 -0
  63. package/src/query-builder/insert.ts +46 -2
  64. package/src/query-builder/query-ast-service.ts +5 -0
  65. package/src/query-builder/query-resolution.ts +78 -0
  66. package/src/query-builder/raw-column-parser.ts +5 -0
  67. package/src/query-builder/relation-alias.ts +7 -0
  68. package/src/query-builder/relation-conditions.ts +61 -48
  69. package/src/query-builder/relation-service.ts +68 -63
  70. package/src/query-builder/relation-utils.ts +3 -0
  71. package/src/query-builder/select/cte-facet.ts +40 -0
  72. package/src/query-builder/select/from-facet.ts +80 -0
  73. package/src/query-builder/select/join-facet.ts +62 -0
  74. package/src/query-builder/select/predicate-facet.ts +103 -0
  75. package/src/query-builder/select/projection-facet.ts +69 -0
  76. package/src/query-builder/select/relation-facet.ts +81 -0
  77. package/src/query-builder/select/setop-facet.ts +36 -0
  78. package/src/query-builder/select-helpers.ts +13 -0
  79. package/src/query-builder/select-query-builder-deps.ts +19 -1
  80. package/src/query-builder/select-query-state.ts +2 -1
  81. package/src/query-builder/select.ts +795 -1163
  82. package/src/query-builder/update-query-state.ts +52 -0
  83. package/src/query-builder/update.ts +69 -19
  84. package/src/schema/table-guards.ts +31 -0
package/README.md CHANGED
@@ -1,19 +1,53 @@
1
- # MetalORM βš™οΈ - Type-safe SQL, layered ORM, decorator-based entities – all on the same core.
1
+ # MetalORM βš™οΈ
2
2
 
3
3
  [![npm version](https://img.shields.io/npm/v/metal-orm.svg)](https://www.npmjs.com/package/metal-orm)
4
4
  [![license](https://img.shields.io/npm/l/metal-orm.svg)](https://github.com/celsowm/metal-orm/blob/main/LICENSE)
5
5
  [![TypeScript](https://img.shields.io/badge/%3C%2F%3E-TypeScript-%23007ACC.svg)](https://www.typescriptlang.org/)
6
6
 
7
- MetalORM is a TypeScript-first, AST-driven SQL toolkit you can dial up or down depending on how β€œORM-y” you want to be:
7
+ > **TypeScript-first ORM that adapts to your needs**: use it as a type-safe query builder, a full-featured ORM runtime, or anything in between.
8
8
 
9
- - **Level 1 – Query builder & hydration 🧩**
9
+ ## Why MetalORM? πŸ’‘
10
+
11
+ - 🎯 **Gradual adoption**: Start with just SQL building, add ORM features when you need them
12
+ - πŸ”’ **Exceptionally strongly typed**: Built with TypeScript generics and type inferenceβ€”**zero** `any` types in the entire codebase
13
+ - πŸ—οΈ **Well-architected**: Implements proven design patterns (Strategy, Visitor, Builder, Unit of Work, Identity Map, Interceptor, and more)
14
+ - 🎨 **One AST, multiple levels**: All features share the same SQL AST foundationβ€”no magic, just composable layers
15
+ - πŸš€ **Multi-dialect from the start**: MySQL, PostgreSQL, SQLite, SQL Server support built-in
16
+
17
+ ---
18
+
19
+ ## ⚑ 30-Second Quick Start
20
+
21
+ ```ts
22
+ import { defineTable, col, selectFrom, MySqlDialect } from 'metal-orm';
23
+
24
+ const users = defineTable('users', {
25
+ id: col.primaryKey(col.int()),
26
+ name: col.varchar(255),
27
+ });
28
+
29
+ const query = selectFrom(users).select('id', 'name').limit(10);
30
+ const { sql, params } = query.compile(new MySqlDialect());
31
+ // That's it! Use sql + params with any driver.
32
+ // ↑ Fully typedβ€”no casting, no 'any', just strong types all the way down
33
+ ```
34
+
35
+ ---
36
+
37
+ ## Three Levels of Abstraction
38
+
39
+ MetalORM is a TypeScript-first, AST-driven SQL toolkit you can dial up or down depending on how "ORM-y" you want to be:
40
+
41
+ - **Level 1 – Query builder & hydration 🧩**
10
42
  Define tables with `defineTable` / `col.*`, build strongly-typed queries on a real SQL AST, and hydrate flat result sets into nested objects – no ORM runtime involved.
11
- - **Level 2 – ORM runtime (entities + Unit of Work 🧠)**
43
+
44
+ - **Level 2 – ORM runtime (entities + Unit of Work 🧠)**
12
45
  Let `OrmSession` (created from `Orm`) turn rows into tracked entities with lazy relations, cascades, and a [Unit of Work](https://en.wikipedia.org/wiki/Unit_of_work) that flushes changes with `session.commit()`.
13
- - **Level 3 – Decorator entities (classes + metadata ✨)**
46
+
47
+ - **Level 3 – Decorator entities (classes + metadata ✨)**
14
48
  Use `@Entity`, `@Column`, `@PrimaryKey`, relation decorators, `bootstrapEntities()` (or the lazy bootstrapping in `getTableDefFromEntity` / `selectFromEntity`) to describe your model classes. MetalORM bootstraps schema & relations from metadata and plugs them into the same runtime and query builder.
15
49
 
16
- Use only the layer you need in each part of your codebase.
50
+ **Use only the layer you need in each part of your codebase.**
17
51
 
18
52
  ---
19
53
 
@@ -28,7 +62,10 @@ Use only the layer you need in each part of your codebase.
28
62
  - [Level 2 – Entities + Unit of Work](#level-2)
29
63
  - [Level 3 – Decorator entities](#level-3)
30
64
  - [When to use which level?](#when-to-use-which-level)
31
- - [Design notes](#design-notes)
65
+ - [Design & Architecture](#design-notes)
66
+ - [FAQ](#frequently-asked-questions-)
67
+ - [Performance & Production](#performance--production-)
68
+ - [Community & Support](#community--support-)
32
69
  - [Contributing](#contributing)
33
70
  - [License](#license)
34
71
 
@@ -173,7 +210,7 @@ import {
173
210
  defineTable,
174
211
  tableRef,
175
212
  col,
176
- SelectQueryBuilder,
213
+ selectFrom,
177
214
  eq,
178
215
  MySqlDialect,
179
216
  } from 'metal-orm';
@@ -192,8 +229,8 @@ todos.columns.done.default = false;
192
229
  const t = tableRef(todos);
193
230
 
194
231
  // 2) Build a simple query
195
- const listOpenTodos = new SelectQueryBuilder(todos)
196
- .selectColumns('id', 'title', 'done')
232
+ const listOpenTodos = selectFrom(todos)
233
+ .select('id', 'title', 'done')
197
234
  .where(eq(t.done, false))
198
235
  .orderBy(t.id, 'ASC');
199
236
 
@@ -221,8 +258,8 @@ That’s it: schema, query, SQL, done.
221
258
  ```ts
222
259
  const t = tableRef(todos);
223
260
 
224
- const listOpenTodos = new SelectQueryBuilder(todos)
225
- .selectColumns('id', 'title', 'done') // typed shorthand for the same fields
261
+ const listOpenTodos = selectFrom(todos)
262
+ .select('id', 'title', 'done') // typed shorthand for the same fields
226
263
  .where(eq(t.done, false))
227
264
  .orderBy(t.id, 'ASC');
228
265
  ```
@@ -234,19 +271,19 @@ const listOpenTodos = new SelectQueryBuilder(todos)
234
271
  If you still want the convenience of accessing columns without spelling `.columns`, you can opt-in with `tableRef()`:
235
272
 
236
273
  ```ts
237
- import { tableRef, eq } from 'metal-orm';
274
+ import { tableRef, eq, selectFrom } from 'metal-orm';
238
275
 
239
276
  // Existing style (always works)
240
- const listOpenTodos = new SelectQueryBuilder(todos)
241
- .selectColumns('id', 'title', 'done')
277
+ const listOpenTodos = selectFrom(todos)
278
+ .select('id', 'title', 'done')
242
279
  .where(eq(todos.columns.done, false))
243
280
  .orderBy(todos.columns.id, 'ASC');
244
281
 
245
282
  // Opt-in ergonomic style
246
283
  const t = tableRef(todos);
247
284
 
248
- const listOpenTodos2 = new SelectQueryBuilder(todos)
249
- .selectColumns('id', 'title', 'done')
285
+ const listOpenTodos2 = selectFrom(todos)
286
+ .select('id', 'title', 'done')
250
287
  .where(eq(t.done, false))
251
288
  .orderBy(t.id, 'ASC');
252
289
  ```
@@ -265,7 +302,7 @@ import {
265
302
  defineTable,
266
303
  col,
267
304
  hasMany,
268
- SelectQueryBuilder,
305
+ selectFrom,
269
306
  eq,
270
307
  count,
271
308
  rowNumber,
@@ -302,7 +339,7 @@ users.columns.email.unique = true;
302
339
  const u = sel(users, 'id', 'name', 'email');
303
340
  const p = sel(posts, 'id', 'userId');
304
341
 
305
- const builder = new SelectQueryBuilder(users)
342
+ const builder = selectFrom(users)
306
343
  .select({
307
344
  ...u,
308
345
  postCount: count(p.id),
@@ -358,7 +395,7 @@ import {
358
395
  Orm,
359
396
  OrmSession,
360
397
  MySqlDialect,
361
- SelectQueryBuilder,
398
+ selectFrom,
362
399
  eq,
363
400
  tableRef,
364
401
  createMysqlExecutor,
@@ -381,8 +418,8 @@ const session = new OrmSession({ orm, executor });
381
418
  const u = tableRef(users);
382
419
 
383
420
  // 2) Load entities with lazy relations
384
- const [user] = await new SelectQueryBuilder(users)
385
- .selectColumns('id', 'name', 'email')
421
+ const [user] = await selectFrom(users)
422
+ .select('id', 'name', 'email')
386
423
  .includeLazy('posts') // HasMany as a lazy collection
387
424
  .includeLazy('roles') // BelongsToMany as a lazy collection
388
425
  .where(eq(u.id, 1))
@@ -528,17 +565,123 @@ All three levels share the same schema, AST, and dialects, so you can mix them a
528
565
  ---
529
566
 
530
567
  <a id="design-notes"></a>
531
- ## Design notes 🧱
568
+ ## Design & Architecture πŸ—οΈ
569
+
570
+ MetalORM is built on solid software engineering principles and proven design patterns.
571
+
572
+ ### Architecture Layers
573
+
574
+ ```
575
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
576
+ β”‚ Your Application β”‚
577
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
578
+ β”‚
579
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
580
+ β”‚ β”‚ β”‚
581
+ β–Ό β–Ό β–Ό
582
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
583
+ β”‚ Level 1 β”‚ β”‚ Level 2 β”‚ β”‚ Level 3 β”‚
584
+ β”‚ Query │◄────── ORM │◄──────Decoratorsβ”‚
585
+ β”‚ Builder β”‚ β”‚ Runtime β”‚ β”‚ β”‚
586
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
587
+ β”‚ β”‚ β”‚
588
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
589
+ β–Ό
590
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
591
+ β”‚ SQL AST β”‚
592
+ β”‚ (Typed Nodes) β”‚
593
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
594
+ β–Ό
595
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
596
+ β”‚ Strategy Pattern: Dialects β”‚
597
+ β”‚ MySQL | PostgreSQL | SQLite | SQL Server β”‚
598
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
599
+ β–Ό
600
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
601
+ β”‚ Database β”‚
602
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
603
+ ```
532
604
 
533
- Under the hood, MetalORM leans on well-known patterns:
605
+ ### Design Patterns
606
+
607
+ - **Strategy Pattern**: Pluggable dialects (MySQL, PostgreSQL, SQLite, SQL Server) and function renderers allow the same query to target different databases
608
+ - **Visitor Pattern**: AST traversal for SQL compilation and expression processing
609
+ - **Builder Pattern**: Fluent query builders (Select, Insert, Update, Delete) for constructing queries step-by-step
610
+ - **Factory Pattern**: Dialect factory and executor creation abstract instantiation logic
611
+ - **Unit of Work**: Change tracking and batch persistence in `OrmSession` coordinate all modifications
612
+ - **Identity Map**: One entity instance per row within a session prevents duplicate object issues
613
+ - **Interceptor/Pipeline**: Query interceptors and flush lifecycle hooks enable cross-cutting concerns
614
+ - **Adapter Pattern**: Connection pooling adapters allow different pool implementations
615
+
616
+ ### Type Safety
617
+
618
+ - **Zero `any` types**: The entire src codebase contains zero `any` typesβ€”every value is properly typed
619
+ - **100% typed public API**: Every public method, parameter, and return value is fully typed
620
+ - **Full type inference**: From schema definition through query building to result hydration
621
+ - **Compile-time safety**: Catch SQL errors at TypeScript compile time, not runtime
622
+ - **Generic-driven**: Leverages TypeScript generics extensively for type propagation
623
+
624
+ ### Separation of Concerns
625
+
626
+ Each layer has a clear, focused responsibility:
627
+
628
+ - **Core AST layer**: SQL representation independent of any specific dialect
629
+ - **Dialect layer**: Vendor-specific SQL compilation (MySQL, PostgreSQL, etc.)
630
+ - **Schema layer**: Table and column definitions with relations
631
+ - **Query builder layer**: Fluent API for building type-safe queries
632
+ - **Hydration layer**: Transforms flat result sets into nested object graphs
633
+ - **ORM runtime layer**: Entity management, change tracking, lazy relations, transactions
634
+
635
+ You can use just the layers you need and stay at the low level (AST + dialects) or adopt higher levels when beneficial.
636
+
637
+ ---
638
+
639
+ ## Frequently Asked Questions ❓
640
+
641
+ **Q: How does MetalORM differ from other ORMs?**
642
+ A: MetalORM's unique three-level architecture lets you choose your abstraction levelβ€”use just the query builder, add the ORM runtime when needed, or go full decorator-based entities. This gradual adoption path is uncommon in the TypeScript ecosystem. You're not locked into an all-or-nothing ORM approach.
643
+
644
+ **Q: Can I use this in production?**
645
+ A: Yes! MetalORM is designed for production use with robust patterns like Unit of Work, Identity Map, and connection pooling support. The type-safe query builder ensures SQL correctness at compile time.
646
+
647
+ **Q: Do I need to use all three levels?**
648
+ A: No! Use only what you need. Many projects stay at Level 1 (query builder) for its type-safe SQL building without any ORM overhead. Add runtime features (Level 2) or decorators (Level 3) only where they provide value.
649
+
650
+ **Q: What about migrations?**
651
+ A: MetalORM provides schema generation via DDL builders. See the [Schema Generation docs](./docs/schema-generation.md) for details on generating CREATE TABLE statements from your table definitions.
652
+
653
+ **Q: How type-safe is it really?**
654
+ A: Exceptionally. The entire codebase contains **zero** `any` typesβ€”every value is properly typed with TypeScript generics and inference. All public APIs are fully typed, and your queries, entities, and results get full TypeScript checking at compile time.
655
+
656
+ **Q: What design patterns are used?**
657
+ A: MetalORM implements several well-known patterns: Strategy (dialects & functions), Visitor (AST traversal), Builder (query construction), Factory (dialect & executor creation), Unit of Work (change tracking), Identity Map (entity caching), Interceptor (query hooks), and Adapter (pooling). This makes the codebase maintainable and extensible.
658
+
659
+ ---
660
+
661
+ ## Performance & Production πŸš€
662
+
663
+ - **Zero runtime overhead for Level 1** (query builder) - it's just SQL compilation and hydration
664
+ - **Efficient batching** for Level 2 lazy relations minimizes database round-trips
665
+ - **Identity Map** prevents duplicate entity instances and unnecessary queries
666
+ - **Connection pooling** supported via executor factory pattern (see [pooling docs](./docs/pooling.md))
667
+ - **Prepared statements** with parameterized queries protect against SQL injection
668
+
669
+ **Production checklist:**
670
+ - βœ… Use connection pooling for better resource management
671
+ - βœ… Enable query logging in development for debugging
672
+ - βœ… Set up proper error handling and retries
673
+ - βœ… Use transactions for multi-statement operations
674
+ - βœ… Monitor query performance with interceptors
675
+
676
+ ---
534
677
 
535
- - **AST + dialect abstraction**: SQL is modeled as typed AST nodes, compiled by dialects that you can extend.
536
- - **Separation of concerns**: schema, AST, SQL compilation, execution, and ORM runtime are separate layers.
537
- - **Executor abstraction**: built-in executor creators (`createMysqlExecutor`, `createPostgresExecutor`, etc.) provide a clean separation between database drivers and ORM operations.
538
- - **Unit of Work + Identity Map**: `OrmSession` coordinates changes and enforces one entity instance per row, following the [Unit of Work](https://en.wikipedia.org/wiki/Unit_of_work) and [Identity map](https://en.wikipedia.org/wiki/Identity_map_pattern) patterns.
539
- - **Domain events + interceptors**: decouple side-effects from persistence and let cross-cutting concerns hook into flush points, similar in spirit to domain events in [Domain-driven design](https://en.wikipedia.org/wiki/Domain-driven_design).
678
+ ## Community & Support πŸ’¬
540
679
 
541
- You can stay at the low level (just AST + dialects) or adopt the higher levels when it makes your code simpler.
680
+ - πŸ› **Issues:** [GitHub Issues](https://github.com/celsowm/metal-orm/issues)
681
+ - πŸ’‘ **Discussions:** [GitHub Discussions](https://github.com/celsowm/metal-orm/discussions)
682
+ - πŸ“– **Documentation:** [Full docs](./docs/index.md)
683
+ - πŸ—ΊοΈ **Roadmap:** [See what's planned](./ROADMAP.md)
684
+ - πŸ“¦ **Changelog:** [View releases](https://github.com/celsowm/metal-orm/releases)
542
685
 
543
686
  ---
544
687