 |
Anaristos Sorcerer
Joined: 17 Jul 2007 Posts: 821 Location: California
|
Posted: Thu Jul 01, 2010 10:01 pm
[321B] Question about db records with embedded lists (lists used as values). |
The following db record has an embedded string list:
| Code: |
$rec = "SetID=ss71|ResetID=""rs71|no71""|Sn=71" //%json() already applied. ($rec = %json($rec).1)
|
Now, if assign the value of key ResetID I get this:
| Code: |
$val = $rec.ResetID // $val = rs71|no71
|
While $val may look like a string list, it is in fact a unprocessed JSON value.
If I use #FORALL, it only finds one entry: rs71|no71
If I do this:
| Code: |
#FORALL %json($val) {....}
|
then everything is fine.
My question is: Must the script be aware that values in the db record are lists and do something special about them (i.e. invoke the %json() function on those values)?
It is not my intent to claim that this is not working properly, merely that it doesn't work as I would expect. I believe that this has to do with the embedded "|" character in the value. If the record looked like this (pre-%json()):
| Code: |
[{"SetID":"ss71", "ResetID":["rs71","no71"], "Sn":71}]
|
it would work, as a test would demonstrate. However, the problem with this is that it would also require special knowledge of CMUD data structures by both SQL (data was fetched from an SQLite database) and JSON. |
|
_________________ Sic itur ad astra. |
|
|
 |
Zugg MASTER

Joined: 25 Sep 2000 Posts: 23379 Location: Colorado, USA
|
Posted: Thu Jul 01, 2010 10:29 pm |
OK, I know you are getting the item from the database, but to prevent other people from being confused, you cannot do:
| Code: |
| $rec = "SetID=ss71|ResetID=""rs71|no71""|Sn=71" |
to assign a table in CMUD. The " quotes around this make it a literal string. The correct way to create this in CMUD is:
| Code: |
| $rec = {SetID=ss71|ResetID="rs71|no71"|Sn=71} |
and that will create the proper nested table.
So I think you need to look back in your original source to see how $rec is loaded in the first place. If the original $rec is coming from a data provider, then show us the original %json($rec) and then when you do
$rec = %json($rec).1
show us the new %json($rec).
I just did this as a test and it worked fine:
| Code: |
// simulate getting a string variable from the data provider in json format
$rec = "[{""SetID"":""ss71"", ""ResetID"":[""rs71"",""no71""], ""Sn"":71}]"
#SHOW %json($rec)
$rec = %json($rec).1
#SHOW %json($rec)
$val = $rec.ResetID
#SHOW %json($val)
#FORALL $val {#SHOW %i} |
This properly outputs two lines: rs71 and no71 just like it should.
You should NOT BE USING %json($val) in your #FORALL statement. $val is a proper string list, so just use #FORALL $val just like always.
Bottom line: You should normally never need the %json function. It is present for debugging purposes only. If you find yourself using %json in your own scripts to do anything except to print the underlying json table structure, then you are doing something wrong. It's ONLY OTHER USE is to create a list/table given a json value stored in a string variable. |
|
|
|
 |
Anaristos Sorcerer
Joined: 17 Jul 2007 Posts: 821 Location: California
|
Posted: Thu Jul 01, 2010 10:56 pm |
Here is the complete script:
| Code: |
<alias name="dnc" id="1570">
<value><![CDATA[#LOCAL $rec
;;
$table = "[Spells " + @username + "]"
;;
$sql1 = "SELECT [Name], [Sn], [Type], [TypeD] FROM " + $table + " WHERE [Sn] = ? OR lower([Name]) = ?"
$sql2 = "UPDATE " + $table + " SET [TypeD] = [TypeD] | " + @TypeFlagsD.isDoNotCast + " WHERE [Sn] = ?"
$sql3 = "SELECT * FROM [Spells Triggers] WHERE [Sn] = ?"
;;
#ECHO %cr
;;
#IF (%null( $spell)) {
#ECHO <color orange>SpellBot: </color><color white>No Sn/Spell/Skill specifed.</color>
#ECHO %cr
#EXIT
}
;;
$rec = @comsql.execute($sql1, %array( $spell, $spell))
;;
#IF (%null( $rec)) {
$kind = %if( %isnumber( $spell), "Sn", "Name")
#ECHO <color orange>SpellBot: </color><color white>No spell/skill found with that $kind.</color>
#ECHO %cr
#EXIT
}
;;
$rec = %json( $rec).1
;;
$kind = "Spell"
$name = $rec.Name
;;
#IF ( %bitand( $rec.Type, @TypeFlagsA.isSpell) = 0) {$kind = "Skill"}
;;
#IF (%bitand( $rec.Type, @TypeFlagsA.isSpellup) = 0) {
#ECHO <color orange>SpellBot: </color><color white>$kind <color><color yellow>$name</color><color white> is not of the spellup category.</color>
#ECHO %cr
#EXIT
}
;;
#IF (%bitand( $rec.TypeD, @TypeFlagsD.isDoNotCast) != 0) {
$kind = "Sn"
#IF (!%isnumber( $spell)) {$kind = "Name"}
#ECHO <color orange>SpellBot: </color><color white>$kind <color><color yellow>$name</color><color white> is already disabled.</color>
#ECHO %cr
#EXIT
}
;;
#CALL @comsql.Execute($sql2, %array( $rec.Sn)) //Set the DoNotCast flag in the database entry.
;;
$rec = @comsql.Execute($sql3, %array( $rec.Sn)) //Load the list of trigger IDs for this spell/skill.
;;
$rec = %json( $rec).1
;;
#FORALL %json( $rec.SetID) {#T- %i}
;;
#FORALL %json( $rec.ResetID) {#T- %i}
;;
#ECHO %cr
;;
#ECHO <color orange>SpellBot: </color><color white>$kind <color><color yellow>$name</color><color white> disabled.</color>
;;
#ECHO %cr]]></value>
<arglist>$spell</arglist>
<notes>This routine stops a spellup spell from being cast or a skill from being invoked.</notes>
</alias>
|
|
|
_________________ Sic itur ad astra. |
|
|
 |
Zugg MASTER

Joined: 25 Sep 2000 Posts: 23379 Location: Colorado, USA
|
Posted: Thu Jul 01, 2010 11:21 pm |
I didn't ask for the complete script. There is nothing I can do with it. What I asked is for you to put some "#SHOW %json($rec)" debugging lines in your code right after the @comsql.execute and then right after the "$rec = %json($rec).1" so that we can see the real data being returned from your database query.
|
|
|
|
 |
Anaristos Sorcerer
Joined: 17 Jul 2007 Posts: 821 Location: California
|
Posted: Fri Jul 02, 2010 2:16 am |
This is the raw record received from the data provider:
| Code: |
[{"SetID":"ss71", "ResetID":"rs71|no71", "Sn":71}]
|
The #SHOW right after the record fetch: (%json applied)
| Code: |
"SetID=ss71|ResetID=""rs71|no71""|Sn=71"
|
The #SHOW right after the data conversion: (%json($rec).1)
| Code: |
{"Sn":71,"ResetID":"rs71|no71","SetID":"ss71"}
|
As you can see the JSON parser sets "rs71|no71" as the value.
If the record were returned like this:
| Code: |
{"Sn":71,"ResetID":["rs71","no71"],"SetID":"ss71"}
|
then the value would be seen as a string list by CMUD. However, there is no reason for the parser to create the record that way. The "|" means nothing to it.
EDIT: I noticed the double double quotes, perhaps that is the problem. They assumption is that they are there to escape the string with the "|". However, I just checked my data provider code. I no longer escape strings containing "|"'s if I am generating JSON structures. |
|
_________________ Sic itur ad astra. |
|
|
 |
Zugg MASTER

Joined: 25 Sep 2000 Posts: 23379 Location: Colorado, USA
|
Posted: Fri Jul 02, 2010 2:46 am |
Right. In your very first line:
| Code: |
| [{"SetID":"ss71", "ResetID":"rs71|no71", "Sn":71}] |
that is WRONG. This JSON value sets the STRING "rs71|no71" as the value of the "ResetID" key. The proper JSON that you should be generating from your data provider should be this:
| Code: |
| [{"SetID":"ss71", "ResetID":["rs71","no71"], "Sn":71}] |
So CMUD is handling this exactly the way it is supposed to. The JSON parser has no clue what the "|" means in CMUD. Within JSON, "|" is just another character. If you want a nested string list, you need to use the proper JSON array syntax.
Bottom line: %json REQUIRES the proper JSON syntax. |
|
|
|
 |
Anaristos Sorcerer
Joined: 17 Jul 2007 Posts: 821 Location: California
|
Posted: Fri Jul 02, 2010 5:14 am |
I understand. I have to store the data in the database in JSON format. Makes sense.
|
|
_________________ Sic itur ad astra. |
|
|
 |
Anaristos Sorcerer
Joined: 17 Jul 2007 Posts: 821 Location: California
|
Posted: Wed Jul 07, 2010 10:27 pm |
OK, I've tried working with this as you suggested and it just won't work. The problem is that the JSON format is correct.
If I have a string list stored in a database column, when I fetch the value of that column I am going to get a string. There is no way for the JSON parser to know that it is a CMUD string list. So when the column is processed and sent to the script it is going to look as one would expect. Namely:
| Code: |
[{"SetID":"ss71", "ResetID":"rs71|no71", "Sn":71}]
|
The only way one would get this:
| Code: |
[{"SetID":"ss71", "ResetID":["rs71","no71"], "Sn":71}]
|
would be if either the data provider or the JSON parser knew what a CMUD string list looked liked and also knew that the requestor expected a CMUD string list to be read.
In the absence of such knowledge by those routines the first string above will be returned, in which case, in order to extract the string list one must do this:
| Code: |
#FORALL %json($rec.ResetID) {....}
|
It would be my pleasure to avoid using the function in such a way but I just can't see any way around it. |
|
_________________ Sic itur ad astra. |
|
|
 |
Zugg MASTER

Joined: 25 Sep 2000 Posts: 23379 Location: Colorado, USA
|
Posted: Wed Jul 07, 2010 10:46 pm |
Well of course JSON doesn't know anything about CMUD string list format. However, you wrote your own data provider in this case, so why can't you fix your data provider to convert string lists to the proper JSON array format?
Also, in your last example you don't need the %json function. What you want is the %list function which takes a string value and converts it to a proper string list. So it should be:
| Code: |
| #FORALL %list($rec.ResetID) {....} |
|
|
|
|
 |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
|