Skip to content

Commit ad2a89d

Browse files
committed
Search System Created
1 parent d625427 commit ad2a89d

File tree

3 files changed

+236
-6
lines changed

3 files changed

+236
-6
lines changed

filexdb/collection.py

Lines changed: 204 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,15 @@
22
from typing import Mapping, List
33

44
from .document import Document
5-
from .fileio import FileIO, BinaryFileIO
5+
from .fileio import FileIO
6+
7+
8+
# ^__^
9+
# (oo)\_______
10+
# (_)\ )\/\
11+
# ||----w |
12+
# || ||
13+
# ~~~~~~~~~~~~~~~~~~~~
614

715

816
class Collection:
@@ -12,10 +20,11 @@ def __init__(self, col_name: str, binary_file: FileIO) -> None:
1220

1321
# Get the data of existing Database or empty database.
1422
self._database = self._binary_file.read()
15-
# print(self._database)
16-
# Initiate a default Collection
1723

18-
# Check the Collection is already exists or no
24+
self._cursor: int = 0
25+
26+
# Initiate a default Collection.
27+
# Check the Collection is already exists or no.
1928
if self._col_name in self._database.keys():
2029

2130
# Get the existing Collection
@@ -81,13 +90,202 @@ def insert_all(self, document_list: List[Mapping]) -> int:
8190

8291
# Iterate over all Documents of document_list & Insert one by one.
8392
for document in document_list:
84-
8593
# insert every single document in Database & increment ``doc_count``.
8694
doc_count += self.insert(document)
8795

8896
return doc_count
8997

9098

99+
""" FIND_ONE
100+
def __find_one(self, query: Mapping = None) -> Document | None:
101+
"
102+
Finds a single ``Document`` of ``Collection``.
103+
104+
If ``query`` is None then returns all the ``Documents`` of ``Collection``.
105+
106+
If ``query`` is not None then returns only the first occurrence.
107+
108+
:param query: Condition to search Document
109+
:return: Document
110+
"
111+
# Default result
112+
_result = {}
113+
114+
# Make sure the query implements the ``Mapping`` interface.
115+
if not isinstance(query, Mapping | None):
116+
raise ValueError('Document is not a Dictionary')
117+
118+
119+
120+
# Check if has ``query`` or not
121+
if query is None:
122+
_result = self._collection[self._cursor]
123+
self._reset_cursor()
124+
else:
125+
print(self._cursor)
126+
_result = self._find_document_by_query(query)
127+
self._reset_cursor()
128+
_result = _result[self._cursor]
129+
130+
return _result
131+
"""
132+
133+
def find(self, query: Mapping = None, limit: tuple = None) -> List[Document | None]:
134+
"""
135+
Finds all ``Document`` of ``Collection``.
136+
137+
If ``query`` is None then returns all the ``Documents`` of ``Collection``.
138+
139+
If ``query`` is not None then find returns all the occurrences.
140+
141+
:param limit: Amount of Document to fetch
142+
:param query: Condition to search Document
143+
:return: List of Document
144+
"""
145+
# Default result
146+
_result = []
147+
148+
# Make sure the query implements the ``Mapping`` interface.
149+
if not isinstance(query, Mapping | None):
150+
raise ValueError('Document is not a Dictionary')
151+
152+
# if limit, Check everything ok
153+
_limit_start = _limit_end = None
154+
155+
if limit:
156+
if len(limit) == 2:
157+
_limit_start = limit[0]
158+
_limit_end = limit[1]
159+
else:
160+
raise ValueError(f"limit is a tuple of 2 values, {len(limit)} is given.")
161+
162+
# Check if ``query`` is None or not None.
163+
if query is None:
164+
# Check if it has a limit or not. If it has a limit do limit specific tasks.
165+
# Else return the whole Collection.
166+
if limit is not None:
167+
_result = self._collection[_limit_start: _limit_end]
168+
else:
169+
_result = self._collection
170+
171+
return _result
172+
173+
elif query is not None:
174+
if limit:
175+
for i in self._collection:
176+
_doc = self._find_document_by_query(query)
177+
178+
# Append Document to the result if found
179+
if _doc:
180+
_result += _doc
181+
182+
# Check the result reached to the limit or not
183+
if len(_result) >= _limit_end:
184+
break
185+
186+
# Reset the cursor
187+
self._reset_cursor()
188+
189+
# Travers limited result
190+
_result = _result[_limit_start: _limit_end]
191+
192+
else:
193+
for i in self._collection:
194+
_doc = self._find_document_by_query(query)
195+
196+
if _doc:
197+
_result += _doc
198+
self._reset_cursor()
199+
200+
return _result
201+
202+
203+
204+
def _reset_cursor(self) -> None:
205+
"""
206+
Reset Cursor Pointer to 0th index
207+
:return: None
208+
"""
209+
self._cursor = 0
210+
211+
def _find_document_by_query(self, query: Mapping) -> List | None:
212+
"""
213+
Finds a single ``Document`` of ``Collection``.
214+
215+
Returns None if ``query`` is None of any Document not found.
216+
217+
:param query: Condition to search Document
218+
:return: Document
219+
"""
220+
result = []
221+
222+
# Make sure the query implements the ``Mapping`` interface.
223+
if not isinstance(query, Mapping | None):
224+
raise ValueError('Document is not a Dictionary')
225+
226+
# Get the length on Collection
227+
_collection_length = len(self._collection)
228+
229+
# Iterate all the Documents of Collection
230+
for doc_index in range(self._cursor, _collection_length):
231+
232+
# Update ``self._doc_index`` with ``doc_index``, to iterate next Document.
233+
self._cursor = doc_index + 1
234+
235+
# Get the length on ``query`` to iterate all attributes
236+
_query_length = len(query)
237+
238+
# Typecast ``query`` in to a ``list`` to iterate it.
239+
_query_list = list(query.items())
240+
241+
# ``_bag_of_query`` indicates the Document is desired or not.
242+
_bag_of_query = [0] * _query_length
243+
244+
for i in range(_query_length):
245+
246+
# Check the ``key`` is belongs to the Documents or not.
247+
if _query_list[i][0] in self._collection[doc_index]:
248+
249+
# Check the ``value`` of ``query`` is same to the Document's or not.
250+
if self._collection[doc_index][_query_list[i][0]] == _query_list[i][1]:
251+
252+
# If both values are same, then update ``_bag_of_query[i]`` as 1.
253+
_bag_of_query[i] = 1
254+
255+
256+
else:
257+
continue
258+
else:
259+
continue
260+
# Check if ``_bag_of_query`` contains any `0` or not.
261+
# If it has any value then this is the desired Document.
262+
# Else such Document in Collection.
263+
264+
265+
266+
if 0 not in _bag_of_query:
267+
268+
# return the Document
269+
result.append(self._collection[doc_index])
270+
271+
elif doc_index <= _collection_length:
272+
# self._doc_index = doc_index
273+
continue
274+
275+
else:
276+
return None
277+
278+
279+
return result
280+
281+
282+
283+
284+
def count(self, query: Mapping = None, limit: tuple = None) -> int:
285+
return len(self.find(query=query, limit=limit))
286+
287+
288+
91289
# ======================== #
92290
def _doc_is_exists(self, doc_id: str | int) -> bool:
93291
# Iterate over all Documents of Collection
@@ -97,7 +295,7 @@ def _doc_is_exists(self, doc_id: str | int) -> bool:
97295

98296
return False
99297

100-
def _get_document_by_id(self, doc_id) -> Document | str:
298+
def _find_document_by_id(self, doc_id) -> Document | str:
101299
for doc in self._collection:
102300
if doc["_id_"] == doc_id:
103301
return doc

filexdb/document.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from typing import Mapping
22
import uuid
3+
import json
34

45

56
def _get_id():
@@ -23,3 +24,19 @@ def __init__(self, value: Mapping) -> None:
2324
self.id = self._doc["_id_"]
2425

2526
super().__init__(self._doc)
27+
28+
def beautify(self) -> str:
29+
"""
30+
Beautify the ``JSON Object`` with new lines & proper indentation.
31+
32+
Convert `JSON Object`` into `JSON String`` using ``json.dumps()``.
33+
34+
:return: JSON String
35+
"""
36+
37+
# Dumping JSON Object & adding indentation
38+
self._doc = json.dumps(self._doc, indent=4)
39+
40+
return self._doc
41+
42+

test/test_collection.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
from filexdb import FileXdb
2+
3+
4+
db = FileXdb("testDb", 'data')
5+
6+
data = {"name": "India", "capital": "New Delhi", "city": ["Kolkata", "Bangalore", "Mumbai", "Delhi"]}
7+
data_list = [
8+
{"name": "Nepal", "capital": "Kathmandu", "city": []},
9+
{"name": "Russia", "capital": "Moscow"}
10+
]
11+
12+
countries = db.collection("countries")
13+
countries.insert(data)
14+
countries.insert_all(data_list)
15+

0 commit comments

Comments
 (0)