FYI, used a workaround:

TowergameDao >> findStateByAgent: anAgent
        | workaround |
        workaround := anAgent ifNotNil: [ ByteArray withAll: anAgent id ].
^ self glorpSession readOneOf: TgState where: [ :one | one agent id = workaround ]

But it is _ugly_ (though, it actually generates the same short SQL; it was RelationExpression >> condensePrimaryKeyComparison which inspired me to do this). I am sure one of the points of Glorp is to be able to write the original:

findStateByAgent: anAgent
^ self glorpSession readOneOf: TgState where: [ :one | one agent = anAgent ]

Is it true (should this work)?

Herby

Herby Vojčík wrote:
Esteban A. Maringolo wrote:
Do you have the code somewhere loadable? Reading chunk is something I
do only when everything crashed :D
Esteban A. Maringolo

I will attach the .st files... not loadable as its in private on-premise
git repo :-(

Thank you very much,

Herby

2017-08-14 13:44 GMT-03:00 Herby Vojčík<[email protected]>:
Hello!

I encountered a problem with OneToOneMapping and type coercion. When
writing
data, thing work; when reading data, the right child of relation
fails to
convert.

I tried everything possible to inject converters (even subclassing
GlorpBlobType), but to no avail. RelationExpression passes conversion
to its
left child:

convertedDbValueOf: anObject
"Assume that our types match, so we can ask either child to do the
conversion. That isn't guaranteed, but should at least work for the
common
cases."
^leftChild convertedDbValueOf: anObject.

but the left child is FieldExpression in case of OneToOneMapping, which:

convertedDbValueOf: anObject
"We don't do any conversion"
^anObject

What is strange, writing works (even the OneToOneMapping, I opened the
sqlite file with an explorer), but second SELECT, one using the relation
(`state := self dao findStateByAgent: agent` in clientSync), fails with
"GlorpDatabaseReadError: Could not coerce arguments". FWIW, the first
one
_does_ convert when creating bindings, as it uses MappingExpression
as left
child (stepped over it in debugger).



Is it meant to be a strange case that primary key is something
non-primitive
needing coercion (in this case, it is a UUID which needs coercion to
ByteArray, even if it is its subclass)?



Here's the stack of running the test which fails:

PharoDatabaseAccessor(DatabaseAccessor)>>handleError:for:
[ :ex | self handleError: ex for: command ] in [ | result |
self checkPermissionFor: command.
result := [ (self useBinding and: [ command useBinding ])
ifTrue: [ command executeBoundIn: self ]
ifFalse: [ command executeUnboundIn: self ] ]
on: Dialect error
do: [ :ex | self handleError: ex for: command ].
aBoolean
ifTrue: [ result ]
ifFalse: [ result upToEnd ] ] in
PharoDatabaseAccessor(DatabaseAccessor)>>executeCommand:returnCursor:
BlockClosure>>cull:
Context>>evaluateSignal:
Context>>handleSignal:
Error(Exception)>>signal
Error(Exception)>>signal:
ExternalLibraryFunction(Object)>>error:
ExternalLibraryFunction(Object)>>externalCallFailed
ExternalLibraryFunction(ExternalFunction)>>invokeWithArguments:
UDBCSQLite3Library>>apiBindBlob:atColumn:with:with:with:
UDBCSQLite3Library>>with:at:putBlob:
UDBCSQLite3Statement>>at:putByteArray:
UDBCSQLite3ResultSet>>execute:withIndex:withValue:
[ :v | i := self execute: statement withIndex: i withValue: v ] in
UDBCSQLite3ResultSet>>execute:withCollection:
OrderedCollection>>do:
UDBCSQLite3ResultSet>>execute:withCollection:
UDBCSQLite3ResultSet>>execute:with:on:
UDBCSQLite3Connection>>execute:with:
GlorpSQLite3Driver>>basicExecuteSQLString:binding:
PharoDatabaseAccessor>>executeCommandBound:
QuerySelectCommand(DatabaseCommand)>>executeBoundIn:
[ (self useBinding and: [ command useBinding ])
ifTrue: [ command executeBoundIn: self ]
ifFalse: [ command executeUnboundIn: self ] ] in [ | result |
self checkPermissionFor: command.
result := [ (self useBinding and: [ command useBinding ])
ifTrue: [ command executeBoundIn: self ]
ifFalse: [ command executeUnboundIn: self ] ]
on: Dialect error
do: [ :ex | self handleError: ex for: command ].
aBoolean
ifTrue: [ result ]
ifFalse: [ result upToEnd ] ] in
PharoDatabaseAccessor(DatabaseAccessor)>>executeCommand:returnCursor:
BlockClosure>>on:do:
[ | result |
self checkPermissionFor: command.
result := [ (self useBinding and: [ command useBinding ])
ifTrue: [ command executeBoundIn: self ]
ifFalse: [ command executeUnboundIn: self ] ]
on: Dialect error
do: [ :ex | self handleError: ex for: command ].
aBoolean
ifTrue: [ result ]
ifFalse: [ result upToEnd ] ] in
PharoDatabaseAccessor(DatabaseAccessor)>>executeCommand:returnCursor:
[ caught := true.
self wait.
blockValue := mutuallyExcludedBlock value ] in Semaphore>>critical:
BlockClosure>>ensure:
Semaphore>>critical:
PharoDatabaseAccessor(DatabaseAccessor)>>executeCommand:returnCursor:
[ session accessor executeCommand: command returnCursor: true ] in
SimpleQuery>>rowsFromDatabaseWithParameters:
BlockClosure>>on:do:
SimpleQuery>>rowsFromDatabaseWithParameters:
SimpleQuery(AbstractReadQuery)>>readFromDatabaseWithParameters:
SimpleQuery(AbstractReadQuery)>>executeWithParameters:in:
GlorpSession>>execute:
GlorpSession>>readOneOf:where:
TowergameDao>>findStateByAgent:
[ | agent state |
agent := self dao findAgentById: anObject agentId.
state := self dao findStateByAgent: agent.
^ NeoJSONObject new
agentId: agent id;
stateVersion: state version;
totalAnsweredQuestions:
(NeoJSONObject new
good: 0;
bad: 0;
yourself);
yourself ] in Towergame>>clientSync:
[ myUnitOfWork := self hasUnitOfWork not.
myUnitOfWork
ifTrue: [ self beginUnitOfWork ].
result := aBlock numArgs = 1
ifTrue: [ aBlock value: self ]
ifFalse: [ aBlock value ].
myUnitOfWork
ifTrue: [ self commitUnitOfWork ] ] in GlorpSession>>inUnitOfWorkDo:
BlockClosure>>ifCurtailed:
GlorpSession>>inUnitOfWorkDo:
TowergameDao>>inUnitOfWorkDo:
Towergame>>clientSync:
TowergameSyncTests>>testPlayerChecksStateVersion
TowergameSyncTests(TestCase)>>performTest
[ self setUp.
self performTest ] in TowergameSyncTests(TestCase)>>runCase
BlockClosure>>ensure:
TowergameSyncTests(TestCase)>>runCase
[ aTestCase runCase ] in [ [ aTestCase runCase ]
on: Halt
do: [ :halt |
"if test was halted we should resume all background failures
to debug all of them together with test process"
failedProcesses keysDo: #resume.
halt pass ] ] in
TestExecutionEnvironment>>runTestCaseSafelly:
BlockClosure>>on:do:
[ [ aTestCase runCase ]
on: Halt
do: [ :halt |
"if test was halted we should resume all background failures
to debug all of them together with test process"
failedProcesses keysDo: #resume.
halt pass ] ] in
TestExecutionEnvironment>>runTestCaseSafelly:
BlockClosure>>on:do:
TestExecutionEnvironment>>runTestCaseSafelly:
[ self runTestCaseSafelly: aTestCase ] in [ [ self runTestCaseSafelly:
aTestCase ]
ensure: [ testCompleted := true.
watchDogSemaphore signal ]. "signal that test case
completes"
self checkForkedProcesses ] in TestExecutionEnvironment>>runTestCase:
BlockClosure>>ensure:
[ [ self runTestCaseSafelly: aTestCase ]
ensure: [ testCompleted := true.
watchDogSemaphore signal ]. "signal that test case
completes"
self checkForkedProcesses ] in TestExecutionEnvironment>>runTestCase:
BlockClosure>>ifCurtailed:
TestExecutionEnvironment>>runTestCase:
[ testEnv runTestCase: aTestCase ] in
DefaultExecutionEnvironment>>runTestCase:
[ self value: anExecutionEnvironment.
anExecutionEnvironment activated.
aBlock value ] in CurrentExecutionEnvironment class>>activate:for:
BlockClosure>>ensure:
CurrentExecutionEnvironment class>>activate:for:
TestExecutionEnvironment(ExecutionEnvironment)>>beActiveDuring:
DefaultExecutionEnvironment>>runTestCase:
CurrentExecutionEnvironment class>>runTestCase:
TowergameSyncTests(TestCase)>>runCaseManaged
[ aTestCase announce: TestCaseStarted withResult: self.
aTestCase runCaseManaged.
aTestCase announce: TestCaseEnded withResult: self.
self addPass: aTestCase ] in TestResult>>runCaseForDebug:
BlockClosure>>on:do:
TestResult>>runCaseForDebug:
[ result runCaseForDebug: self ] in TowergameSyncTests(TestCase)>>debug
BlockClosure>>ensure:
TowergameSyncTests(TestCase)>>debug
[ :each |
each debug.
self announceTest: each.
self changed: each ] in [ self tests
do: [ :each |
each debug.
self announceTest: each.
self changed: each ] ] in TestSuite>>debug
OrderedCollection>>do:
[ self tests
do: [ :each |
each debug.
self announceTest: each.
self changed: each ] ] in TestSuite>>debug
BlockClosure>>ensure:
TestSuite>>debug
[ :aSuite | aSuite debug ] in TestRunner>>debugSuite:
BlockClosure>>cull:
BlockClosure>>cull:cull:
[ aBlock cull: aTestSuite cull: result ] in TestRunner>>executeSuite:as:
BlockClosure>>ensure:
TestRunner>>executeSuite:as:
TestRunner>>debugSuite:
TestRunner>>debug:
TestRunner>>errorSelected:
PluggableListMorph>>changeModelSelection:
PluggableListMorph>>mouseUpOnSingle:
PluggableListMorph>>mouseUp:
PluggableListMorph(Morph)>>handleMouseUp:
MouseButtonEvent>>sentTo:
PluggableListMorph(Morph)>>handleEvent:
MorphicEventDispatcher>>dispatchDefault:with:
MorphicEventDispatcher>>handleMouseUp:
MouseButtonEvent>>sentTo:
[ ^ anEvent sentTo: self ] in
MorphicEventDispatcher>>dispatchEvent:with:
BlockClosure>>ensure:
MorphicEventDispatcher>>dispatchEvent:with:
PluggableListMorph(Morph)>>processEvent:using:
PluggableListMorph(Morph)>>processEvent:
PluggableListMorph>>handleFocusEvent:
[ ActiveHand := self.
ActiveEvent := anEvent.
result := focusHolder
handleFocusEvent: (anEvent transformedBy: (focusHolder
transformedFrom: self)) ] in HandMorph>>sendFocusEvent:to:clear:
BlockClosure>>on:do:
WorldMorph(PasteUpMorph)>>becomeActiveDuring:
HandMorph>>sendFocusEvent:to:clear:
HandMorph>>sendEvent:focus:clear:
HandMorph>>sendMouseEvent:
HandMorph>>handleEvent:
HandMorph>>processEventsFromQueue:
HandMorph>>processEvents
[ :h |
self activeHand: h.
h processEvents.
self activeHand: nil ] in WorldState>>doOneCycleNowFor:
Array(SequenceableCollection)>>do:
WorldState>>handsDo:
WorldState>>doOneCycleNowFor:
WorldState>>doOneCycleFor:
WorldMorph>>doOneCycle
WorldMorph class>>doOneCycle
[ [ WorldMorph doOneCycle.
Processor yield.
false ] whileFalse: [ ] ] in MorphicUIManager>>spawnNewProcess
[ self value.
Processor terminateActive ] in BlockClosure>>newProcess







Reply via email to