userver: en/testsuite/databases/mongo/ensure_db_indexes.py Source File
Loading...
Searching...
No Matches
ensure_db_indexes.py
1import typing
2
3import pymongo
4import pytest
5
6SORT_STR_TO_PYMONGO = {
7 'ascending': pymongo.ASCENDING,
8 'descending': pymongo.DESCENDING,
9 '2d': pymongo.GEO2D,
10 '2dsphere': pymongo.GEOSPHERE,
11 'hashed': pymongo.HASHED,
12 'text': pymongo.TEXT,
13}
14
15
16def create_collection(collection):
17 try:
18 collection.database.create_collection(collection.name)
19 except pymongo.errors.CollectionInvalid:
20 pass
21
22
23def shard_collection(collection, sharding):
24 db_admin = collection.database.client.admin
25 try:
26 db_admin.command('enablesharding', collection.database.name)
27 except pymongo.errors.OperationFailure as exc:
28 if exc.code != 23:
29 raise
30 kwargs = _get_kwargs_for_shard_func(sharding)
31 if not _is_collection_sharded(collection):
32 db_admin.command('shardcollection', collection.full_name, **kwargs)
33
34
35def ensure_db_indexes(dbase, db_settings, sharding_enabled=True):
36 for alias, value in db_settings.items():
37 collection = getattr(dbase, alias, None)
38 if collection is not None:
39 create_collection(collection)
40
41 indexes = value.get('indexes')
42 if indexes:
43 for index in indexes:
44 _ensure_index(index, collection)
45 index_info = collection.index_information()
46 assert len(index_info) == len(indexes) + 1, (
47 'Collection {} have {} indexes, but must have {} '.format(
48 alias,
49 len(index_info),
50 len(indexes) + 1,
51 )
52 )
53
54 if sharding_enabled:
55 sharding = value.get('sharding')
56 if sharding:
57 shard_collection(collection, sharding)
58
59
60def _ensure_index(index, collection):
61 arg, kwargs = _get_args_for_ensure_func(index)
62 kwargs.pop('expireAfterSeconds', None)
63 try:
64 collection.create_index(arg, **kwargs)
65 except pymongo.errors.OperationFailure as exc:
66 pytest.fail(
67 'ensure_index() failed for {}: {}'.format(collection.name, exc),
68 )
69
70
71def _get_args_for_ensure_func(index):
72 kwargs = {}
73 for key, value in index.items():
74 if key == 'key':
75 if isinstance(value, str):
76 arg = index['key']
77 elif isinstance(value, list):
78 arg = []
79 for obj in value:
80 arg.append((obj['name'], SORT_STR_TO_PYMONGO[obj['type']]))
81 else:
82 kwargs[key] = value
83
84 if 'background' not in kwargs:
85 kwargs['background'] = True
86
87 return arg, kwargs
88
89
90def _get_kwargs_for_shard_func(sharding):
91 kwargs = {}
92
93 for key, value in sharding.items():
94 if key == 'key':
95 sharding_key: dict[str, typing.Any]
96 if isinstance(value, str):
97 sharding_key = {value: 1}
98 elif isinstance(value, list):
99 sharding_key = {}
100 for obj in value:
101 sharding_key[obj['name']] = SORT_STR_TO_PYMONGO[obj['type']]
102 else:
103 raise ValueError('Cannot handle key: {!r}'.format(value))
104 kwargs['key'] = sharding_key
105 else:
106 kwargs[key] = value
107
108 return kwargs
109
110
111def _is_collection_sharded(collection):
112 collstats = collection.database.command('collstats', collection.name)
113 return collstats.get('sharded')