google-api-client-wrapper 1.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- google_api_client_wrapper-1.0.0.dist-info/METADATA +103 -0
- google_api_client_wrapper-1.0.0.dist-info/RECORD +39 -0
- google_api_client_wrapper-1.0.0.dist-info/WHEEL +5 -0
- google_api_client_wrapper-1.0.0.dist-info/licenses/LICENSE +21 -0
- google_api_client_wrapper-1.0.0.dist-info/top_level.txt +1 -0
- google_client/__init__.py +6 -0
- google_client/services/__init__.py +13 -0
- google_client/services/calendar/__init__.py +14 -0
- google_client/services/calendar/api_service.py +454 -0
- google_client/services/calendar/constants.py +48 -0
- google_client/services/calendar/exceptions.py +35 -0
- google_client/services/calendar/query_builder.py +314 -0
- google_client/services/calendar/types.py +403 -0
- google_client/services/calendar/utils.py +338 -0
- google_client/services/drive/__init__.py +13 -0
- google_client/services/drive/api_service.py +1133 -0
- google_client/services/drive/constants.py +37 -0
- google_client/services/drive/exceptions.py +60 -0
- google_client/services/drive/query_builder.py +385 -0
- google_client/services/drive/types.py +242 -0
- google_client/services/drive/utils.py +392 -0
- google_client/services/gmail/__init__.py +16 -0
- google_client/services/gmail/api_service.py +715 -0
- google_client/services/gmail/constants.py +6 -0
- google_client/services/gmail/exceptions.py +45 -0
- google_client/services/gmail/query_builder.py +408 -0
- google_client/services/gmail/types.py +285 -0
- google_client/services/gmail/utils.py +426 -0
- google_client/services/tasks/__init__.py +12 -0
- google_client/services/tasks/api_service.py +561 -0
- google_client/services/tasks/constants.py +32 -0
- google_client/services/tasks/exceptions.py +35 -0
- google_client/services/tasks/query_builder.py +324 -0
- google_client/services/tasks/types.py +156 -0
- google_client/services/tasks/utils.py +224 -0
- google_client/user_client.py +208 -0
- google_client/utils/__init__.py +0 -0
- google_client/utils/datetime.py +144 -0
- google_client/utils/validation.py +71 -0
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
|
|
2
|
+
MAX_RESULTS_LIMIT = 1000
|
|
3
|
+
DEFAULT_MAX_RESULTS = 30
|
|
4
|
+
MAX_FILE_SIZE = 5368709120 # 5GB Drive API limit for resumable uploads
|
|
5
|
+
DEFAULT_CHUNK_SIZE = 1048576 # 1MB default chunk size for uploads
|
|
6
|
+
|
|
7
|
+
# Special folder IDs
|
|
8
|
+
SHARED_DRIVE_ROOT = "root"
|
|
9
|
+
TRASH_FOLDER = "trash"
|
|
10
|
+
SHARED_WITH_ME_FOLDER = "sharedWithMe"
|
|
11
|
+
|
|
12
|
+
# Common MIME types
|
|
13
|
+
FOLDER_MIME_TYPE = "application/vnd.google-apps.folder"
|
|
14
|
+
GOOGLE_DOCS_MIME_TYPE = "application/vnd.google-apps.document"
|
|
15
|
+
GOOGLE_SHEETS_MIME_TYPE = "application/vnd.google-apps.spreadsheet"
|
|
16
|
+
GOOGLE_SLIDES_MIME_TYPE = "application/vnd.google-apps.presentation"
|
|
17
|
+
|
|
18
|
+
MICROSOFT_WORD_MIME_TYPE = "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
|
|
19
|
+
MICROSOFT_EXCEL_MIME_TYPE = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
|
|
20
|
+
MICROSOFT_POWERPOINT_MIME_TYPE = "application/vnd.openxmlformats-officedocument.presentationml.presentation"
|
|
21
|
+
|
|
22
|
+
# File field selections for API calls
|
|
23
|
+
DEFAULT_FILE_FIELDS = "id,name,size,mimeType,createdTime,modifiedTime,parents,webViewLink,webContentLink,owners,permissions"
|
|
24
|
+
MINIMAL_FILE_FIELDS = "id,name,mimeType"
|
|
25
|
+
FULL_FILE_FIELDS = "*"
|
|
26
|
+
|
|
27
|
+
# Permission roles
|
|
28
|
+
PERMISSION_ROLE_READER = "reader"
|
|
29
|
+
PERMISSION_ROLE_WRITER = "writer"
|
|
30
|
+
PERMISSION_ROLE_COMMENTER = "commenter"
|
|
31
|
+
PERMISSION_ROLE_OWNER = "owner"
|
|
32
|
+
|
|
33
|
+
# Permission types
|
|
34
|
+
PERMISSION_TYPE_USER = "user"
|
|
35
|
+
PERMISSION_TYPE_GROUP = "group"
|
|
36
|
+
PERMISSION_TYPE_DOMAIN = "domain"
|
|
37
|
+
PERMISSION_TYPE_ANYONE = "anyone"
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
class DriveError(Exception):
|
|
4
|
+
"""Base exception for Drive API errors."""
|
|
5
|
+
pass
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class FileNotFoundError(DriveError):
|
|
9
|
+
"""Raised when a file or folder is not found."""
|
|
10
|
+
pass
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class FolderNotFoundError(DriveError):
|
|
14
|
+
"""Raised when a folder is not found."""
|
|
15
|
+
pass
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class PermissionDeniedError(DriveError):
|
|
19
|
+
"""Raised when the user lacks permission for a Drive operation."""
|
|
20
|
+
pass
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class DriveQuotaExceededError(DriveError):
|
|
24
|
+
"""Raised when Drive storage quota is exceeded."""
|
|
25
|
+
pass
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class FileTooLargeError(DriveError):
|
|
29
|
+
"""Raised when a file exceeds size limits."""
|
|
30
|
+
pass
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class InvalidFileTypeError(DriveError):
|
|
34
|
+
"""Raised when an unsupported file type is used."""
|
|
35
|
+
pass
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class UploadFailedError(DriveError):
|
|
39
|
+
"""Raised when file upload fails."""
|
|
40
|
+
pass
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class DownloadFailedError(DriveError):
|
|
44
|
+
"""Raised when file download fails."""
|
|
45
|
+
pass
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class SharingError(DriveError):
|
|
49
|
+
"""Raised when file sharing operations fail."""
|
|
50
|
+
pass
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class DrivePermissionError(DriveError):
|
|
54
|
+
"""Raised when permission operations fail."""
|
|
55
|
+
pass
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
class InvalidQueryError(DriveError):
|
|
59
|
+
"""Raised when a Drive search query is invalid."""
|
|
60
|
+
pass
|
|
@@ -0,0 +1,385 @@
|
|
|
1
|
+
from datetime import datetime, date
|
|
2
|
+
from typing import Optional, List, Union, TYPE_CHECKING
|
|
3
|
+
|
|
4
|
+
from .constants import FOLDER_MIME_TYPE, MAX_RESULTS_LIMIT, DEFAULT_MAX_RESULTS
|
|
5
|
+
from ...utils.datetime import convert_datetime_to_iso
|
|
6
|
+
|
|
7
|
+
if TYPE_CHECKING:
|
|
8
|
+
from .api_service import DriveItem, DriveFolder
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class DriveQueryBuilder:
|
|
12
|
+
"""
|
|
13
|
+
Builder pattern for constructing Drive queries with a fluent API.
|
|
14
|
+
Provides a clean, readable way to build complex file queries.
|
|
15
|
+
|
|
16
|
+
Example usage:
|
|
17
|
+
files = (user.drive.query()
|
|
18
|
+
.limit(50)
|
|
19
|
+
.in_folder("parent_folder_id")
|
|
20
|
+
.search("meeting")
|
|
21
|
+
.file_type("pdf")
|
|
22
|
+
.execute())
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
def __init__(self, api_service_class):
|
|
26
|
+
self._api_service = api_service_class
|
|
27
|
+
self._max_results: Optional[int] = DEFAULT_MAX_RESULTS
|
|
28
|
+
self._query_parts: List[str] = []
|
|
29
|
+
self._fields: Optional[str] = None
|
|
30
|
+
self._order_by: Optional[str] = None
|
|
31
|
+
self._page_token: Optional[str] = None
|
|
32
|
+
|
|
33
|
+
def limit(self, count: int) -> "DriveQueryBuilder":
|
|
34
|
+
"""
|
|
35
|
+
Set the maximum number of files to retrieve.
|
|
36
|
+
Args:
|
|
37
|
+
count: Maximum number of files (1-1000)
|
|
38
|
+
Returns:
|
|
39
|
+
Self for method chaining
|
|
40
|
+
"""
|
|
41
|
+
if count < 1 or count > MAX_RESULTS_LIMIT:
|
|
42
|
+
raise ValueError(f"Limit must be between 1 and {MAX_RESULTS_LIMIT}")
|
|
43
|
+
self._max_results = count
|
|
44
|
+
return self
|
|
45
|
+
|
|
46
|
+
def search(self, query: str) -> "DriveQueryBuilder":
|
|
47
|
+
"""
|
|
48
|
+
Add a search term to the query (searches name and content).
|
|
49
|
+
Args:
|
|
50
|
+
query: Search term to add
|
|
51
|
+
Returns:
|
|
52
|
+
Self for method chaining
|
|
53
|
+
"""
|
|
54
|
+
if query:
|
|
55
|
+
escaped_query = query.replace("'", "\'\'")
|
|
56
|
+
self._query_parts.append(f"fullText contains '{escaped_query}'")
|
|
57
|
+
return self
|
|
58
|
+
|
|
59
|
+
def name_contains(self, text: str) -> "DriveQueryBuilder":
|
|
60
|
+
"""
|
|
61
|
+
Filter files whose name contains the specified text.
|
|
62
|
+
Args:
|
|
63
|
+
text: Text to search for in file names
|
|
64
|
+
Returns:
|
|
65
|
+
Self for method chaining
|
|
66
|
+
"""
|
|
67
|
+
if text:
|
|
68
|
+
escaped_text = text.replace("'", "\'\'")
|
|
69
|
+
self._query_parts.append(f"name contains '{escaped_text}'")
|
|
70
|
+
return self
|
|
71
|
+
|
|
72
|
+
def name_equals(self, name: str) -> "DriveQueryBuilder":
|
|
73
|
+
"""
|
|
74
|
+
Filter files with the exact name.
|
|
75
|
+
Args:
|
|
76
|
+
name: Exact name to match
|
|
77
|
+
Returns:
|
|
78
|
+
Self for method chaining
|
|
79
|
+
"""
|
|
80
|
+
if name:
|
|
81
|
+
escaped_name = name.replace("'", "\'\'")
|
|
82
|
+
self._query_parts.append(f"name = '{escaped_name}'")
|
|
83
|
+
return self
|
|
84
|
+
|
|
85
|
+
def in_folder(self, folder: Union[str, "DriveFolder"]) -> "DriveQueryBuilder":
|
|
86
|
+
"""
|
|
87
|
+
Filter files within a specific folder.
|
|
88
|
+
Args:
|
|
89
|
+
folder: DriveFolder object or folder ID string
|
|
90
|
+
Returns:
|
|
91
|
+
Self for method chaining
|
|
92
|
+
"""
|
|
93
|
+
if folder:
|
|
94
|
+
# Handle both DriveFolder objects and string IDs for backwards compatibility
|
|
95
|
+
folder_id = folder.folder_id if hasattr(folder, 'folder_id') else folder
|
|
96
|
+
self._query_parts.append(f"'{folder_id}' in parents")
|
|
97
|
+
return self
|
|
98
|
+
|
|
99
|
+
def in_any_folder(self, folders: List[Union[str, "DriveFolder"]]) -> "DriveQueryBuilder":
|
|
100
|
+
"""
|
|
101
|
+
Filter files within any of the specified folders.
|
|
102
|
+
Args:
|
|
103
|
+
folders: List of DriveFolder objects or folder ID strings
|
|
104
|
+
Returns:
|
|
105
|
+
Self for method chaining
|
|
106
|
+
"""
|
|
107
|
+
if folders:
|
|
108
|
+
folder_ids = []
|
|
109
|
+
for folder in folders:
|
|
110
|
+
folder_id = folder.folder_id if hasattr(folder, 'folder_id') else folder
|
|
111
|
+
folder_ids.append(folder_id)
|
|
112
|
+
folder_conditions = [f"'{folder_id}' in parents" for folder_id in folder_ids]
|
|
113
|
+
combined_condition = " or ".join(folder_conditions)
|
|
114
|
+
self._query_parts.append(f"({combined_condition})")
|
|
115
|
+
return self
|
|
116
|
+
|
|
117
|
+
def not_in_folder(self, folder: Union[str, "DriveFolder"]) -> "DriveQueryBuilder":
|
|
118
|
+
"""
|
|
119
|
+
Filter files NOT within a specific folder.
|
|
120
|
+
Args:
|
|
121
|
+
folder: DriveFolder object or folder ID string to exclude
|
|
122
|
+
Returns:
|
|
123
|
+
Self for method chaining
|
|
124
|
+
"""
|
|
125
|
+
if folder:
|
|
126
|
+
folder_id = folder.folder_id if hasattr(folder, 'folder_id') else folder
|
|
127
|
+
self._query_parts.append(f"not '{folder_id}' in parents")
|
|
128
|
+
return self
|
|
129
|
+
|
|
130
|
+
def file_type(self, mime_type: str) -> "DriveQueryBuilder":
|
|
131
|
+
"""
|
|
132
|
+
Filter files by MIME type.
|
|
133
|
+
Args:
|
|
134
|
+
mime_type: MIME type to filter by
|
|
135
|
+
Returns:
|
|
136
|
+
Self for method chaining
|
|
137
|
+
"""
|
|
138
|
+
if mime_type:
|
|
139
|
+
self._query_parts.append(f"mimeType = '{mime_type}'")
|
|
140
|
+
return self
|
|
141
|
+
|
|
142
|
+
def folders_only(self) -> "DriveQueryBuilder":
|
|
143
|
+
"""
|
|
144
|
+
Filter to show only folders.
|
|
145
|
+
Returns:
|
|
146
|
+
Self for method chaining
|
|
147
|
+
"""
|
|
148
|
+
self._query_parts.append(f"mimeType = '{FOLDER_MIME_TYPE}'")
|
|
149
|
+
return self
|
|
150
|
+
|
|
151
|
+
def files_only(self) -> "DriveQueryBuilder":
|
|
152
|
+
"""
|
|
153
|
+
Filter to show only files (exclude folders).
|
|
154
|
+
Returns:
|
|
155
|
+
Self for method chaining
|
|
156
|
+
"""
|
|
157
|
+
self._query_parts.append(f"mimeType != '{FOLDER_MIME_TYPE}'")
|
|
158
|
+
return self
|
|
159
|
+
|
|
160
|
+
def folders_named(self, name: str) -> "DriveQueryBuilder":
|
|
161
|
+
"""
|
|
162
|
+
Filter to show only folders with a specific name.
|
|
163
|
+
Args:
|
|
164
|
+
name: Folder name to match
|
|
165
|
+
Returns:
|
|
166
|
+
Self for method chaining
|
|
167
|
+
"""
|
|
168
|
+
if name:
|
|
169
|
+
escaped_name = name.replace("'", "\'\'")
|
|
170
|
+
self._query_parts.append(f"mimeType = '{FOLDER_MIME_TYPE}' and name = '{escaped_name}'")
|
|
171
|
+
return self
|
|
172
|
+
|
|
173
|
+
def folders_containing(self, text: str) -> "DriveQueryBuilder":
|
|
174
|
+
"""
|
|
175
|
+
Filter to show only folders whose name contains specific text.
|
|
176
|
+
Args:
|
|
177
|
+
text: Text to search for in folder names
|
|
178
|
+
Returns:
|
|
179
|
+
Self for method chaining
|
|
180
|
+
"""
|
|
181
|
+
if text:
|
|
182
|
+
escaped_text = text.replace("'", "\'\'")
|
|
183
|
+
self._query_parts.append(f"mimeType = '{FOLDER_MIME_TYPE}' and name contains '{escaped_text}'")
|
|
184
|
+
return self
|
|
185
|
+
|
|
186
|
+
def shared_with_me(self) -> "DriveQueryBuilder":
|
|
187
|
+
"""
|
|
188
|
+
Filter to show only files shared with the user.
|
|
189
|
+
Returns:
|
|
190
|
+
Self for method chaining
|
|
191
|
+
"""
|
|
192
|
+
self._query_parts.append("sharedWithMe = true")
|
|
193
|
+
return self
|
|
194
|
+
|
|
195
|
+
def owned_by_me(self) -> "DriveQueryBuilder":
|
|
196
|
+
"""
|
|
197
|
+
Filter to show only files owned by the user.
|
|
198
|
+
Returns:
|
|
199
|
+
Self for method chaining
|
|
200
|
+
"""
|
|
201
|
+
self._query_parts.append("'me' in owners")
|
|
202
|
+
return self
|
|
203
|
+
|
|
204
|
+
def starred(self) -> "DriveQueryBuilder":
|
|
205
|
+
"""
|
|
206
|
+
Filter to show only starred files.
|
|
207
|
+
Returns:
|
|
208
|
+
Self for method chaining
|
|
209
|
+
"""
|
|
210
|
+
self._query_parts.append("starred = true")
|
|
211
|
+
return self
|
|
212
|
+
|
|
213
|
+
def trashed(self, include_trashed: bool = True) -> "DriveQueryBuilder":
|
|
214
|
+
"""
|
|
215
|
+
Filter files based on trash status.
|
|
216
|
+
Args:
|
|
217
|
+
include_trashed: If True, show only trashed files. If False, exclude trashed files.
|
|
218
|
+
Returns:
|
|
219
|
+
Self for method chaining
|
|
220
|
+
"""
|
|
221
|
+
if include_trashed:
|
|
222
|
+
self._query_parts.append("trashed = true")
|
|
223
|
+
else:
|
|
224
|
+
self._query_parts.append("trashed = false")
|
|
225
|
+
return self
|
|
226
|
+
|
|
227
|
+
def created_after(self, date_time: datetime) -> "DriveQueryBuilder":
|
|
228
|
+
"""
|
|
229
|
+
Filter files created after the specified datetime.
|
|
230
|
+
Args:
|
|
231
|
+
date_time: Datetime to filter by
|
|
232
|
+
Returns:
|
|
233
|
+
Self for method chaining
|
|
234
|
+
"""
|
|
235
|
+
if date_time:
|
|
236
|
+
iso_date = convert_datetime_to_iso(date_time)
|
|
237
|
+
self._query_parts.append(f"createdTime > '{iso_date}'")
|
|
238
|
+
return self
|
|
239
|
+
|
|
240
|
+
def created_before(self, date_time: datetime) -> "DriveQueryBuilder":
|
|
241
|
+
"""
|
|
242
|
+
Filter files created before the specified datetime.
|
|
243
|
+
Args:
|
|
244
|
+
date_time: Datetime to filter by
|
|
245
|
+
Returns:
|
|
246
|
+
Self for method chaining
|
|
247
|
+
"""
|
|
248
|
+
if date_time:
|
|
249
|
+
iso_date = convert_datetime_to_iso(date_time)
|
|
250
|
+
self._query_parts.append(f"createdTime < '{iso_date}'")
|
|
251
|
+
return self
|
|
252
|
+
|
|
253
|
+
def modified_after(self, date_time: datetime) -> "DriveQueryBuilder":
|
|
254
|
+
"""
|
|
255
|
+
Filter files modified after the specified datetime.
|
|
256
|
+
Args:
|
|
257
|
+
date_time: Datetime to filter by
|
|
258
|
+
Returns:
|
|
259
|
+
Self for method chaining
|
|
260
|
+
"""
|
|
261
|
+
if date_time:
|
|
262
|
+
iso_date = convert_datetime_to_iso(date_time)
|
|
263
|
+
self._query_parts.append(f"modifiedTime > '{iso_date}'")
|
|
264
|
+
return self
|
|
265
|
+
|
|
266
|
+
def modified_before(self, date_time: datetime) -> "DriveQueryBuilder":
|
|
267
|
+
"""
|
|
268
|
+
Filter files modified before the specified datetime.
|
|
269
|
+
Args:
|
|
270
|
+
date_time: Datetime to filter by
|
|
271
|
+
Returns:
|
|
272
|
+
Self for method chaining
|
|
273
|
+
"""
|
|
274
|
+
if date_time:
|
|
275
|
+
iso_date = convert_datetime_to_iso(date_time)
|
|
276
|
+
self._query_parts.append(f"modifiedTime < '{iso_date}'")
|
|
277
|
+
return self
|
|
278
|
+
|
|
279
|
+
def with_extension(self, extension: str) -> "DriveQueryBuilder":
|
|
280
|
+
"""
|
|
281
|
+
Filter files by file extension.
|
|
282
|
+
Args:
|
|
283
|
+
extension: File extension (with or without dot)
|
|
284
|
+
Returns:
|
|
285
|
+
Self for method chaining
|
|
286
|
+
"""
|
|
287
|
+
if extension:
|
|
288
|
+
# Ensure extension starts with dot
|
|
289
|
+
if not extension.startswith('.'):
|
|
290
|
+
extension = '.' + extension
|
|
291
|
+
self._query_parts.append(f"fileExtension = '{extension[1:]}'")
|
|
292
|
+
return self
|
|
293
|
+
|
|
294
|
+
def custom_query(self, query: str) -> "DriveQueryBuilder":
|
|
295
|
+
"""
|
|
296
|
+
Add a custom query string.
|
|
297
|
+
Args:
|
|
298
|
+
query: Custom query string
|
|
299
|
+
Returns:
|
|
300
|
+
Self for method chaining
|
|
301
|
+
"""
|
|
302
|
+
if query:
|
|
303
|
+
self._query_parts.append(query)
|
|
304
|
+
return self
|
|
305
|
+
|
|
306
|
+
def order_by(self, field: str, ascending: bool = True) -> "DriveQueryBuilder":
|
|
307
|
+
"""
|
|
308
|
+
Set the order of results.
|
|
309
|
+
Args:
|
|
310
|
+
field: Field to order by (name, createdTime, modifiedTime, etc.)
|
|
311
|
+
ascending: If True, order ascending; if False, order descending
|
|
312
|
+
Returns:
|
|
313
|
+
Self for method chaining
|
|
314
|
+
"""
|
|
315
|
+
direction = "asc" if ascending else "desc"
|
|
316
|
+
self._order_by = f"{field} {direction}"
|
|
317
|
+
return self
|
|
318
|
+
|
|
319
|
+
def order_by_name(self, ascending: bool = True) -> "DriveQueryBuilder":
|
|
320
|
+
"""
|
|
321
|
+
Order results by name.
|
|
322
|
+
Args:
|
|
323
|
+
ascending: If True, order A-Z; if False, order Z-A
|
|
324
|
+
Returns:
|
|
325
|
+
Self for method chaining
|
|
326
|
+
"""
|
|
327
|
+
return self.order_by("name", ascending)
|
|
328
|
+
|
|
329
|
+
def order_by_modified_time(self, ascending: bool = False) -> "DriveQueryBuilder":
|
|
330
|
+
"""
|
|
331
|
+
Order results by modification time.
|
|
332
|
+
Args:
|
|
333
|
+
ascending: If True, oldest first; if False, newest first (default)
|
|
334
|
+
Returns:
|
|
335
|
+
Self for method chaining
|
|
336
|
+
"""
|
|
337
|
+
return self.order_by("modifiedTime", ascending)
|
|
338
|
+
|
|
339
|
+
def order_by_created_time(self, ascending: bool = False) -> "DriveQueryBuilder":
|
|
340
|
+
"""
|
|
341
|
+
Order results by creation time.
|
|
342
|
+
Args:
|
|
343
|
+
ascending: If True, oldest first; if False, newest first (default)
|
|
344
|
+
Returns:
|
|
345
|
+
Self for method chaining
|
|
346
|
+
"""
|
|
347
|
+
return self.order_by("createdTime", ascending)
|
|
348
|
+
|
|
349
|
+
def fields(self, fields: str) -> "DriveQueryBuilder":
|
|
350
|
+
"""
|
|
351
|
+
Set specific fields to retrieve from the API.
|
|
352
|
+
Args:
|
|
353
|
+
fields: Comma-separated list of fields
|
|
354
|
+
Returns:
|
|
355
|
+
Self for method chaining
|
|
356
|
+
"""
|
|
357
|
+
self._fields = fields
|
|
358
|
+
return self
|
|
359
|
+
|
|
360
|
+
def _build_query(self) -> str:
|
|
361
|
+
"""
|
|
362
|
+
Build the final query string.
|
|
363
|
+
Returns:
|
|
364
|
+
Combined query string
|
|
365
|
+
"""
|
|
366
|
+
if not self._query_parts:
|
|
367
|
+
return ""
|
|
368
|
+
|
|
369
|
+
return " and ".join(f"({part})" for part in self._query_parts)
|
|
370
|
+
|
|
371
|
+
def execute(self) -> List["DriveItem"]:
|
|
372
|
+
"""
|
|
373
|
+
Execute the query and return results.
|
|
374
|
+
Returns:
|
|
375
|
+
List of DriveItem objects matching the query
|
|
376
|
+
"""
|
|
377
|
+
query = self._build_query()
|
|
378
|
+
|
|
379
|
+
return self._api_service.list(
|
|
380
|
+
query=query,
|
|
381
|
+
max_results=self._max_results,
|
|
382
|
+
order_by=self._order_by,
|
|
383
|
+
fields=self._fields,
|
|
384
|
+
page_token=self._page_token
|
|
385
|
+
)
|