Search code examples
scalaimplicit

Always execute code at beginning and end of method


I'm connecting to MongoDb using following code :

   def insert() = {

    val mc = new com.mongodb.MongoClient("localhost", 27017);
    val db = mc.getDatabase("MyDb");

    //My insert code

    mc.close();

  }                                               //> insert: ()Unit

I have various methods which open and close the connection. Can the lines :

  val mc = new com.mongodb.MongoClient("localhost", 27017);
val db = mc.getDatabase("MyDb");
mc.close();

be extracted so that they are implicitly called at beginning and end of method. Does Scala implicits cater for this scenario or is reflection required ?


Solution

  • A common pattern would be to use a call-by-name method where you can pass a function that accepts a DB and does something with it. The call-by-name method can facilitate the creation of the client, etc, and execute the code within.

    def withDB[A](block: DB => A): A = {
      val mc = new com.mongodb.MongoClient("localhost", 27017);
      val db = mc.getDatabase("MyDb");
      try block(db) finally mc.close()
    }
    

    And use it:

    def insert() = withDB { db =>
       // do something with `db`
    }
    

    However, a look at the documentation says:

    A MongoDB client with internal connection pooling. For most applications, you should have one MongoClient instance for the entire JVM.

    Which makes the above approach look like a bad idea, assuming that is the version you are using. I can definitely see some concurrency issues trying to do this and having too many connections open.

    But, you can follow the same pattern, stuffing the connection creating into a singleton object. You would need to manage the closing of the client when your application is shutdown, however.

    object Mongo {
      lazy val mc = new com.mongodb.MongoClient("localhost", 27017);
      lazy val db = mc.getDatabase("MyDb");
    
      def withDB[A](block: DB => A): A = block(db)
    
      def close(): Unit = mc.close()
    }