From 2aad432cf7c2867b096202f3fe3cbfc93c77dd29 Mon Sep 17 00:00:00 2001 From: MaximilianoTabacman Date: Fri, 22 Mar 2024 11:27:56 -0300 Subject: [PATCH] Added support for interval queries --- source/Sagan-Core/InMemoryRepository.class.st | 16 +++ .../GemStoneRepositoryProviderTest.class.st | 133 ++++++++++++++++++ .../GemStoneRepository.class.st | 18 +++ 3 files changed, 167 insertions(+) diff --git a/source/Sagan-Core/InMemoryRepository.class.st b/source/Sagan-Core/InMemoryRepository.class.st index 077b043..1b23c19 100644 --- a/source/Sagan-Core/InMemoryRepository.class.st +++ b/source/Sagan-Core/InMemoryRepository.class.st @@ -50,6 +50,22 @@ InMemoryRepository >> findAll [ ^ contents copy ] +{ #category : 'querying' } +InMemoryRepository >> findAllFrom: aFromIndex to: aToIndex sortedBy: anIndexName [ + + | from to | + + contents ifEmpty: [ ^ contents ]. + + from := ( aFromIndex min: contents size ) max: 0. + to := ( aToIndex min: contents size ) max: 0. + + ^ ( contents sorted: [ :a :b | + ( a instVarNamed: anIndexName asString ) <= ( b instVarNamed: anIndexName asString ) ] ) + copyFrom: from + to: to +] + { #category : 'querying' } InMemoryRepository >> findAllMatching: aCriteriaOrBlock [ diff --git a/source/Sagan-GemStone-Tests/GemStoneRepositoryProviderTest.class.st b/source/Sagan-GemStone-Tests/GemStoneRepositoryProviderTest.class.st index ac3babe..d1a55ac 100644 --- a/source/Sagan-GemStone-Tests/GemStoneRepositoryProviderTest.class.st +++ b/source/Sagan-GemStone-Tests/GemStoneRepositoryProviderTest.class.st @@ -86,6 +86,139 @@ GemStoneRepositoryProviderTest >> testQueryReturningBeforeAllIndexedResultsAreRe ] ] +{ #category : 'tests' } +GemStoneRepositoryProviderTest >> testQueryingIndexedCollectionByStreaming [ + + 1000 timesRepeat: [ + self extraterrestrials + store: self johnTravolta; + store: self johnLock; + store: self ellaTravolta + ]. + + self extraterrestrials store: self silvesterStallone. + + 1000 timesRepeat: [ + self extraterrestrials + store: self johnTravolta; + store: self johnLock; + store: self ellaTravolta + ]. + + self extraterrestrials withQueryFrom: 'each.firstName >= ''''' do: [ :query | + | stream silvesterStallone | + + stream := query readStream. + stream skip: 2000 * 3. + silvesterStallone := stream next. + self assert: + ( silvesterStallone firstName = 'Silvester' and: [ silvesterStallone lastName = 'Stallone' ] ). + self assert: stream atEnd + ] +] + +{ #category : 'tests' } +GemStoneRepositoryProviderTest >> testQueryingIndexedCollectionForAllElements [ + + 4 timesRepeat: [ + 1000 timesRepeat: [ + self extraterrestrials + store: self johnTravolta; + store: self johnLock; + store: self ellaTravolta + ]. + + self extraterrestrials store: self silvesterStallone. + + 1000 timesRepeat: [ + self extraterrestrials + store: self johnTravolta; + store: self johnLock; + store: self ellaTravolta + ] + ]. + self extraterrestrials withQueryFrom: 'true' do: [ :query | + self assert: query size equals: 3000 + 1 + 3000 * 4. + self + assert: ( query select: [ :extraterrestrial | + extraterrestrial firstName = 'Silvester' and: [ extraterrestrial lastName = 'Stallone' ] ] ) + size + equals: 4. + self + assert: ( query select: [ :extraterrestrial | + extraterrestrial firstName = 'John' and: [ extraterrestrial lastName = 'Travolta' ] ] ) size + equals: 2000 * 4. + self + assert: ( query select: [ :extraterrestrial | + extraterrestrial firstName = 'John' and: [ extraterrestrial lastName = 'Lock' ] ] ) size + equals: 2000 * 4. + self + assert: ( query select: [ :extraterrestrial | + extraterrestrial firstName = 'Ella' and: [ extraterrestrial lastName = 'Travolta' ] ] ) size + equals: 2000 * 4 + ] +] + +{ #category : 'tests' } +GemStoneRepositoryProviderTest >> testQueryingIndexedCollectionForNoElements [ + + 4 timesRepeat: [ + 1000 timesRepeat: [ + self extraterrestrials + store: self johnTravolta; + store: self johnLock; + store: self ellaTravolta + ]. + + self extraterrestrials store: self silvesterStallone. + + 1000 timesRepeat: [ + self extraterrestrials + store: self johnTravolta; + store: self johnLock; + store: self ellaTravolta + ] + ]. + self extraterrestrials withQueryFrom: 'false' do: [ :query | self assert: query isEmpty ] +] + +{ #category : 'tests' } +GemStoneRepositoryProviderTest >> testQueryingInterval [ + + | result | + + 1000 timesRepeat: [ + self extraterrestrials + store: self johnTravolta; + store: self johnLock; + store: self ellaTravolta; + store: self silvesterStallone + ]. + + result := self extraterrestrials findAllFrom: 1000 to: 1001 sortedBy: 'lastName'. + self assert: result size equals: 2. + self assert: ( result first firstName = 'John' and: [ result first lastName = 'Lock' ] ). + self assert: ( result last firstName = 'Silvester' and: [ result last lastName = 'Stallone' ] ). + + result := self extraterrestrials findAllFrom: 4000 to: 4005 sortedBy: 'lastName'. + self + withTheOnlyOneIn: result + do: [ :extraterrestrial | self assert: extraterrestrial lastName equals: 'Travolta' ]. + result := self extraterrestrials findAllFrom: 4000 to: 4005 sortedBy: 'firstName'. + self withTheOnlyOneIn: result do: [ :extraterrestrial | + self + assert: extraterrestrial firstName equals: 'Silvester'; + assert: extraterrestrial lastName equals: 'Stallone' + ]. + + result := self extraterrestrials findAllFrom: -50 to: 0 sortedBy: 'lastName'. + self assert: result isEmpty. + result := self extraterrestrials findAllFrom: 6 to: -2 sortedBy: 'lastName'. + self assert: result isEmpty. + result := self extraterrestrials findAllFrom: 5000 to: 10000 sortedBy: 'lastName'. + self assert: result isEmpty +] + { #category : 'tests' } GemStoneRepositoryProviderTest >> testQueryingWhenCollectionIsLargeAndIndexed [ diff --git a/source/Sagan-GemStone/GemStoneRepository.class.st b/source/Sagan-GemStone/GemStoneRepository.class.st index 47e8e69..ccd3d7d 100644 --- a/source/Sagan-GemStone/GemStoneRepository.class.st +++ b/source/Sagan-GemStone/GemStoneRepository.class.st @@ -50,6 +50,24 @@ GemStoneRepository >> findAll [ ^ contents copy ] +{ #category : 'querying' } +GemStoneRepository >> findAllFrom: aFromIndex to: aToIndex sortedBy: anIndexName [ + + | results | + + results := OrderedCollection new. + self withQueryFrom: ( 'each.<1s> >= ''''' expandMacrosWith: anIndexName asString ) do: [ :query | + | stream start limit | + + stream := query readStream. + start := aFromIndex - 1 max: 0. + limit := aToIndex - start max: 0. + stream skip: start. + limit timesRepeat: [ stream atEnd ifFalse: [ results add: stream next ] ] + ]. + ^ results +] + { #category : 'querying' } GemStoneRepository >> findAllMatching: aCriteriaOrBlock [