-
Notifications
You must be signed in to change notification settings - Fork 17
/
Copy pathdeclarative.py
123 lines (111 loc) · 4.45 KB
/
declarative.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
from ming.metadata import collection, Index
from .mapper import mapper
from .property import ORMProperty
import six
class _MappedClassMeta(type):
def __init__(cls, name, bases, dct):
cls._registry['%s.%s' % (cls.__module__, cls.__name__)] = mapper(cls)
cls._compiled = False
def __new__(meta, name, bases, dct):
# Get the mapped base class(es)
mapped_bases = [b for b in bases if hasattr(b, 'query')]
doc_bases = [mapper(b).collection for b in mapped_bases]
# Build up the mongometa class
mm_bases = tuple(
(b.__mongometa__ for b in mapped_bases if hasattr(b, '__mongometa__'))
)
if not mm_bases:
mm_bases = (object,)
mm_dict = {}
if '__mongometa__' in dct:
mm_dict.update(dct['__mongometa__'].__dict__)
dct['__mongometa__'] = mm = type(
'__mongometa__<%s>' % name,
mm_bases,
mm_dict)
if hasattr(mm, 'collection_class'):
collection_class = mm.collection
else:
collection_class = meta._build_collection_class(doc_bases, dct, mm, mm_dict)
clsdict = {}
properties = {}
include_properties = getattr(mm, 'include_properties', [])
exclude_properties = getattr(mm, 'exclude_properties', [])
extensions = getattr(mm, 'extensions', [])
for k,v in six.iteritems(dct):
if isinstance(v, ORMProperty):
v.name = k
properties[k] = v
else:
clsdict[k] = v
cls = type.__new__(meta, name, bases, clsdict)
mapper(cls, collection_class, mm.session,
properties=properties,
include_properties=include_properties,
exclude_properties=exclude_properties,
extensions=extensions)
return cls
@classmethod
def _build_collection_class(meta, doc_bases, dct, mm, mm_dict):
fields = []
indexes = []
# Set the names of the fields
for k,v in six.iteritems(dct):
try:
field = getattr(v, 'field', None)
except:
continue
if field is not None:
if field.name is None:
field.name = k
fields.append(v.field)
# Get the index information
for idx in getattr(mm, 'indexes', []):
indexes.append(Index(idx))
for idx in getattr(mm, 'unique_indexes', []):
indexes.append(Index(idx, unique=True))
for idx in getattr(mm, 'custom_indexes', []):
indexes.append(Index(**idx))
collection_kwargs = dict(
polymorphic_on=mm_dict.get('polymorphic_on', None),
polymorphic_identity=getattr(mm, 'polymorphic_identity', None),
version_of=getattr(mm, 'version_of', None),
migrate=getattr(mm, 'migrate', None)
)
if hasattr(mm, 'before_save'):
collection_kwargs['before_save'] = getattr(mm.before_save, '__func__', mm.before_save)
if not doc_bases:
collection_cls = collection(
mm.name, mm.session and mm.session.impl,
*(fields + indexes),
**collection_kwargs)
else:
if mm.name is not None:
collection_kwargs['collection_name'] = mm.name
if mm.session is not None:
collection_kwargs['session'] = mm.session.impl
collection_cls = collection(
doc_bases, *(fields + indexes), **collection_kwargs)
return collection_cls
@six.add_metaclass(_MappedClassMeta)
class MappedClass(object):
"""Declares a Ming Mapped Document.
Mapped Documents provide a declarative interface to
schema, relations and properties declaration for your
Models stored as MongoDB Documents.
MappedClasses required that a ``__mongometa__`` subclass
is available inside which provides the details regarding
the ``name`` of the collection storing the documents and
the ``session`` used to store the documents::
class WikiPage(MappedClass):
class __mongometa__:
session = session
name = 'wiki_page'
_id = FieldProperty(schema.ObjectId)
title = FieldProperty(schema.String(required=True))
text = FieldProperty(schema.String(if_missing=''))
"""
_registry = {}
class __mongometa__:
name=None
session=None