Schema-less persistence for Smalltalk with support for multiple backends.
Mapless is a schema-less persistence framework supporting multiple backends and offering a user-friendly API. Querying Mapless objects involves a common family of methods, and there's no need to declare accessors and mutators. See examples below.
Designed to eliminate the need for schema maintenance, Mapless avoids any Object-Relational Mapping requirements.
Mapless achieves a balance between maximum data survivability and robust architectural flexibility without imposing a heavy burden in terms of adoption and maintenance. A sweet spot for development and production.
- Intuitive API for frictionless persistence.
- No need to create and maintain schemas.
- Composable.
- JSON friendly.
- No need to create accessors and mutators.
- Multiple backends to choose from.
- Enables smooth data migration/interoperation among backends.
- Scalable observer-pattern functionality across images (requires Redis).
- SQLite
- PostgreSQL
- Redis
- MongoDB
- Memory
- UnQLite (frozen support)
Try Mapless by installing it in a supported Pharo image and the following snippets:
"Instantiates an SQLite Mapless repository."
repository := MaplessSQLiteRepository
for: 'TryMapless'
on: 'path/string/to/your/sqlite.db'.
"Custom class to model your data"
Mapless subclass: #Person
instanceVariableNames: ''
classVariableNames: ''
package: 'YourApp-Mapless'
"Guarantees the database has a Person table (this is idempotent)."
repository ensureTableFor: Person.
"Instantiates a Mapless object."
philosopher := Person new
firstName: 'Aristotle';
yourself.
"Saves it."
repository save: philosopher.
"Loads one by known ID."
identified := repository findOne: Person atId: philosopher id.
"Loads all instances of that class that were stored in that database."
allOrEmpty := repository findAll: Person.
"Query to load all the instances that match the condition."
someOrEmpty := repository findAll: Person where: [ :each |
each firstName = 'Aristotle' ].
"Conditionally loading the first matching instance."
oneOrNil := repository findOne: Person where: [ :each |
each firstName = 'Aristotle' ].
"Create a Person Mapless model"
philosopher := Person new
firstName: 'Aristotle';
save.
"Set it as the person for a new User Mapless model"
philosopherUser := User new
person: philosopher;
save.
"Query for that user by ID and get its person instance"
aristotle := (User findId: philosopherUser id) person.
To start with Mapless, download Pharo, open a Pharo Playground and evaluate:
"Load latest version of Mapless with its default backends (Memory and SQLite)"
Metacello new
baseline: 'Mapless';
repository: 'github://sebastianconcept/Mapless:latest/src';
load.
"Load latest version of Mapless specifying which backends explicitely"
Metacello new
baseline: 'Mapless';
repository: 'github://sebastianconcept/Mapless:latest/src';
load: #('Core' 'SQLite' 'Postgres' 'Mongo' 'Redis' 'Memory')
To include Mapless as a dependency from BaselineOf
or ConfigurationOf
add it with:
spec
baseline: 'Mapless'
with: [ spec
repository: 'github://sebastianconcept/Mapless:latest/src';
load: #('Core' 'SQLite' 'Postgres' 'Mongo' 'Redis' 'Memory') ]
To deliver a high-performance solution that preserves arbitrary application state (data) with a focus on flexibility, availability, and capacity. It aims to strategically aid in scaling without causing vendor lock-in, across various persistence backends, and by neutralizing the costs associated with object-mapping impedance mismatch.