-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathapp_quickstart2.py
118 lines (86 loc) · 4.78 KB
/
app_quickstart2.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
""" Bit more advanced PyMotyc application.
There are some more concepts demonstrated:
- declarative binding of the database to pymotyc.Engine instance with engine.database decorator,
- custom identity field, id will be generated by PyMotyc,
- inject_motyc_fields=True options to turn model fields to MotycField,
- model fields (turned to MotycField) then can be used as keys in queries, making them refactorable,
- query builder, when logical operations between MotycField will form MotycQuery,
which can be used then in collection find... operations.
For basic usage see app_quickstart.py, here only advanced concepts will be commented.
Here we have employee_id field in the model to represent identity. It is of type str and contains UUID
in str representation, which will be generated by PyMotyc while saving model instance with empty identity.
Identity generation callable can be provided for collection, if default is not applicable.
"""
import asyncio
import uuid
from motor.motor_asyncio import AsyncIOMotorClient
from pydantic import BaseModel
import pymotyc
from pymotyc import M
class Employee(BaseModel):
employee_id: str = None # UUID in str representation used as identity, will be generated by PyMotyc while saving
name: str
age: int
# Create PyMotyc engine instance.
engine = pymotyc.Engine()
# Decorate database @engine.database to put under control of PyMotyc engine.
@engine.database
class Warehouse:
employees: pymotyc.Collection[Employee] = pymotyc.Collection(identity='employee_id')
async def main():
motor = AsyncIOMotorClient("mongodb://127.0.0.1:27017")
# Bind previously created PyMotyc Engine instance to the Motor instance.
# Note we use inject_motyc_fields=True to use advanced Motyc queries,
# where model's fields themselves, instead of field names, can be used as keys
# for mongo find, sort or update queries, as well as in query builder.
await engine.bind(motor=motor, inject_motyc_fields=True)
# For custom identity unique index is created, so we have to recreate it after collection drop.
await Warehouse.employees.collection.drop()
await Warehouse.employees.create_indexes()
# ===== Use statically typed collections! =====
# Let's add first Employee to collection.
vasya = await Warehouse.employees.save(Employee(name='Vasya Pupkin', age=42))
assert isinstance(vasya, Employee)
vasya_id = vasya.employee_id
assert uuid.UUID(vasya_id) # vasya's identity is generated by PyMotyc and it is UUID in str representation
# Let's add some more Employees.
frosya = await Warehouse.employees.save(Employee(name='Frosya Taburetkina', age=22))
frosya_id = frosya.employee_id
dusya = await Warehouse.employees.save(Employee(name='Dusya Ivanova', age=20))
dusya_id = dusya.employee_id
# Let's explore our collection now...
# ...as a whole, please note we use advanced Motyc query for sort operation...
employees = await Warehouse.employees.find(sort={Employee.age: 1})
assert employees == [
Employee(employee_id=dusya_id, name='Dusya Ivanova', age=20),
Employee(employee_id=frosya_id, name='Frosya Taburetkina', age=22),
Employee(employee_id=vasya_id, name='Vasya Pupkin', age=42)
]
# ...or with query, please note we use Motyc query builder for simple operations.
# The helper M is just used to statically cast model field to MotycField
# (which are actually injected thanks to inject_motyc_fields=True option)
employees = await Warehouse.employees.find((M(Employee.age) > 40) & M(Employee.name).regex('Vasya'))
assert employees == [Employee(employee_id=vasya_id, name='Vasya Pupkin', age=42)]
# Let's get back our first Employee by it's identity.
# Note: identity should be provided in search query.
vasya = await Warehouse.employees.find_one({Employee.employee_id: vasya_id})
assert vasya.name == 'Vasya Pupkin'
assert vasya.age == 42
# Modify and save model instance (see app_quickstart.py for concurrency issue comments).
vasya.age += 1
vasya = await Warehouse.employees.save(vasya)
assert vasya.age == 43
# Or modify in-place.
# Note: query builder for update operations is not available (yet?)
vasya = await Warehouse.employees.update_one({Employee.employee_id: vasya_id}, update={'$inc': {Employee.age: 1}})
assert vasya.age == 44
# Finally let's remove someone from collection.
await Warehouse.employees.delete_one({Employee.employee_id: vasya_id})
# And check if is it done.
employees = await Warehouse.employees.find(sort={Employee.age: 1})
assert employees == [
Employee(employee_id=dusya_id, name='Dusya Ivanova', age=20),
Employee(employee_id=frosya_id, name='Frosya Taburetkina', age=22),
]
if __name__ == "__main__":
asyncio.run(main())