Skip to content

Commit

Permalink
Merge pull request #85 from sebastianconcept/84-Add-UnQLite-as-backen…
Browse files Browse the repository at this point in the history
…d-option

84 add un q lite as backend option
  • Loading branch information
sebastianconcept committed Apr 5, 2022
2 parents 5b3f3cd + a322825 commit fdf3e86
Show file tree
Hide file tree
Showing 22 changed files with 1,734 additions and 35 deletions.
7 changes: 7 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
April 3, 2022
===================================
* Adds `MaplessUnQLiteCursor` to provide basic navigation of the database treating values as `Mapless`.
* Adds `testSeekGreaterThan` and `testSeekGreaterThan` for cursor positioning.
* Adds `fromCurrentDoEach:` and `fromCurrentReverseDoEach:` for iterating `Mapless` objects.
* All tests green.

March 30, 2022
===================================
* Introducing `MaplessPostgresRepository` via dependency on [P3](https://github.com/svenvc/P3).
Expand Down
45 changes: 43 additions & 2 deletions src/BaselineOfMapless/BaselineOfMapless.class.st
Original file line number Diff line number Diff line change
@@ -1,3 +1,21 @@
"
I can load the Mapless project with the default or optional modules pulling the right dependencies.
For Memory, Mongo and Redis backends you can load its default:
Metacello new
baseline: 'Mapless';
repository: 'github://sebastianconcept/Mapless:master/src';
load.
Or if you want, for example Memory and Postgres:
Metacello new
baseline: 'Mapless';
repository: 'github://sebastianconcept/Mapless:master/src';
load: #('Memory' 'Postgres')
"
Class {
#name : #BaselineOfMapless,
#superclass : #BaselineOf,
Expand All @@ -17,8 +35,9 @@ BaselineOfMapless >> baseline: spec [
group: 'Mongo' with: #('Mapless-Mongo-Tests');
group: 'Redis' with: #('Mapless-Redis-Tests');
group: 'Postgres' with: #('Mapless-Postgres-Tests');
group: 'UnQLite' with: #('Mapless-UnQLite-Tests');
group: 'Benchmark' with: #('Mapless-Benchmark-Core');
group: 'default' with: #('Memory' 'Mongo' 'Redis' 'Postgres') ]
group: 'default' with: #('Memory' 'Mongo') ]
]

{ #category : #baseline }
Expand Down Expand Up @@ -77,7 +96,10 @@ BaselineOfMapless >> setUpPackages: spec [
self setUpRedisPackages: spec.

self setUpPostgresDependencies: spec.
self setUpPostgresPackages: spec
self setUpPostgresPackages: spec.

self setUpUnQLiteDependencies: spec.
self setUpUnQLitePackages: spec
]

{ #category : #baseline }
Expand Down Expand Up @@ -113,3 +135,22 @@ BaselineOfMapless >> setUpRedisPackages: spec [
package: 'Mapless-Redis-Tests'
with: [ spec requires: #('Mapless-Redis-Core' 'Mapless-Tests-Base') ]
]

{ #category : #baseline }
BaselineOfMapless >> setUpUnQLiteDependencies: spec [
spec
baseline: 'PunQLite'
with: [ spec
repository: 'github://mumez/PunQLite/repository';
loads: #('Core') ]
]

{ #category : #baseline }
BaselineOfMapless >> setUpUnQLitePackages: spec [
spec
package: 'Mapless-UnQLite-Core'
with: [ spec requires: #('Mapless-Base-Core' 'PunQLite') ].
spec
package: 'Mapless-UnQLite-Tests'
with: [ spec requires: #('Mapless-UnQLite-Core' 'Mapless-Tests-Base') ]
]
4 changes: 2 additions & 2 deletions src/Mapless-Base-Core/Mapless.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,7 @@ Mapless >> asDictionary [
dic at: self class name asString put: attributes.
self data
associationsDo: [ :assoc |
assoc value isPersistentModel
assoc value isMapless
ifTrue: [ attributes at: assoc key put: assoc value asDictionary ]
ifFalse: [ attributes at: assoc key put: assoc value ] ].
dic ] value: OrderedJsonObject new
Expand Down Expand Up @@ -468,7 +468,7 @@ Mapless >> isDeleted [
]

{ #category : #testing }
Mapless >> isPersistentModel [
Mapless >> isMapless [
^ true
]

Expand Down
5 changes: 3 additions & 2 deletions src/Mapless-Base-Core/MaplessRepository.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,9 @@ MaplessRepository class >> for: aDatabaseName with: aDatabaseAccessor [
MaplessRepository class >> for: aDatabaseName with: aDatabaseAccessor using: aMaplessResolver [
^ self new
initializeOn: aDatabaseName
with: aDatabaseAccessor
using: aMaplessResolver
with: aDatabaseAccessor
using: aMaplessResolver;
yourself
]

{ #category : #actions }
Expand Down
5 changes: 3 additions & 2 deletions src/Mapless-Base-Core/MaplessResolver.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,9 @@ MaplessResolver >> referenceDataFrom: aJsonObject in: aMaplessRepository [

{ #category : #converting }
MaplessResolver >> storableFor: aMapless in: aMaplessRepository [
"Returns a new JsonObject that's the BSON friendly version of the jsonObject of aMapless.
It does that by visiting to cast all the values.
"Returns a new JsonObject that's a serializable friendly
version of the jsonObject of aMapless.
It does that by deep visiting and casting all its values.
It will complain if sub models are not previously saved."

| storableDocument storablePart |
Expand Down
7 changes: 7 additions & 0 deletions src/Mapless-Base-Core/OrderedJsonObject.extension.st
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,10 @@ Extension { #name : #OrderedJsonObject }
OrderedJsonObject >> asJsonObjectIn: aMaplessRepository [
^ self
]

{ #category : #'*Mapless-Base-Core' }
OrderedJsonObject >> mpWriteSelector [
self class == OrderedJsonObject
ifTrue: [ ^ #writeMap: ].
^ nil
]
148 changes: 148 additions & 0 deletions src/Mapless-Benchmark-Core/MaplessUnQLiteBenchmark.class.st
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
Class {
#name : #MaplessUnQLiteBenchmark,
#superclass : #Object,
#category : #'Mapless-Benchmark-Core'
}

{ #category : #actions }
MaplessUnQLiteBenchmark class >> runOn: aMaplessRepository [
self runOn: aMaplessRepository printingOn: Stdio stdout
]

{ #category : #actions }
MaplessUnQLiteBenchmark class >> runOn: aMaplessRepository printingOn: aStream [
aStream
lf;
cr;
lf;
cr;
nextPutAll: 'Benchmarking Mapless on UnQLite...';
lf;
cr.
self save1KPeopleOn: aMaplessRepository printingOn: aStream.
self save10KPeopleOn: aMaplessRepository printingOn: aStream.
self save1KUsersOn: aMaplessRepository printingOn: aStream.
self save10KUsersOn: aMaplessRepository printingOn: aStream
]

{ #category : #actions }
MaplessUnQLiteBenchmark class >> save10KPeopleOn: aMaplessRepository printingOn: aStream [
self save: 10000 peopleOn: aMaplessRepository printingOn: aStream
]

{ #category : #actions }
MaplessUnQLiteBenchmark class >> save10KUsersOn: aMaplessRepository printingOn: aStream [
self save: 10000 usersOn: aMaplessRepository printingOn: aStream
]

{ #category : #actions }
MaplessUnQLiteBenchmark class >> save1KPeopleOn: aMaplessRepository printingOn: aStream [
self save: 1000 peopleOn: aMaplessRepository printingOn: aStream
]

{ #category : #actions }
MaplessUnQLiteBenchmark class >> save1KUsersOn: aStream [
self save: 1000 usersOn: aStream
]

{ #category : #actions }
MaplessUnQLiteBenchmark class >> save1KUsersOn: aMaplessRepository printingOn: aStream [
self save: 1000 usersOn: aMaplessRepository printingOn: aStream
]

{ #category : #actions }
MaplessUnQLiteBenchmark class >> save: aQuantity peopleOn: aMaplessRepository printingOn: aStream [
| firstNames lastNames delay savesPerSecond guysIds readsPerSecond guy totalDelay |
firstNames := OrderedCollection new.
lastNames := OrderedCollection new.
guysIds := OrderedCollection new.
totalDelay := 0.
1 to: aQuantity do: [ :i |
guy := DummyPerson new
firstName: Character alphabet shuffled anyOne asString;
lastName: Character alphabet shuffled anyOne asString;
yourself.
delay := Time
microsecondsToRun: [ aMaplessRepository save: guy.
guysIds add: guy id ].
totalDelay := totalDelay + delay ].
savesPerSecond := (1000000 * aQuantity / totalDelay asFloat)
truncated.
aStream
lf;
cr;
nextPutAll: 'Saved ';
nextPutAll: aQuantity asString;
nextPutAll: ' instances of MaplessDummyPerson in: ';
nextPutAll: (totalDelay / 1000) asFloat rounded asString;
nextPutAll: ' ms ';
nextPutAll: '(~' , savesPerSecond asString , ' saves per second)';
flush.
totalDelay := 0.
guysIds
do: [ :guyId |
delay := Time
microsecondsToRun: [ guy := aMaplessRepository findOne: DummyPerson atId: guyId ].
totalDelay := totalDelay + delay ].
readsPerSecond := (1000000 * aQuantity / totalDelay asFloat)
truncated.
aStream
lf;
cr;
nextPutAll: 'Read ';
nextPutAll: aQuantity asString;
nextPutAll: ' instances of MaplessDummyPerson in: ';
nextPutAll: (totalDelay / 1000) asFloat rounded asString;
nextPutAll: ' ms ';
nextPutAll: '(~' , readsPerSecond asString , ' reads per second)';
flush
]

{ #category : #actions }
MaplessUnQLiteBenchmark class >> save: aQuantity usersOn: aMaplessRepository printingOn: aStream [
| guy user userIds delay savesPerSecond readsPerSecond totalDelay |
userIds := OrderedCollection new.
totalDelay := 0.
1 to: aQuantity do: [ :i |
guy := DummyPerson new
firstName: Character alphabet shuffled anyOne asString;
lastName: Character alphabet shuffled anyOne asString;
yourself.
user := DummyUser new
username: guy firstName;
person: guy;
yourself.
delay := Time
microsecondsToRun: [ aMaplessRepository save: user person.
aMaplessRepository save: user ].
totalDelay := totalDelay + delay.
userIds add: user id ].
savesPerSecond := (1000000 * aQuantity / totalDelay asFloat) truncated.
aStream
lf;
cr;
nextPutAll: 'Saved ';
nextPutAll: aQuantity asString;
nextPutAll: ' instances of MaplessDummyPerson and MaplessDummyUser in: ';
nextPutAll: (totalDelay / 1000) asFloat rounded asString;
nextPutAll: ' ms ';
nextPutAll: '(~' , savesPerSecond asString , ' saves per second)';
flush.
totalDelay := 0.
userIds
do: [ :userId |
delay := Time
microsecondsToRun: [ user := aMaplessRepository findOne: DummyUser atId: userId ].
totalDelay := totalDelay + delay ].
readsPerSecond := (1000000 * aQuantity / totalDelay asFloat) truncated.
aStream
lf;
cr;
nextPutAll: 'Read ';
nextPutAll: aQuantity asString;
nextPutAll: ' instances of MaplessDummyPerson and MaplessDummyUser in: ';
nextPutAll: (totalDelay / 1000) asFloat rounded asString;
nextPutAll: ' ms ';
nextPutAll: '(~' , readsPerSecond asString , ' reads per second)';
flush
]
6 changes: 3 additions & 3 deletions src/Mapless-Postgres-Core/MaplessPostgresClient.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -134,13 +134,13 @@ MaplessPostgresClient >> isValid [
]

{ #category : #actions }
MaplessPostgresClient >> maplessFromResult: anArray in: aMaplessPostgresRepository [
MaplessPostgresClient >> maplessFromResult: anArray in: aMaplessRepository [
| id maplessData |
id := anArray first.
maplessData := JsonObject
fromAssociations: anArray second associations.
maplessData at: aMaplessPostgresRepository idPropertyName put: id.
^ Mapless fromJSONObject: maplessData in: aMaplessPostgresRepository
maplessData at: aMaplessRepository idPropertyName put: id.
^ Mapless fromJSONObject: maplessData in: aMaplessRepository
]

{ #category : #accessing }
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
Class {
#name : #PostgresCurrentClient,
#name : #MaplessPostgresCurrentClient,
#superclass : #DynamicVariable,
#category : #'Mapless-Postgres-Core-Connections'
}
5 changes: 1 addition & 4 deletions src/Mapless-Postgres-Core/MaplessPostgresRepository.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -260,10 +260,7 @@ MaplessPostgresRepository >> maplessDataPropertyName [

{ #category : #actions }
MaplessPostgresRepository >> normalizeIdOfOn: aJsonObject [
self halt.
"aJsonObject at: 'id' put: (aJsonObject at: self idPropertyName).
aJsonObject removeKey: self idPropertyName ifAbsent: [ nil ].
^ aJsonObject"
"No need to normalize it"
]

{ #category : #reactions }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ MaplessStandalonePostgresPool >> currentClientDynamicVariable [
"Answers the class of the dynamic variable that will
hold the value of the current client during the evaluation of its usage."

^ PostgresCurrentClient
^ MaplessPostgresCurrentClient
]

{ #category : #accessing }
Expand Down
22 changes: 17 additions & 5 deletions src/Mapless-Redis-Core/MaplessRedisRepository.class.st
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Class {
#name : #MaplessRedisRepository,
#superclass : #MaplessRepository,
#category : #'Mapless-Redis-Core-Connections'
#category : #'Mapless-Redis-Core-Core'
}

{ #category : #actions }
Expand Down Expand Up @@ -133,13 +133,20 @@ MaplessRedisRepository >> makeMapless: aMaplessClass fromValue: storedValue with

{ #category : #accessing }
MaplessRedisRepository >> namespaced: propertyName of: aMapless [
^ aMapless maplessClassName , ':' , propertyName , ':'
, (aMapless data at: propertyName)
^ '{1}:{2}:{3}'
format:
{aMapless maplessClassName.
propertyName.
(aMapless data at: propertyName)}
]

{ #category : #accessing }
MaplessRedisRepository >> namespaced: propertyName of: aMaplessClass valued: aValue [
^ aMaplessClass name , ':' , propertyName , ':' , aValue
^ '{1}:{2}:{3}'
format:
{aMaplessClass name.
propertyName.
aValue}
]

{ #category : #accessing }
Expand All @@ -149,7 +156,12 @@ MaplessRedisRepository >> namespacedIdOf: aMapless [

{ #category : #accessing }
MaplessRedisRepository >> namespacedIdOf: aMaplessClass valued: aValue [
^ aMaplessClass name , ':id:' , aValue
^ self namespaced: 'id' of: aMaplessClass valued: aValue
]

{ #category : #actions }
MaplessRedisRepository >> normalizeIdOfOn: aJsonObject [
"No need to normalize it"
]

{ #category : #reactions }
Expand Down
13 changes: 0 additions & 13 deletions src/Mapless-Redis-Tests/ManifestMaplessRedisTests.class.st

This file was deleted.

Loading

0 comments on commit fdf3e86

Please sign in to comment.