###
### Author: David Wallin
### Time-stamp: <2015-03-04 23:06:35 dwa>

from multicorn import ForeignDataWrapper
from multicorn.utils import log_to_postgres as log2pg

from pymongo import MongoClient
from dateutil.parser import parse


def coltype_formatter(coltype):
    if coltype in ('timestamp without time zone', 'timestamp with time zone', 'date'):
        return lambda x: x if hasattr(x, 'isoformat') else parse(x)
    else:
        return None


class Mongoose_fdw (ForeignDataWrapper):

    def __init__(self, options, columns):
        super(Mongoose_fdw, self).__init__(options, columns)

        self.host_name = options.get('host', 'localhost')
        self.port_nr = int(options.get('port', '27017'))

        self.user = options.get('user')
        self.password = options.get('password')

        self.db_name = options.get('db', 'test')
        self.collection_name = options.get('collection', 'test')

        self.c = MongoClient(host=self.host_name,
                             port=self.port_nr)

        self.auth_db = options.get('auth_db', self.db_name)

        self.c.userprofile.authenticate(self.user,
                                        self.password,
                                        source=self.auth_db)

        self.db = getattr(self.c, self.db_name)
        self.coll = getattr(self.db, self.collection_name)

        self.fields = {col: coltype_formatter(coldef.type_name) for (col, coldef) in columns.items()}

    def build_spec(self, quals):
        Q = {}

        comp_mapper = {'>': '$gt',
                       '>=': '$gte',
                       '<=': '$lte',
                       '<': '$lt'}

        for qual in quals:
            val_formatter = self.fields[qual.field_name]
            vform = lambda val: val_formatter(val) if val_formatter is not None else val
            if qual.operator == '=':

                Q[qual.field_name] = vform(qual.value)
            elif qual.operator in ('>', '>=', '<=', '<'):
                comp = Q.setdefault(qual.field_name, {})
                comp[comp_mapper[qual.operator]] = vform(qual.value)
                Q[qual.field_name] = comp
            else:
                log2pg('Qual operator {} not implemented yet: {}'.format(qual.field_name, qual))
        return Q

    def execute(self, quals, columns):

        ## Only request fields of interest:
        fields = {k: True for k in columns}
        if '_id' not in fields:
            fields['_id'] = False

        Q = self.build_spec(quals)

        cur = self.coll.find(spec=Q, fields=fields, snapshot=True)
        for doc in cur:
            yield doc

## Local Variables: ***
## mode:python ***
## coding: utf-8 ***
## End: ***

@@ -52,18 +52,18 @@
 03-0
-4 23:06:35
+5 21:54:14
  dwa
@@ -228,16 +228,159 @@
  parse%0A%0A
+from functools import partial%0A%0Adict_traverser = partial(reduce,%0A                         lambda x, y: x.get(y, %7B%7D) if type(x) == dict else x)%0A%0A
 %0Adef col
@@ -1485,32 +1485,77 @@
 llection_name)%0A%0A
+        # log2pg('cols: %7B%7D'.format(columns))%0A
         self.fie
@@ -1565,16 +1565,30 @@
  = %7Bcol:
+ %7B'formatter':
  coltype
@@ -1615,16 +1615,70 @@
 pe_name)
+,%0A                             'path': col.split('.')%7D
  for (co
@@ -1986,16 +1986,29 @@
 ld_name%5D
+%5B'formatter'%5D
 %0A       
@@ -2126,17 +2126,16 @@
 == '=':%0A
-%0A
         
@@ -2173,32 +2173,33 @@
 orm(qual.value)%0A
+%0A
             elif
@@ -2408,16 +2408,17 @@
  = comp%0A
+%0A
         
@@ -2772,16 +2772,100 @@
 (quals)%0A
+        # log2pg('spec: %7B%7D'.format(Q))%0A        # log2pg('fields: %7B%7D'.format(fields))
 %0A       
@@ -2966,19 +2966,88 @@
   yield 
-doc
+%7Bcol: dict_traverser(self.fields%5Bcol%5D%5B'path'%5D, doc) for col in columns%7D%0A
 %0A%0A## Loc

allow nested fields