Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

serializable ObjectId #18

Closed
doncatnip opened this issue Apr 21, 2011 · 5 comments
Closed

serializable ObjectId #18

doncatnip opened this issue Apr 21, 2011 · 5 comments

Comments

@doncatnip
Copy link

Hey hey

It would be awesome if ObjectId's are nativeley (re)serializable. E.g. to embed them in json return values of json-rpc handlers. That way, one can avoid iterating over docs to replace certain objects with the string value ( or to write a specific handlers for the parser, if supported )

I did it by inheriting from str, making it serializable by anything which knows how to handle str. Just a couple of changes here and there to make it immutable

if you're interested, here comes a diff

diff --git a/txmongo/_pymongo/bson.py b/txmongo/_pymongo/bson.py
index aef08f8..7587ff1 100644
--- a/txmongo/_pymongo/bson.py
+++ b/txmongo/_pymongo/bson.py
@@ -416,6 +416,8 @@ def _element_to_bson(key, value, check_keys):
         full_length = struct.pack("<i", 8 + len(cstring) + len(scope))
         length = struct.pack("<i", len(cstring))
         return "\x0F" + name + full_length + length + cstring + scope
+    if isinstance(value, ObjectId):
+        return "\x07" + name + value.binary
     if isinstance(value, str):
         cstring = _make_c_string(value)
         length = struct.pack("<i", len(cstring))
@@ -429,8 +431,6 @@ def _element_to_bson(key, value, check_keys):
     if isinstance(value, (list, tuple)):
         as_dict = SON(zip([str(i) for i in range(len(value))], value))
         return "\x04" + name + _dict_to_bson(as_dict, check_keys)
-    if isinstance(value, ObjectId):
-        return "\x07" + name + value.binary
     if value is True:
         return "\x08" + name + "\x01"
     if value is False:
diff --git a/txmongo/_pymongo/objectid.py b/txmongo/_pymongo/objectid.py
index 1c8de98..4c43cea 100644
--- a/txmongo/_pymongo/objectid.py
+++ b/txmongo/_pymongo/objectid.py
@@ -41,7 +41,7 @@ def _machine_bytes():
     return machine_hash.digest()[0:3]


-class ObjectId(object):
+class ObjectId( str ):
     """A Mongo ObjectId.
     """

@@ -50,7 +50,7 @@ class ObjectId(object):

     _machine_bytes = _machine_bytes()

-    def __init__(self, oid=None):
+    def __new__(klass, oid=None):
         """Initialize a new ObjectId_.

         If `oid` is ``None``, create a new (unique)
@@ -70,11 +70,16 @@ class ObjectId(object):
         .. _ObjectId: http://www.mongodb.org/display/DOCS/Object+IDs
         """
         if oid is None:
-            self.__generate()
+            oid = klass._generate()
         else:
-            self.__validate(oid)
+            oid = klass._validate(oid)

-    def __generate(self):
+        self = str.__new__( klass, oid.encode("hex") )
+        self.__id = oid
+        return self
+
+    @classmethod
+    def _generate(klass):
         """Generate a new value for this ObjectId.
         """
         oid = ""
@@ -94,9 +99,10 @@ class ObjectId(object):
         ObjectId._inc = (ObjectId._inc + 1) % 0xFFFFFF
         ObjectId._inc_lock.release()

-        self.__id = oid
+        return oid

-    def __validate(self, oid):
+    @classmethod
+    def _validate(self, oid):
         """Validate and use the given id for this ObjectId.

         Raises TypeError if id is not an instance of (str, ObjectId) and
@@ -106,13 +112,13 @@ class ObjectId(object):
           - `oid`: a valid ObjectId
         """
         if isinstance(oid, ObjectId):
-            self.__id = oid.__id
+            return oid.__id
         elif isinstance(oid, basestring):
             if len(oid) == 12:
-                self.__id = oid
+                return oid
             elif len(oid) == 24:
                 try:
-                    self.__id = oid.decode("hex")
+                    return oid.decode("hex")
                 except TypeError:
                     raise InvalidId("%s is not a valid ObjectId" % oid)
             else:
@@ -154,9 +160,6 @@ class ObjectId(object):
         return datetime.datetime.utcfromtimestamp(t)
     generation_time = property(generation_time)

-    def __str__(self):
-        return self.__id.encode("hex")
-
     def __repr__(self):
         return "ObjectId('%s')" % self.__id.encode("hex")
@fiorix
Copy link
Collaborator

fiorix commented Apr 22, 2011

Oh yes, I had the same issue a while ago. Have you seen the solution for this on the original pymongo driver?
Check this out: https://github.com/mongodb/mongo-python-driver/blob/master/bson/json_util.py
I'd like to make it a simple string, but I also like the idea of keeping this driver in sync with the original driver.. I just don't have enough time to dedicate to it.

@doncatnip
Copy link
Author

I didn't seen the pymongo solution. I agree, it's nice to keep stuff in sync - however, i needed a solution which would work with other serializers too, like cjson.

@fiorix
Copy link
Collaborator

fiorix commented Apr 22, 2011

Sure, I agree it's better if it works on other json serializers. Not sure what to do... Will come back (soon?) with more on this...

@doncatnip
Copy link
Author

I'll try to bring this to the pymongo folks (soon?), as i just now realize that this is the very _pymongo package ( was kinda tired yesterday ) ...

@fiorix
Copy link
Collaborator

fiorix commented Apr 22, 2011

Perfect!

@fiorix fiorix closed this as completed Sep 14, 2013
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants