diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..ca43b724 --- /dev/null +++ b/LICENSE @@ -0,0 +1,9 @@ +MIT License + +Copyright (c) 2014 Sebastian Sastre + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md index d3059365..cddb35ee 100644 --- a/README.md +++ b/README.md @@ -1,177 +1,88 @@ -Mapless -======= +# Mapless -*Obscenely simple persistence for Smalltalk.* Mapless is a small framework for storing objects in a key->value fashion (i.e.: noSQL databases) without requiring any kind of mapping definitions. +Schema-less persistence for Smalltalk with support for multiple backends. -Currently supported backends are `MongoDB` and `Redis`. +
-**Current best version tagged as:** v0.5.1-alpha +___ -## Loading +## Features +- 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 chose from. +- Enables smooth data migration/interoperation among backends. +- Via Redis PUB/SUB, scalable observer-pattern functionality across images. -By default `Mapless` will load `Memory`, `Mongo` and `Redis` backends: +## Ambition - Metacello new - baseline: 'Mapless'; - repository: 'github://sebastianconcept/Mapless:master/src'; - load. - -## Design philosophy -Without loosing pragmatism, here is a notion used as source of inspiration for Mapless' design: - - *There are no instVars...* - *There are no accessors...* - *There is no object-mapping impedance...* - - *Only persistence.* - -### Applicability - -Mapless can be used for Model persistence, object oriented shared cache, observer pattern across images and network JSON communication. - -### Motivation -> "I wanted to persist objects with *low friction* and *low maintenance* but *high scaling* and *availability* capabilities so Mapless is totally biased towards that. This framework is what I came up with after incorporating my experience with [Aggregate](https://github.com/sebastianconcept/Aggregate) in [airflowing](http://airflowing.com)." ~ [Sebastian Sastre](http://sebastiansastre.co) - - - -### How does it look? - -You can store and retrieve your Mapless models on MongoDB like a breeze. -#### Getting the connection - - odb := MongoPool instance databaseAt: 'YourMongoDatabase'. - -#### Create a new model - -Just subclass MaplessModel with your app "business objects". Here we use a Task model: - - task := Task new description: 'Try Mapless'; beIncomplete. - -#### Save it - -In Mapless you do things sending a #do: with a closure which Mapless uses to automatically discern which MongoDB database and collection has to be used. It also will know if it needs to do an insert or an update. As a bonus, you get the collection *and* the database created lazily. - -Want to save something? Zero bureaucracy, just tell that to the model: - odb do:[ task save ]. - -The spirit of the project is to preserve developer *low-friction* when using persistence. -#### Fetching data - -Getting all models of a given class: - odb do:[ Task findAll ]. - -Getting a specific model: - odb do: [ Task findId: 'c472099f-79b9-8ea2-d61f-e5df34b3ed06' ]. +Mapless gives you performant state plasticity and high availability in a scale that goes beyond one Smalltalk image and without backend vendor locking nor object-mapping impedance mismatch. -For getting efficiently a (sub)group of models, you write your own Mapless class side getters. They should act on the MongoDB indices with the parameters of your query. You'll get your models in a breeze: +## Supported backends +1. MongoDB +2. Redis +3. Memory +4. PostgreSQL +5. UnQLite - odb do:[ Task findAtUsername: 'awesomeguy' ]. +## Examples -#### Adding something to a model -You can use Mapless models pretending they are [prototypical](http://en.wikipedia.org/wiki/Prototype-based_programming) like in [Self](http://en.wikipedia.org/wiki/Self_(programming_language)) or [Javascript](http://en.wikipedia.org/wiki/JavaScript) objects. No instVars. No setters. No getters. All just works: +```Smalltalk +"Instanciates a mapless object." +genius := DummyPerson new + firstName: 'Aristotle'; + yourself. - odb do: [ - task - deadline: Date tomorrow; - notes: 'Wonder how it feels to use this thing, hmm...'; - save ]. +"Saves it." +repository save: genius. +``` -#### Need composition? +```Smalltalk +"Loads one by known ID." +identified := repository findOne: DummyPerson atId: genius id. +``` -Of course you do! The only thing you need is to save the children first - odb do: [ | anAlert | - anAlert := Alert new - duration: 24 hours; - message: 'You will miss the target!'; - save. - task - alert: anAlert; - save ] +```Smalltalk +"Loads all instances of that class that were stored in that database." +allOrEmpty := repository findAll: DummyPerson. +``` -This is what I like to call *low-maintenance*. -#### Navigating the object graph +```Smalltalk +"Query to load all the instances that match the condition." +someOrEmpty := repository findAll: DummyPerson where: [ :each | each lastName = 'Peterson' ]. +``` -Mapless embraces an aggressive *lazy approach*. When you query for models you get them. But if they are composed by other (sub)Mapless, they are going to be references and *only* reify into the proper Mapless model *if* you send them a message and you can do this with arbitrary depth: +```Smalltalk +"Conditionally loading the first matching instance." +oneOrNil := repository findOne: DummyPerson where: [ :each | each lastName = 'Peterson' ]. +``` - odb do: [ task alert message ]. +## Installation - odb do: [ task alert class = MaplessReference ]. "<- true" +Open a Pharo workspace and evaluate: - odb do: [ task alert description ]. "<- 'You will miss the target!'" - -#### Persisting different models - -Say for your app you now need to store different kind of models, say `List` or `User` or anything else, how you typically proceed? - -This is what happens to you with Mapless: - -1. Create a subclass for them. -2.UserModel ensureIndex: '{ key1: 1, key2: -1 }'
-
-### *Pharo Smalltalk
-Getting a fresh Pharo Smalltalk image and its virtual machine is as easy as running in your terminal:
-
- wget -O- https://get.pharo.org | bash
-
-_______
-
-MIT License
-
-Copyright (c) 2014 [Sebastian Sastre](http://sebastiansastre.co)
+ Metacello new
+ baseline: 'Mapless';
+ repository: 'github://sebastianconcept/Mapless:v0.5.0-alpha/src';
+ load
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
+## Include as dependency
+In BaselineOf or ConfigurationOf it can be added in this way:
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
+ spec
+ baseline: 'Mapless'
+ with: [ spec
+ repository: 'github://sebastianconcept/Mapless:v0.5.0-alpha/src';
+ loads: #('Core' 'Mongo' 'Memory' 'Redis' 'UnQLite') ]
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
diff --git a/changelog.md b/changelog.md
index b4d5c473..b5078dfe 100644
--- a/changelog.md
+++ b/changelog.md
@@ -1,6 +1,7 @@
April 6, 2022
===================================
-* Removed the docker directory with a replica set docker-compose.yml. This is better done when using your own or https://github.com/sebastianconcept/mongo-rs
+* Removed the docker directory with a replica set docker-compose.yml. This is better done when using your own or https://github.com/sebastianconcept/mongo-rs.
+* Starting to improve README based on https://github.com/sebastianconcept/Mapless/issues/87.
April 3, 2022
===================================