@@ -492,24 +492,29 @@ def _row_data(max_index):
492492 yield [
493493 index ,
494494 'First%09d' % (index ,),
495- 'Last09%d ' % (index ),
495+ 'Last%09d ' % (max_index - index ),
496496 'test-%09d@example.com' % (index ,),
497497 ]
498498
499- def _set_up_table (self , row_count ):
500- retry = RetryInstanceState (_has_all_ddl )
501- retry (self ._db .reload )()
499+ def _set_up_table (self , row_count , db = None ):
502500
503- session = self ._db .session ()
501+ if db is None :
502+ db = self ._db
503+ retry = RetryInstanceState (_has_all_ddl )
504+ retry (db .reload )()
505+
506+ session = db .session ()
504507 session .create ()
505508 self .to_delete .append (session )
506509
507- with session . transaction () as transaction :
508- transaction .delete (self .TABLE , self .ALL )
510+ def _unit_of_work ( transaction , test ) :
511+ transaction .delete (test .TABLE , test .ALL )
509512 transaction .insert (
510- self .TABLE , self .COLUMNS , self ._row_data (row_count ))
513+ test .TABLE , test .COLUMNS , test ._row_data (row_count ))
514+
515+ committed = session .run_in_transaction (_unit_of_work , test = self )
511516
512- return session , transaction . committed
517+ return session , committed
513518
514519 def test_read_w_manual_consume (self ):
515520 ROW_COUNT = 4000
@@ -531,6 +536,63 @@ def test_read_w_manual_consume(self):
531536 self .assertEqual (streamed ._current_row , [])
532537 self .assertEqual (streamed ._pending_chunk , None )
533538
539+ def test_read_w_index (self ):
540+ ROW_COUNT = 2000
541+ # Indexed reads cannot return non-indexed columns
542+ MY_COLUMNS = self .COLUMNS [0 ], self .COLUMNS [2 ]
543+ EXTRA_DDL = [
544+ 'CREATE INDEX contacts_by_last_name ON contacts(last_name)' ,
545+ ]
546+ pool = BurstyPool ()
547+ temp_db = Config .INSTANCE .database (
548+ 'test_read_w_index' , ddl_statements = DDL_STATEMENTS + EXTRA_DDL ,
549+ pool = pool )
550+ operation = temp_db .create ()
551+ self .to_delete .append (_DatabaseDropper (temp_db ))
552+
553+ # We want to make sure the operation completes.
554+ operation .result (30 ) # raises on failure / timeout.
555+
556+ session , committed = self ._set_up_table (ROW_COUNT , db = temp_db )
557+
558+ snapshot = session .snapshot (read_timestamp = committed )
559+ rows = list (snapshot .read (
560+ self .TABLE , MY_COLUMNS , self .ALL , index = 'contacts_by_last_name' ))
561+
562+ expected = list (reversed (
563+ [(row [0 ], row [2 ]) for row in self ._row_data (ROW_COUNT )]))
564+ self ._check_row_data (rows , expected )
565+
566+ def test_read_w_limit (self ):
567+ ROW_COUNT = 4000
568+ LIMIT = 100
569+ session , committed = self ._set_up_table (ROW_COUNT )
570+
571+ snapshot = session .snapshot (read_timestamp = committed )
572+ rows = list (snapshot .read (
573+ self .TABLE , self .COLUMNS , self .ALL , limit = LIMIT ))
574+
575+ all_data_rows = list (self ._row_data (ROW_COUNT ))
576+ expected = all_data_rows [:LIMIT ]
577+ self ._check_row_data (rows , expected )
578+
579+ def test_read_w_range (self ):
580+ from google .cloud .spanner .keyset import KeyRange
581+ ROW_COUNT = 4000
582+ START_CLOSED = 1000
583+ END_OPEN = 2000
584+ session , committed = self ._set_up_table (ROW_COUNT )
585+ key_range = KeyRange (start_closed = [START_CLOSED ], end_open = [END_OPEN ])
586+ keyset = KeySet (ranges = (key_range ,))
587+
588+ snapshot = session .snapshot (read_timestamp = committed )
589+ rows = list (snapshot .read (
590+ self .TABLE , self .COLUMNS , keyset ))
591+
592+ all_data_rows = list (self ._row_data (ROW_COUNT ))
593+ expected = all_data_rows [START_CLOSED :END_OPEN ]
594+ self ._check_row_data (rows , expected )
595+
534596 def test_execute_sql_w_manual_consume (self ):
535597 ROW_COUNT = 4000
536598 session , committed = self ._set_up_table (ROW_COUNT )
@@ -662,3 +724,13 @@ def test_execute_sql_w_query_param(self):
662724 param_types = {'my_list' : array_type },
663725 expected = [(u'dog' ,), (u'cat' ,)],
664726 )
727+
728+
729+ class _DatabaseDropper (object ):
730+ """Helper for cleaning up databases created on-the-fly."""
731+
732+ def __init__ (self , db ):
733+ self ._db = db
734+
735+ def delete (self ):
736+ self ._db .drop ()
0 commit comments