diff --git a/source/Sagan-Core-Tests/RepositoryBasedTest.class.st b/source/Sagan-Core-Tests/RepositoryBasedTest.class.st index 5aef71b..1c02c2a 100644 --- a/source/Sagan-Core-Tests/RepositoryBasedTest.class.st +++ b/source/Sagan-Core-Tests/RepositoryBasedTest.class.st @@ -140,6 +140,16 @@ RepositoryBasedTest >> sistineStallone [ ^ self extraterrestrialNamedFirst: 'Sistine' last: 'Stallone' bornOn: (Date year: 1998 month: 6 day: 27) ] +{ #category : 'tests - querying' } +RepositoryBasedTest >> testCountAll [ + + self extraterrestrials + store: self silvesterStallone; + store: self sistineStallone. + + self assert: self extraterrestrials countAll equals: 2 +] + { #category : 'tests - querying' } RepositoryBasedTest >> testCountMatching [ @@ -153,6 +163,46 @@ RepositoryBasedTest >> testCountMatching [ assert: ( self extraterrestrials countMatching: [ :person | person birthDate = (Date year: 1998 month: 6 day: 27) ] ) equals: 1 ] +{ #category : 'tests - querying' } +RepositoryBasedTest >> testFindAllFromUpToSortedByAscending [ + + | found | + + self extraterrestrials + store: self johnTravolta; + store: self johnLock; + store: self silvesterStallone. + + found := self extraterrestrials findAllFrom: 2 upTo: 2 sortedByAscending: #lastName. + self + withTheOnlyOneIn: found + do: [ :extraterrestrial | self assert: extraterrestrial lastName equals: 'Stallone' ]. + + found := self extraterrestrials findAllFrom: 1 upTo: 1 sortedByAscending: #lastName. + self + withTheOnlyOneIn: found + do: [ :extraterrestrial | self assert: extraterrestrial lastName equals: 'Lock' ]. + + found := self extraterrestrials findAllFrom: 1 upTo: 2 sortedByAscending: #firstName. + self assert: ( found allSatisfy: [ :extraterrestrial | extraterrestrial firstName = 'John' ] ). + + found := self extraterrestrials findAllFrom: 8 upTo: 9 sortedByAscending: #lastName. + self assert: found isEmpty. + + self + should: [ self extraterrestrials findAllFrom: 0 upTo: 0 sortedByAscending: #lastName ] + raise: PersistenceCommandFailed + withMessageText: 'Starting position must be strictly positive.'. + self + should: [ self extraterrestrials findAllFrom: -6 upTo: 1 sortedByAscending: #lastName ] + raise: PersistenceCommandFailed + withMessageText: 'Starting position must be strictly positive.'. + self + should: [ self extraterrestrials findAllFrom: 3 upTo: 1 sortedByAscending: #lastName ] + raise: PersistenceCommandFailed + withMessageText: 'Maximum position must be equal or greater than starting position.' +] + { #category : 'tests - querying' } RepositoryBasedTest >> testFindAllMatching [ diff --git a/source/Sagan-Core/InMemoryRepository.class.st b/source/Sagan-Core/InMemoryRepository.class.st index d667095..b46cce2 100644 --- a/source/Sagan-Core/InMemoryRepository.class.st +++ b/source/Sagan-Core/InMemoryRepository.class.st @@ -56,22 +56,6 @@ InMemoryRepository >> findAll [ ^ contents copy ] -{ #category : 'querying' } -InMemoryRepository >> findAllFrom: aFromIndex upTo: 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 [ @@ -143,6 +127,22 @@ InMemoryRepository >> updateAfterCheckingConflicts: aDomainObject with: anUpdate ^ aDomainObject ] +{ #category : 'private - querying' } +InMemoryRepository >> validatedFindAllFrom: aStartingPosition upTo: aMaximumPosition sortedByAscending: aVariableName [ + + | from to | + + ( contents isEmpty or: [ aStartingPosition > contents size ] ) ifTrue: [ ^ Set new ]. + + from := aStartingPosition max: 1. + to := ( aMaximumPosition min: contents size ) max: 1. + + ^ ( contents sorted: [ :a :b | + ( a instVarNamed: aVariableName asString ) <= ( b instVarNamed: aVariableName asString ) ] ) + copyFrom: from + to: to +] + { #category : 'querying' } InMemoryRepository >> withOneMatching: aCriteriaOrBlock do: foundBlock else: noneBlock [ diff --git a/source/Sagan-Core/RepositoryBehavior.class.st b/source/Sagan-Core/RepositoryBehavior.class.st index 27a982b..c7040a2 100644 --- a/source/Sagan-Core/RepositoryBehavior.class.st +++ b/source/Sagan-Core/RepositoryBehavior.class.st @@ -29,6 +29,17 @@ RepositoryBehavior >> asMatchingCriteria: aBlockOrCriteria [ ^ aBlockOrCriteria asMatchingCriteriaIn: self ] +{ #category : 'private - preconditions' } +RepositoryBehavior >> assertBoundariesAreValidFrom: aStartingPosition upTo: aMaximumPosition [ + + aStartingPosition strictlyPositive ifFalse: [ + PersistenceCommandFailed signal: 'Starting position must be strictly positive.' ]. + + aStartingPosition <= aMaximumPosition ifFalse: [ + PersistenceCommandFailed signal: + 'Maximum position must be equal or greater than starting position.' ] +] + { #category : 'private - preconditions' } RepositoryBehavior >> assertIncludes: inMemoryObject [ @@ -62,28 +73,44 @@ RepositoryBehavior >> conflictCheckingStrategy [ ^ self subclassResponsibility ] +{ #category : 'querying' } +RepositoryBehavior >> countAll [ + + ^ self subclassResponsibility +] + { #category : 'querying' } RepositoryBehavior >> countMatching: aCriteria [ - self subclassResponsibility + ^ self subclassResponsibility ] { #category : 'querying' } -RepositoryBehavior >> findAll [ - - self subclassResponsibility +RepositoryBehavior >> findAll [ + + ^ self subclassResponsibility +] + +{ #category : 'querying' } +RepositoryBehavior >> findAllFrom: aStartingPosition upTo: aMaximumPosition sortedByAscending: aVariableName [ + + self assertBoundariesAreValidFrom: aStartingPosition upTo: aMaximumPosition. + ^ self + validatedFindAllFrom: aStartingPosition + upTo: aMaximumPosition + sortedByAscending: aVariableName ] { #category : 'querying' } RepositoryBehavior >> findAllMatching: aCriteria [ - self subclassResponsibility + ^ self subclassResponsibility ] { #category : 'querying' } RepositoryBehavior >> findAllMatching: aCriteria sortedBy: aSortCriteria [ - self subclassResponsibility + ^ self subclassResponsibility ] { #category : 'private - accessing' } @@ -153,14 +180,20 @@ RepositoryBehavior >> updateAfterCheckingConflicts: aDomainObject with: anUpdate ^ self subclassResponsibility ] +{ #category : 'private - querying' } +RepositoryBehavior >> validatedFindAllFrom: aStartingPosition upTo: aMaximumPosition sortedByAscending: aVariableName [ + + ^ self subclassResponsibility +] + { #category : 'querying' } RepositoryBehavior >> withOneMatching: aCriteria do: foundBlock else: noneBlock [ - self subclassResponsibility + ^ self subclassResponsibility ] { #category : 'querying' } RepositoryBehavior >> withOneMatching: aCriteria sortedBy: aSortCriteria do: foundBlock else: noneBlock [ - self subclassResponsibility + ^ self subclassResponsibility ] diff --git a/source/Sagan-GemStone-Tests/GemStoneRepositoryProviderTest.class.st b/source/Sagan-GemStone-Tests/GemStoneRepositoryProviderTest.class.st index 41f1eef..917d202 100644 --- a/source/Sagan-GemStone-Tests/GemStoneRepositoryProviderTest.class.st +++ b/source/Sagan-GemStone-Tests/GemStoneRepositoryProviderTest.class.st @@ -195,27 +195,27 @@ GemStoneRepositoryProviderTest >> testQueryingInterval [ store: self silvesterStallone ]. - result := self extraterrestrials findAllFrom: 1000 upTo: 1001 sortedBy: 'lastName'. + result := self extraterrestrials findAllFrom: 1000 upTo: 1001 sortedByAscending: '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 upTo: 4005 sortedBy: 'lastName'. + result := self extraterrestrials findAllFrom: 4000 upTo: 4005 sortedByAscending: 'lastName'. self withTheOnlyOneIn: result do: [ :extraterrestrial | self assert: extraterrestrial lastName equals: 'Travolta' ]. - result := self extraterrestrials findAllFrom: 4000 upTo: 4005 sortedBy: 'firstName'. + result := self extraterrestrials findAllFrom: 4000 upTo: 4005 sortedByAscending: 'firstName'. self withTheOnlyOneIn: result do: [ :extraterrestrial | self assert: extraterrestrial firstName equals: 'Silvester'; assert: extraterrestrial lastName equals: 'Stallone' ]. - result := self extraterrestrials findAllFrom: -50 upTo: 0 sortedBy: 'lastName'. + result := self extraterrestrials findAllFrom: -50 upTo: 0 sortedByAscending: 'lastName'. self assert: result isEmpty. - result := self extraterrestrials findAllFrom: 6 upTo: -2 sortedBy: 'lastName'. + result := self extraterrestrials findAllFrom: 6 upTo: -2 sortedByAscending: 'lastName'. self assert: result isEmpty. - result := self extraterrestrials findAllFrom: 5000 upTo: 10000 sortedBy: 'lastName'. + result := self extraterrestrials findAllFrom: 5000 upTo: 10000 sortedByAscending: 'lastName'. self assert: result isEmpty ] diff --git a/source/Sagan-GemStone/GemStoneRepository.class.st b/source/Sagan-GemStone/GemStoneRepository.class.st index 48053a5..efb903f 100644 --- a/source/Sagan-GemStone/GemStoneRepository.class.st +++ b/source/Sagan-GemStone/GemStoneRepository.class.st @@ -56,28 +56,6 @@ GemStoneRepository >> findAll [ ^ contents copy ] -{ #category : 'querying' } -GemStoneRepository >> findAllFrom: aStartingPosition upTo: aMaximumPosition sortedBy: anIndexName [ - - | results | - - results := OrderedCollection new. - self withQueryFrom: ( 'each.<1s> >= ''''' expandMacrosWith: anIndexName asString ) do: [ :query | - | stream skipped limit | - - stream := query readStream. - skipped := aStartingPosition - 1 max: 0. - limit := aMaximumPosition - skipped max: 0. - stream skip: skipped. - limit timesRepeat: [ - stream atEnd - ifTrue: [ ^ results ] - ifFalse: [ results add: stream next ] - ] - ]. - ^ results -] - { #category : 'querying' } GemStoneRepository >> findAllMatching: aCriteriaOrBlock [ @@ -181,6 +159,30 @@ GemStoneRepository >> updateAfterCheckingConflicts: aDomainObject with: anUpdate ^ aDomainObject ] +{ #category : 'private - querying' } +GemStoneRepository >> validatedFindAllFrom: aStartingPosition upTo: aMaximumPosition sortedByAscending: aVariableName [ + + | results | + + results := OrderedCollection new. + self + withQueryFrom: ( 'each.<1s> >= ''''' expandMacrosWith: aVariableName asString ) + do: [ :query | + | stream limit offset | + + stream := query readStream. + limit := aMaximumPosition - aStartingPosition + 1. + offset := aStartingPosition - 1. + stream skip: offset. + limit timesRepeat: [ + stream atEnd + ifTrue: [ ^ results ] + ifFalse: [ results add: stream next ] + ] + ]. + ^ results +] + { #category : 'querying' } GemStoneRepository >> withOneMatching: aCriteriaOrBlock do: foundBlock else: noneBlock [ diff --git a/source/Sagan-RDBMS/RDBMSRepository.class.st b/source/Sagan-RDBMS/RDBMSRepository.class.st index 76730d4..af46e53 100644 --- a/source/Sagan-RDBMS/RDBMSRepository.class.st +++ b/source/Sagan-RDBMS/RDBMSRepository.class.st @@ -60,6 +60,12 @@ RDBMSRepository >> conflictCheckingStrategy [ ^ conflictCheckingStrategy ] +{ #category : 'querying' } +RDBMSRepository >> countAll [ + + ^ self withReadSessionDo: [ :session | session count: modelObjectClass ] +] + { #category : 'querying' } RDBMSRepository >> countMatching: aCriteriaOrBlock [ @@ -183,6 +189,19 @@ RDBMSRepository >> updateAfterCheckingConflicts: aDomainObject with: anUpdatedDo ^self update: aDomainObject executing: [:original | original synchronizeWith: anUpdatedDomainObject] ] +{ #category : 'private - querying' } +RDBMSRepository >> validatedFindAllFrom: aStartingPosition upTo: aMaximumPosition sortedByAscending: aVariableName [ + + | query limit offset | + + limit := aMaximumPosition - aStartingPosition + 1. + offset := aStartingPosition - 1. + query := SimpleQuery read: modelObjectClass limit: limit. + query offset: offset. + aVariableName ascending asSortFunction asOrderByIn: query. + ^ self executeQuery: query +] + { #category : 'querying' } RDBMSRepository >> withOneMatching: aCriteriaOrBlock do: foundBlock else: noneBlock [