Merge: doc: fixed some typos and other misc. corrections
[nit.git] / lib / popcorn / pop_repos.nit
index 559fbd9..c054d5a 100644 (file)
 # Repositories can be used in Popcorn app to manage your data persistence.
 # Here an example with a book management app:
 #
-# ~~~
+# ~~~nitish
 # # First we declare the `Book` class. It has to be serializable so it can be used
 # # within a `Repository`.
 #
 # import popcorn
 # import popcorn::pop_repos
+# import popcorn::pop_json
 #
 # # Serializable book representation.
 # class Book
 #      serialize
-#      super Jsonable
 #
 #      # Book uniq ID
 #      var id: String = (new MongoObjectId).id is serialize_as "_id"
@@ -54,7 +54,6 @@
 #      redef fun to_s do return title
 #      redef fun ==(o) do return o isa SELF and id == o.id
 #      redef fun hash do return id.hash
-#      redef fun to_json do return serialize_to_json
 # end
 #
 # # We then need to subclass the `MongoRepository` to provide Book specific services.
 # # Let's wrap it all together in a Popcorn app:
 #
 # # Init database
-# var mongo = new MongoClient("mongodb://localhost:27017/")
+# var mongo = new MongoClient("mongodb://mongo:27017/")
 # var db = mongo.database("tests_app_{100000.rand}")
 # var coll = db.collection("books")
 #
 # ~~~
 module pop_repos
 
+import popcorn::pop_config
 import serialization
-import json::serialization
+import json
 import mongodb::queries
 
+redef class AppConfig
+
+       # Default database host string for MongoDb
+       var default_db_host = "mongodb://mongo:27017/"
+
+       # Default database hostname
+       var default_db_name = "popcorn"
+
+       # MongoDb host name
+       var opt_db_host = new OptionString("MongoDb host", "--db-host")
+
+       # MongoDb database name
+       var opt_db_name = new OptionString("MongoDb database name", "--db-name")
+
+       # MongoDB server used for data persistence
+       fun db_host: String do return opt_db_host.value or else ini["db.host"] or else default_db_host
+
+       # MongoDB DB used for data persistence
+       fun db_name: String do return opt_db_name.value or else ini["db.name"] or else default_db_name
+
+       init do
+               super
+               add_option(opt_db_host, opt_db_name)
+       end
+
+       # Mongo db client
+       var client = new MongoClient(db_host) is lazy
+
+       # Mongo db instance
+       var db: MongoDb = client.database(db_name) is lazy
+end
+
 # A Repository is an object that can store serialized instances.
 #
 # Repository is the base class of all kind of persistance processes. It offers
@@ -163,6 +195,9 @@ interface Repository[E: Serializable]
        # Remove the instance based on `query`
        fun remove(query: nullable QUERY): Bool is abstract
 
+       # Remove all the instances matching on `query`
+       fun remove_all(query: nullable QUERY): Bool is abstract
+
        # Remove all instances
        fun clear: Bool is abstract
 
@@ -217,19 +252,17 @@ end
 
 # A Repository that uses MongoDB as backend.
 #
-# ~~~
+# ~~~nitish
 # import popcorn
-# import popcorn::pop_routes
+# import popcorn::pop_repos
+# import popcorn::pop_json
 #
 # # First, let's create a User abstraction:
 #
 # # Serializable user representation.
 # class User
+#      super RepoObject
 #      serialize
-#      super Jsonable
-#
-#      # User uniq ID
-#      var id: String = (new MongoObjectId).id is serialize_as "_id"
 #
 #      # User login
 #      var login: String
@@ -238,9 +271,6 @@ end
 #      var password: String is writable
 #
 #      redef fun to_s do return login
-#      redef fun ==(o) do return o isa SELF and id == o.id
-#      redef fun hash do return id.hash
-#      redef fun to_json do return serialize_to_json
 # end
 #
 # # We then need to subclass the `MongoRepository` to provide User specific services:
@@ -260,7 +290,7 @@ end
 # # The repository can then be used with User instances:
 #
 # # Init database
-# var mongo = new MongoClient("mongodb://localhost:27017/")
+# var mongo = new MongoClient("mongodb://mongo:27017/")
 # var db = mongo.database("tests")
 # var coll = db.collection("test_pop_repo_{100000.rand}")
 #
@@ -324,6 +354,10 @@ class MongoRepository[E: Serializable]
                return collection.remove(query or else new JsonObject)
        end
 
+       redef fun remove_all(query) do
+               return collection.remove_all(query or else new JsonObject)
+       end
+
        redef fun clear do return collection.drop
 
        # Perform an aggregation query over the repo.
@@ -338,6 +372,60 @@ class MongoRepository[E: Serializable]
        end
 end
 
+# Base serializable entity that can go into a JsonRepository
+#
+# Provide boiler plate implementation of all object serializable to json.
+#
+# `id` is used as a primary key for `find_by_id`.
+#
+# Subclassing RepoObject makes it easy to create a serializable class:
+# ~~~
+# import popcorn::pop_repos
+#
+# class Album
+#      super RepoObject
+#      serialize
+#
+#      var title: String
+#      var price: Float
+# end
+# ~~~
+#
+# Do not forget the `serialize` annotation else the fields will not be serialized.
+#
+# It is also possible to redefine the `id` primary key to use your own:
+# ~~~
+# import popcorn::pop_repos
+#
+# class Order
+#      super RepoObject
+#      serialize
+#
+#      redef var id = "order-{get_time}"
+#
+#      # ...
+#
+# end
+# ~~~
+abstract class RepoObject
+       serialize
+
+       # `self` unique id.
+       #
+       # This attribute is serialized under the key `_id` to be used
+       # as primary key by MongoDb
+       var id: String = (new MongoObjectId).id is writable, serialize_as "_id"
+
+       # Base object comparison on ID
+       #
+       # Because multiple deserialization can exists of the same instance,
+       # we use the ID to determine if two object are the same.
+       redef fun ==(o) do return o isa SELF and id == o.id
+
+       redef fun hash do return id.hash
+       redef fun to_s do return id
+end
+
 # JsonObject can be used as a `RepositoryQuery`.
 #
 # See `mongodb` lib.