Angular(2) ToH with Basex backend

Tuesday, 7 March 2017 · 5 messages · last reply 18 Mar 2017
RS
Rob Stapper7 Mar 2017 20:48 #
Hi, So finally I got the Tour of Heroes from the Angular(2) tutorial [1] working with BaseX as database backend. Everything works pretty well except for one thing: When adding a new record, Angular expects the backend (BaseX) to create an unique ID for the record and send it, together with the original, back to the angular-frontend [2]. In BaseX however, it is not possible to retrieve updated data from within the same transaction as the update of the database took place. The work around is to fetch the updated record outside the updating-transaction by means of a web:redirect to the link that retrieves a record [3]. This work around has two major disadvantages: 1. one can never be a 100% sure that the fetched data is exactly the data as it was stored in the base because updating and fetching are two separate transactions. 2. this only works if the records have a unique set of key fields. This doesn't always have to be the case. I've reported this situation a while ago and I wouldn't come back on it if the Angular-way of working didn't come up with the same situation. In my opinion BaseX would even be better equipped as database backend as it is if it was possible to fetch the updated date in the database from within the same transaction as the update took place. Is this something that could be considered for a future release? Cheers, Rob Stapper PS. I got this far thanks to the suggestions on CORS. [1] https://angular.io/docs/ts/latest/tutorial [2] https://angular.io/docs/ts/latest/tutorial/toh-pt6.html chapter: "Add a hero". [3] declare %rest:path("/product/save") %rest:POST("{ $parameterSet}") %updating function _:product.save ( $parameterSet as array(*) )
  {
( db:output( web:redirect( "/product/find" , map{ "code" : $parameterSet(2) } ) ) , dbx:save( $_:dataBase , $_:objectType , trace( $parameterSet(1), "objectID:" ) , product:new( $parameterSet(2) , $parameterSet(3) , $parameterSet(4) ) ) )
AB
Andy Bunce7 Mar 2017 22:30 #
Hi Rob, Good to hear you have solved the CORS problem.
Quoted text · Rob Stapper · 1 line
>In BaseX however, it is not possible to retrieve updated data from within
the same transaction as the update of the database took place. I think often this is not so much of a problem as it first appears because you know the data going into the transaction and the current state of the database and can use this data in db:output(), which will only run if the transaction succeeded. For the case of generating ids you might use increment a counter or generate a guid, in either case the computed value can be used in the db:output expression. I wrote a similar sounding project to yours basex-cellar [1] [2] using angular 1, (a slightly scary 5 years ago- it may have suffered some bit rot over the years ). An example of an update, in this case adding a wine to a cellar database is [3] /Andy [1] https://github.com/apb2006/basex-cellar [2] https://www.slideshare.net/AndyBunce/base-x-usergrouptalk [3] https://github.com/apb2006/basex-cellar/blob/master/src/cellar/api/cellar.xqm#L47
Quoted text · Rob Stapper · 107 lines
On 7 March 2017 at 19:48, Rob Stapper <r.stapper at lijbrandt.nl> wrote: > Hi, > > > > So finally I got the Tour of Heroes from the Angular(2) tutorial [1] > working with BaseX as database backend. > > Everything works pretty well except for one thing: When adding a new > record, Angular expects the backend (BaseX) to create an unique ID for the > record and send it, together with the original, back to the > angular-frontend [2]. > > > > In BaseX however, it is not possible to retrieve updated data from within > the same transaction as the update of the database took place. > > The work around is to fetch the updated record outside the > updating-transaction by means of a web:redirect to the link that retrieves > a record [3]. > > > > This work around has two major disadvantages: > > 1. one can never be a 100% sure that the fetched data is exactly the data > as it was stored in the base because updating and fetching are two separate > transactions. > > 2. this only works if the records have a unique set of key fields. This > doesn’t always have to be the case. > > > > I’ve reported this situation a while ago and I wouldn’t come back on it if > the Angular-way of working didn’t come up with the same situation. > > In my opinion BaseX would even be better equipped as database backend as > it is if it was possible to fetch the updated date in the database from > within the same transaction as the update took place. > > > > Is this something that could be considered for a future release? > > > > Cheers, > > Rob Stapper > > > > PS. I got this far thanks to the suggestions on CORS. > > > > [1] https://angular.io/docs/ts/latest/tutorial > > [2] https://angular.io/docs/ts/latest/tutorial/toh-pt6.html chapter: > “Add a hero”. > > [3] > > declare > > %rest:path("/product/save") > > %rest:POST("{ $parameterSet}") > > %updating > > function _:product.save > > ( $parameterSet as array(*) > > ) > > { > > ( db:output( web:redirect( "/product/find" > > , map{ "code" : $parameterSet(2) } > > ) > > ) > > , dbx:save( $_:dataBase > > , $_:objectType > > , trace( $parameterSet(1), "objectID:" ) > > , product:new( $parameterSet(2) > > , $parameterSet(3) > > , $parameterSet(4) > > ) > > ) > > ) >
R
r.stapper8 Mar 2017 09:43 #
Thanks Andy and Wray for your response. In my case the ID is generated at the backend as part of the transaction. Which I think is the proper place to do in a multi user environment. Fetching this ID within a db:output can only be done if my data has a unique key. This doesn't necessarily always be the case. Agreed; it is a pretty theoretical approach but if it makes theoretically sence. I could try to get the ID as a result of the transaction, probably need mixedupdates set, and use this whitin a db:output. cheers Rob PS. @ Andy, I needed OPTIONS in the REST-interface, which worked ;-) I'll have a look in your wine cellar.
Quoted text · Andy Bunce · 133 lines
Andy Bunce schreef op 07.03.2017 22:30: > Hi Rob, > > Good to hear you have solved the CORS problem. > >> In BaseX however, it is not possible to retrieve updated data from > within the same transaction as the update of the database took place. > > I think often this is not so much of a problem as it first appears > because you know the data going into the transaction and the current > state of the database and can use this data in db:output(), which will > only run if the transaction succeeded. > For the case of generating ids you might use increment a counter or > generate a guid, in either case the computed value can be used in the > db:output expression. > I wrote a similar sounding project to yours basex-cellar [1] [2] using > angular 1, (a slightly scary 5 years ago- it may have suffered some > bit rot over the years ). > > An example of an update, in this case adding a wine to a cellar > database is [3] > > /Andy > [1] https://github.com/apb2006/basex-cellar [3] > [2] https://www.slideshare.net/AndyBunce/base-x-usergrouptalk [4] > [3] > https://github.com/apb2006/basex-cellar/blob/master/src/cellar/api/cellar.xqm#L47 > [5] > > On 7 March 2017 at 19:48, Rob Stapper <r.stapper at lijbrandt.nl> wrote: > >> Hi, >> >> So finally I got the Tour of Heroes from the Angular(2) tutorial [1] >> working with BaseX as database backend. >> >> Everything works pretty well except for one thing: When adding a >> new record, Angular expects the backend (BaseX) to create an unique >> ID for the record and send it, together with the original, back to >> the angular-frontend [2]. >> >> In BaseX however, it is not possible to retrieve updated data from >> within the same transaction as the update of the database took >> place. >> >> The work around is to fetch the updated record outside the >> updating-transaction by means of a web:redirect to the link that >> retrieves a record [3]. >> >> This work around has two major disadvantages: >> >> 1. one can never be a 100% sure that the fetched data is exactly the >> data as it was stored in the base because updating and fetching are >> two separate transactions. >> >> 2. this only works if the records have a unique set of key fields. >> This doesn’t always have to be the case. >> >> I’ve reported this situation a while ago and I wouldn’t come >> back on it if the Angular-way of working didn’t come up with the >> same situation. >> >> In my opinion BaseX would even be better equipped as database >> backend as it is if it was possible to fetch the updated date in the >> database from within the same transaction as the update took place. >> >> Is this something that could be considered for a future release? >> >> Cheers, >> >> Rob Stapper >> >> PS. I got this far thanks to the suggestions on CORS. >> >> [1] https://angular.io/docs/ts/latest/tutorial [1] >> >> [2] https://angular.io/docs/ts/latest/tutorial/toh-pt6.html [2] >> chapter: “Add a hero”. >> >> [3] >> >> declare >> >> %rest:path("/product/save") >> >> %rest:POST("{ $parameterSet}") >> >> %updating >> >> function _:product.save >> >> ( $parameterSet as array(*) >> >> ) >> >> { >> >> ( db:output( web:redirect( "/product/find" >> >> , map{ "code" : $parameterSet(2) } >> >> ) >> >> ) >> >> , dbx:save( $_:dataBase >> >> , $_:objectType >> >> , trace( $parameterSet(1), "objectID:" ) >> >> , product:new( $parameterSet(2) >> >> , $parameterSet(3) >> >> , $parameterSet(4) >> >> ) >> >> ) >> >> ) > > > > Links: > ------ > [1] https://angular.io/docs/ts/latest/tutorial > [2] https://angular.io/docs/ts/latest/tutorial/toh-pt6.html > [3] https://github.com/apb2006/basex-cellar > [4] https://www.slideshare.net/AndyBunce/base-x-usergrouptalk > [5] > https://github.com/apb2006/basex-cellar/blob/master/src/cellar/api/cellar.xqm#L47
CG
Christian Grün11 Mar 2017 16:34 #
Hi Rob, Andy has already given you all relevant links. I am left with one question: What does your dbx:save function do? Is this the function that generates the ID? Christian
Quoted text · r.stapper · 159 lines
On Wed, Mar 8, 2017 at 9:43 AM, <r.stapper at lijbrandt.nl> wrote: > Thanks Andy and Wray for your response. > > In my case the ID is generated at the backend as part of the transaction. > Which I think is the proper place to do in a multi user environment. > Fetching this ID within a db:output can only be done if my data has a unique > key. This doesn't necessarily always be the case. > Agreed; it is a pretty theoretical approach but if it makes theoretically > sence. > > I could try to get the ID as a result of the transaction, probably need > mixedupdates set, and use this whitin a db:output. > > cheers > Rob > > PS. @ Andy, I needed OPTIONS in the REST-interface, which worked ;-) I'll > have a look in your wine cellar. > > > Andy Bunce schreef op 07.03.2017 22:30: >> >> Hi Rob, >> >> Good to hear you have solved the CORS problem. >> >>> In BaseX however, it is not possible to retrieve updated data from >> >> within the same transaction as the update of the database took place. >> >> I think often this is not so much of a problem as it first appears >> because you know the data going into the transaction and the current >> state of the database and can use this data in db:output(), which will >> only run if the transaction succeeded. >> For the case of generating ids you might use increment a counter or >> generate a guid, in either case the computed value can be used in the >> db:output expression. >> I wrote a similar sounding project to yours basex-cellar [1] [2] using >> angular 1, (a slightly scary 5 years ago- it may have suffered some >> bit rot over the years ). >> >> An example of an update, in this case adding a wine to a cellar >> database is [3] >> >> /Andy >> [1] https://github.com/apb2006/basex-cellar [3] >> [2] https://www.slideshare.net/AndyBunce/base-x-usergrouptalk [4] >> [3] >> >> https://github.com/apb2006/basex-cellar/blob/master/src/cellar/api/cellar.xqm#L47 >> [5] >> >> >> On 7 March 2017 at 19:48, Rob Stapper <r.stapper at lijbrandt.nl> wrote: >> >>> Hi, >>> >>> So finally I got the Tour of Heroes from the Angular(2) tutorial [1] >>> working with BaseX as database backend. >>> >>> Everything works pretty well except for one thing: When adding a >>> new record, Angular expects the backend (BaseX) to create an unique >>> ID for the record and send it, together with the original, back to >>> the angular-frontend [2]. >>> >>> In BaseX however, it is not possible to retrieve updated data from >>> within the same transaction as the update of the database took >>> place. >>> >>> The work around is to fetch the updated record outside the >>> updating-transaction by means of a web:redirect to the link that >>> retrieves a record [3]. >>> >>> This work around has two major disadvantages: >>> >>> 1. one can never be a 100% sure that the fetched data is exactly the >>> data as it was stored in the base because updating and fetching are >>> two separate transactions. >>> >>> 2. this only works if the records have a unique set of key fields. >>> This doesn’t always have to be the case. >>> >>> I’ve reported this situation a while ago and I wouldn’t come >>> back on it if the Angular-way of working didn’t come up with the >>> same situation. >>> >>> In my opinion BaseX would even be better equipped as database >>> backend as it is if it was possible to fetch the updated date in the >>> database from within the same transaction as the update took place. >>> >>> Is this something that could be considered for a future release? >>> >>> Cheers, >>> >>> Rob Stapper >>> >>> PS. I got this far thanks to the suggestions on CORS. >>> >>> [1] https://angular.io/docs/ts/latest/tutorial [1] >>> >>> [2] https://angular.io/docs/ts/latest/tutorial/toh-pt6.html [2] >>> chapter: “Add a hero”. >>> >>> [3] >>> >>> declare >>> >>> %rest:path("/product/save") >>> >>> %rest:POST("{ $parameterSet}") >>> >>> %updating >>> >>> function _:product.save >>> >>> ( $parameterSet as array(*) >>> >>> ) >>> >>> { >>> >>> ( db:output( web:redirect( "/product/find" >>> >>> , map{ "code" : $parameterSet(2) } >>> >>> ) >>> >>> ) >>> >>> , dbx:save( $_:dataBase >>> >>> , $_:objectType >>> >>> , trace( $parameterSet(1), "objectID:" ) >>> >>> , product:new( $parameterSet(2) >>> >>> , $parameterSet(3) >>> >>> , $parameterSet(4) >>> >>> ) >>> >>> ) >>> >>> ) >> >> >> >> >> Links: >> ------ >> [1] https://angular.io/docs/ts/latest/tutorial >> [2] https://angular.io/docs/ts/latest/tutorial/toh-pt6.html >> [3] https://github.com/apb2006/basex-cellar >> [4] https://www.slideshare.net/AndyBunce/base-x-usergrouptalk >> [5] >> >> https://github.com/apb2006/basex-cellar/blob/master/src/cellar/api/cellar.xqm#L47
RS
Rob Stapper18 Mar 2017 16:00 #
Hi Christian, Works like a charm. %output:media-type("application/json") did the trick. Thanks, Rob -----Oorspronkelijk bericht-----
Quoted text · Christian Grün · 72 lines
Van: Christian Grün [mailto:christian.gruen at gmail.com] Verzonden: vrijdag 17 maart 2017 15:48 Aan: Rob Stapper Onderwerp: Re: [basex-talk] Angular(2) ToH with Basex backend Hi Rob, > because of the use of a map:entry function. Maps and arrays are function items; this is the reason why they are currently not cached (they can contain nested function items, which refers to code that will not be available after execution). To solve this, just serialize your result via db:output(json:serialize(...)) and use %output:media-type("application/json"). Cheers, Christian PS: Better write to the mailing list, so that everyone else can follow our conversation. > > It would be nice if updating REST-function also are able to output > maps and arrays (transformed to JSON, ofcourse) > > [ 1] > declare > %rest:path("/{$dataBase}/{$objectType}") > %rest:POST("{ $dataRec}") > %input:json("format=map") > > %output:method("json") > %output:indent("no") > %updating > function _:dataRecord.create > ( $dataBase as xs:string > , $objectType as xs:string > , $dataRec as map(*) > ) > { > let $objectTable := objectTable:add( dbx:objectTable( $dataBase, > $objectType) > , object:new( $dataRec) > ) > let $result := map:entry( 'objectID', objectTable:objectID( > $objectTable)) > return ( dbx:flush( $dataBase > , $objectType > , $objectTable > ) > , db:output( ( _:responseHeader( ) > , $result > ) ) > ) > } ; > > > Christian Grün schreef op 17.03.2017 13:23: > >>> [1] example: ( not muti-user proof) >>> let $step1 := db:open('db', 'doc.xml') (: $step1/data/@id => i :) >>> let $step2 := $step1 update { replace value of node ./@id with ( 1 >>> + >>> ./@id)}) >>> (: multi-user gap :) >>> return ( >>> db:replace('db', 'doc.xml', $step2) >>> db:output( $step2/@id) >>> ) >> >> >> There won’t be a multi-user gap, because our transaction management >> (see http://docs.basex.org/wiki/Transaction_Management) and the >> execution via the Pending Update List will ensure that no other user >> will interfere. >> >> If you NEED to give other users the chance to update the replaced >> document in between, there will be no other chance to split your >> query into two separate steps. But I think there will be no reason to >> do that?

⚡Generated with XQuery