Parsing and converting JSON - delphi-10.3-rio

I have an issue with TJSONObject.ParseJSONValue or TJSONObject.toString
the following code does not display the JSON from Memo1 in Memo2, only an empty "{}":
A:=tJSONObject.Create;
A.ParseJSONValue(Memo1.Lines.Text);
Memo2.Lines.Text:=A.ToString;
What is wrong with it?

ParseJSONValue() is a class function of TJSONObject. It does not modify the TJSONObject that it is called on, like you are expecting. It returns a new TJSONValue, which will point to a TJSONObject if the JSON data represents a JSON object. You are ignoring that return value (and thus leaking it, as you need to call Free on it with you are done using it).
You need to change your code to something more like this:
var A: TJSONValue;
A := TJSONObject.ParseJSONValue(Memo1.Text);
if A <> nil then
try
Memo2.Text := A.ToString;
finally
A.Free;
end;

ParseJSONValue is a FUNCTION so it needs to be
A:=A.ParseJSONValue...
how stupid....

Related

How to insert a document if a filter returns nothing, otherwise replace the document found in mongodb with go?

I am not using the MGO package like in this example, just the active repo from here.
I am having a hard time reading the documentation. Basically, I have a bson.M object that I want to replace the current one, and if that one doesn't exist, insert it.
Currently my code looks like:
updateFilter := bson.D{{"from_symbol", fromSymbol}, {"to_symbol", strings.ToUpper(currency["to_symbol"].(string))}}
// The above seems to be correctly finding the documents I want
// currency is my bson.M object
_, err := collection.ReplaceOne(ctx, updateFilter, currency)
// However this line will not additionally insert if the object is not found, it is replacing fine
I'm sure I could manually run another query looking to see if the document exists, but that seems unnecessary.
Thank you!
EDIT:
It looks like there should be a way to do something with replaceOptions, see the documentation.
upsert := options.ReplaceOptions{Upsert: true}
_, err := collection.ReplaceOne(ctx, updateFilter, currency, upset)
However this gives me the error:
cannot use true (type bool) as type *bool in field value
Use the SetUpsert function:
collection.ReplaceOne(ctx,filter,newDoc,options.Replace().SetUpsert(true))

Validation error while trying to parse a json array to List[Object] in Scala

I have a method that returns a JsArray of a type Foo.
To process the response, I am doing the following:
val foos : List[Foo] = Json.toJson(result).as[List[Foo]]
While debugging, I could see that the result is comming as:
"[]"
and it is generated by the code:
Ok(Json.toJson(foos))
Where foos is a List[Foo]
But I am getting the error:
[JsResultException: JsResultException(errors:List((,List(ValidationError(error.expected.jsarray,WrappedArray())))))]
I've tried many ways, but can't solve this.
What I am doing wrong?
You're most likely looking for Json.parse, rather than Json.toJson.
import play.api.libs.json.Json
scala> Json.toJson("[]")
res0: play.api.libs.json.JsValue = "[]"
scala> Json.parse("[]")
res1: play.api.libs.json.JsValue = []
Trying to convert res0 to a List[Foo] doesn't work because you're trying to convert the string "[]" rather than than the same string without quotation marks, [].
It seems like you have it the wrong way around. Json.toJson(value) is used to convert from a Scala object to a JSON value. You are using it incorrectly to try and read a JSON body and convert it to a Scala object. You probably want to do something like this:
val foos : JsResult[List[Foo]] = result.validate[List[Foo]]
where result is your JSON value.
Look at this, under the 'JsValue to a model' section:
https://www.playframework.com/documentation/2.6.x/ScalaJson

Storing values obtained from for each loop Scala

Scala beginner who is trying to store values obtains in a Scala foreach loop but failing miserably.
The basic foreach loop looks like this currently:
order.orderList.foreach((x: OrderRef) => {
val references = x.ref}))
When run this foreach loop will execute twice and return a reference each time. I'm trying to capture the reference value it returns on each run (so two references in either a list or array form so I can access these values later)
I'm really confused about how to go about doing this...
I attempted to retrieve and store the values as an array but when ran, the array list doesn't seem to hold any values.
This was my attempt:
val newArray = Array(order.orderList.foreach((x: OrderRef) => {
val references = x.ref
}))
println(newArray)
Any advice would be much appreciated. If there is a better way to achieve this, please share. Thanks
Use map instead of foreach
order.orderList.map((x: OrderRef) => {x.ref}))
Also val references = x.ref doesn't return anything. It create new local variable and assign value to it.
Agree with answer 1, and I believe the reason is below:
Return of 'foreach' or 'for' should be 'Unit', and 'map' is an with an changed type result like example below:
def map[B](f: (A) ⇒ B): Array[B]
Compare To for and foreach, the prototype should be like this
def foreach(f: (A) ⇒ Unit): Unit
So If you wanna to get an changed data which is maped from your source data, considering more about functions like map, flatMap, and these functions will traverse all datas like for and foreach(except with yield), but with return values.

Access $firebaseObject value with variable instead of string

I need to assign a variable to a string and pass that variable to a Firebase query in a $firebaseObject. But, when I try this, the firebaseObject is null. I tried with directly putting the string in and it works, but I don't want that.
Code:
//var itemkey='-JyO7Zsgsucf5ESttJwt';
var itemkey=window.localStorage['fbid'];-------> string: '-JyO7Zsgsucf5ESttJwt'
console.log(typeof itemkey); ------------------> string
$scope.galphoto = $firebaseObject(ref.child(itemkey));
console.log($scope.galphoto) ------------------> null
When I call
$scope.galphoto = $firebaseObject(ref.child(itemkey));
With itemkey='-JyO7Zsgsucf5ESttJwt',
then console.log($scope.galphoto) is properly shown. However, when I use what I really want to use,
window.localStorage['fbid']
then console.log($scope.galphoto) is null.
Why?
I think you may be trying to console.log the result before it's available. $firebaseObject returns the data with some delay. You may try to do something like
$scope.galphoto = $firebaseObject(ref.child(itemkey));
$scope.galphoto.$loaded().then(function () {
console.log($scope.galphoto);
}
You should see the expected result, since you're waiting for the promise to respond. It could help you better understand how to get the desired result.

DELPHI class with dynamic array has problem with SetLength()

I need to create a class containing an array of record objects but trying to use SetLength raise an Access Violation errror.
Consider the following example of a tree object with fruits.
type
TFruit = record
color: string;
weight: double;
end;
type
TObjectTree = class
Public
Fruits: array of TFruit;
constructor Create;
procedure AddFruit;
end;
In the implementation, when trying to resize the array of Fruit objects or initializing to nil generates problems.
constructor TObjectTree.Create;
begin
inherited Create;
Fruits:=nil; //Raises an error
end;
procedure TObjectTree.AddFruit(FruitColor: string; FruitWeight: integer);
begin
SetLength(Fruits, Length(Fruits)+1); //Raises an error (when I comment Fruits:=nil; in the constructor)
Fruits[Length(Fruits)].color:=FruitColor;
Fruits[Length(Fruits)].weight:=FruitWeight;
end;
How can I use dynamic arrays in a class?
Replace
Fruits[Length(Fruits)].color:=FruitColor;
Fruits[Length(Fruits)].weight:=FruitWeight;
with
Fruits[High(Fruits)].color:=FruitColor;
Fruits[High(Fruits)].weight:=FruitWeight;
then it works.
Something tells me you've neglected to create an instance of TObjectTree. You've declared a TObjectTree variable, but you've either not called TObjectTree.Create, or you've called it directly on the variable you declared instead of assigning a new value to that variable:
var
Tree: TObjectTree;
begin
// This is wrong.
Tree.Create;
// This is right.
Tree := TObjectTree.Create;
Without properly instantiating TObjectTree, there is no valid memory to back the Fruits field you attempt to use, so assigning a value to it gives an error.
As an addition to the answers of iamjoosy and Rob Kennedy, I would code this like so:
procedure TObjectTree.AddFruit(FruitColor: string; FruitWeight: integer);
var
NewCount: Integer;
begin
NewCount := Length(Fruits)+1;
SetLength(Fruits, NewCount);
Fruits[NewCount-1].color := FruitColor;
Fruits[NewCount-1].weight := FruitWeight;
end;
It is clearer, in my view, to call Length() just once.
You do not need to assign Fruits := nil in the constructor since that happens automatically. All fields are zero-initialised when an object is instantiated. That said, Fruits := nil should not raise an error. If it does it is probably a result of a memory corruption due to the out-of-bounds array accessing.
A further point to make is that enabling range checking would have resulted in an informative error that would have explained the problem. This is much more helpful than relying on access violations. I can't recommend range checking highly enough.
Finally, the SetLength(..., Length(...)+1) pattern typically leads to very inefficient memory usage and can lead to performance problems for large lists. If you have Delphi 2009+, I would recommend using TList<TFruit> instead.

Resources