@@ -243,8 +243,12 @@ class GlideRecord(object):
243
243
:param ServiceNowClient client: We need to know which instance we're connecting to
244
244
:param str table: The table are we going to access
245
245
:param int batch_size: Batch size (items returned per HTTP request). Default is ``500``.
246
+ :param bool rewindable: If we can rewind the record. Default is ``True``. If ``False`` then we cannot rewind
247
+ the record, which means as an Iterable this object will be 'spent' after iteration.
248
+ This is normally the default behavior expected for a python Iterable, but not a GlideRecord.
249
+ When ``False`` less memory will be consumed, as each previous record will be collected.
246
250
"""
247
- def __init__ (self , client : 'ServiceNowClient' , table : str , batch_size = 500 ):
251
+ def __init__ (self , client : 'ServiceNowClient' , table : str , batch_size : int = 500 , rewindable : bool = True ):
248
252
self ._log = logging .getLogger (__name__ )
249
253
self ._client = client
250
254
self .__table : str = table
@@ -262,6 +266,7 @@ def __init__(self, client: 'ServiceNowClient', table: str, batch_size=500):
262
266
self .__order : str = "ORDERBYsys_id" # we *need* a default order in the event we page, see issue#96
263
267
self .__is_new_record : bool = False
264
268
self .__display_value : Union [bool , str ] = 'all'
269
+ self .__rewindable = rewindable
265
270
266
271
def _clear_query (self ):
267
272
self .__query = Query (self .__table )
@@ -443,6 +448,7 @@ def order_by_desc(self, column: str):
443
448
def pop_record (self ) -> 'GlideRecord' :
444
449
"""
445
450
Pop the current record into a new :class:`GlideRecord` object - equivalent to a clone of a singular record
451
+ FIXME: this, by the name, should be a destructive operation, but it is not.
446
452
447
453
:return: Give us a new :class:`GlideRecord` containing only the current record
448
454
"""
@@ -481,8 +487,10 @@ def set_new_guid_value(self, value):
481
487
482
488
def rewind (self ):
483
489
"""
484
- Rewinds the record so it may be iterated upon again. Not required to be called if iterating in the pythonic method .
490
+ Rewinds the record (iterable) so it may be iterated upon again. Only possible when the record is rewindable .
485
491
"""
492
+ if not self ._is_rewindable ():
493
+ raise Exception ('Cannot rewind a non-rewindable record' )
486
494
self .__current = - 1
487
495
488
496
def changes (self ) -> bool :
@@ -506,6 +514,12 @@ def query(self, query=None):
506
514
:AuthenticationException: If we do not have rights
507
515
:RequestException: If the transaction is canceled due to execution time
508
516
"""
517
+ if not self ._is_rewindable () and self .__current > 0 :
518
+ raise RuntimeError (f"huh { self ._is_rewindable } and { self .__current } " )
519
+ # raise RuntimeError('Cannot re-query a non-rewindable record that has been iterated upon')
520
+ self ._do_query (query )
521
+
522
+ def _do_query (self , query = None ):
509
523
stored = self .__query
510
524
if query :
511
525
assert isinstance (query , Query ), 'cannot query with a non query object'
@@ -564,7 +578,7 @@ def get(self, name, value=None) -> bool:
564
578
return False
565
579
else :
566
580
self .add_query (name , value )
567
- self .query ()
581
+ self ._do_query ()
568
582
return self .next ()
569
583
570
584
def insert (self ) -> Optional [GlideElement ]:
@@ -645,7 +659,7 @@ def delete_multiple(self) -> bool:
645
659
if self .__total is None :
646
660
if not self .__field_limits :
647
661
self .fields = 'sys_id' # type: ignore ## all we need...
648
- self .query ()
662
+ self ._do_query ()
649
663
650
664
allRecordsWereDeleted = True
651
665
def handle (response ):
@@ -1074,9 +1088,13 @@ def to_pandas(self, columns=None, mode='smart'):
1074
1088
1075
1089
return data
1076
1090
1091
+ def _is_rewindable (self ) -> bool :
1092
+ return self .__rewindable
1093
+
1077
1094
def __iter__ (self ):
1078
1095
self .__is_iter = True
1079
- self .rewind ()
1096
+ if self ._is_rewindable ():
1097
+ self .rewind ()
1080
1098
return self
1081
1099
1082
1100
def __next__ (self ):
@@ -1092,6 +1110,8 @@ def next(self, _recursive=False) -> bool:
1092
1110
if l > 0 and self .__current + 1 < l :
1093
1111
self .__current = self .__current + 1
1094
1112
if self .__is_iter :
1113
+ if not self ._is_rewindable (): # if we're not rewindable, remove the previous record
1114
+ self .__results [self .__current - 1 ] = None
1095
1115
return self # type: ignore # this typing is internal only
1096
1116
return True
1097
1117
if self .__total and self .__total > 0 and \
@@ -1100,10 +1120,10 @@ def next(self, _recursive=False) -> bool:
1100
1120
_recursive is False :
1101
1121
if self .__limit :
1102
1122
if self .__current + 1 < self .__limit :
1103
- self .query ()
1123
+ self ._do_query ()
1104
1124
return self .next (_recursive = True )
1105
1125
else :
1106
- self .query ()
1126
+ self ._do_query ()
1107
1127
return self .next (_recursive = True )
1108
1128
if self .__is_iter :
1109
1129
self .__is_iter = False
0 commit comments