How to get all properties with the ids - kotlin

I'm new to all the graph database stuff and I'm having a hard time with some basic queries.
I'm using Gremlin with Kotlin to connect to AWS Neptune.
I want to get all my vertex properties including the Id.
I have added an vertex with:
g.addV("foo")
.property("name", "Foo 1")
.next()
And to retrieve the properties I have tried:
g.V()
.hasLabel("foo")
.valueMap<String>()
.by(unfold<String>())
.forEach {
// val name = it["name"] -> works great!
// val id = it["id"] -> doesn't exist
}
In this first approach I get a map for each item but this map does not contain the ID.
g.V()
.hasLabel("foo")
.forEach {
// it is an ReferenceVertex that has an ID!
val name = it.property<String>("name") // This returns an EmptyVertexProperty, so I can't read the name
}
I'm using
<dependency>
<groupId>org.apache.tinkerpop</groupId>
<artifactId>gremlin-driver</artifactId>
<version>3.4.4</version>
</dependency>
Bonus question
I couldn't figure out (nor find in the documentation) what the generics on valueMap and unfold method do. Kotlin does not allow me to ommit them (as I have seem in some java code...?), but changing them to Int, for instance, changes nothing in the outcome for these examples... So what is it for? D:
Thanks in advance!

If you want to get the Id with all the other properties you need to run valueMap().with(WithOptions.tokens) or you can use elementMap().

Related

Kotlin Java streams - map Selenium WebElement(s) to List

I'm struggling a bit with a pretty simple case of mapping a list of Selenium WebElements to a List of classes using Java Streams.
The element:
val elements: List<WebElement> = element.findElements(By.cssSelector("[data-e2e-selector=expense]"))
(Currently, there are only two elements in the list.)
I'm currently mapping the WebElement list to a MutableList of classes the "classic way":
val expenseElements: MutableList<ExpenseElement> = ArrayList()
for (element in elements) {
expenseElements += ExpenseElement(element)
}
Which is working fine. But I feel I should learn to use Stram() to do this more "elegantly". Or, at least, because I want to :-)
But my feeble attempt at using Stream()
val expenseElements = elements.stream().map { UtgiftElement(element) }.collect(Collectors.toList())
results in only the first element being included. So the first elements takes up both places in the the list.
The first method:
expenseElements[0].expense() = "Entry 1"
expenseElements[1].expense() = "Entry 2"
The non-working Stream() method:
expenseElements[0].expense() = "Entry 1"
expenseElements[1].expense() = "Entry 1"
This is basic I know, but I've tried replicating code that does the same in Java. I have to start somewhere.
There's a mistake in your mapping lambda. You do:
map { UtgiftElement(element) }
But that is not correct. The map function provides you with a single input, named it by default. Your lambda should either by map { UtgiftElement(it) } or map { element -> UtgiftElement(element) }.
I do not know where your element variable comes from, but I think it is not one of the elements in the stream.

Extracting Nested POJO Object with Rest-Assured

I'm writing some tests using rest-assured and its Kotlin extensions to test some simple Spring MVC endpoints. I'm trying to understand how to extract values.
One endpoint returns a BookDetailsView POJO, the other returns a Page<BookDetailsView> (where Page is an interface provided by Spring for doing paging).
BookDetailsView is a really simple Kotlin data class with a single field:
data class BookDetailsView(val id: UUID)
For the single object endpoint, I have:
#Test
fun `single object`() {
val details = BookDetailsView(UUID.randomUUID())
whenever(bookDetailsService.getBookDetails(details.id)).thenReturn(details)
val result: BookDetailsView = Given {
mockMvc(mockMvc)
} When {
get("/book_details/${details.id}")
} Then {
statusCode(HttpStatus.SC_OK)
} Extract {
`as`(BookDetailsView::class.java)
}
assertEquals(details.id, result.id)
}
This works as expected, but trying to apply the same technique for the Page<BookDetailsView> runs afoul of all sorts of parsing challenges since Page is an interface, and even trying to use PageImpl isn't entirely straightforward. In the end, I don't even really care about the Page object, I just care about the nested list of POJOs inside it.
I've tried various permutations like the code below to just grab the bit I care about:
#Test
fun `extract nested`() {
val page = PageImpl(listOf(
BookDetailsView(UUID.randomUUID())
))
whenever(bookDetailsService.getBookDetailsPaged(any())).thenReturn(page)
val response = Given {
mockMvc(mockMvc)
} When {
get("/book_details")
} Then {
statusCode(HttpStatus.SC_OK)
body("content.size()", `is`(1))
body("content[0].id", equalTo(page.first().id.toString()))
} Extract {
path<List<BookDetailsView>>("content")
}
println(response[0].javaClass)
}
The final println spits out class java.util.LinkedHashMap. If instead I try to actually use the object, I get class java.util.LinkedHashMap cannot be cast to class BookDetailsView. There are lots of questions and answers related to this, and I understand it's ultimately an issue of the underlying JSON parser not knowing what to do, but I'm not clear on:
Why does the "simple" case parse without issue?
Shouldn't the type param passed to the path() function tell it what type to use?
What needs configuring to make the second case work, OR
Is there some other approach for grabbing a nested object that would make more sense?
Digging a bit into the code, it appears that the two cases may actually be using different json parsers/configurations (the former seems to stick to rest-assured JSON parsing, while the latter ends up in JsonPath's?)
I don't know kotlin but here is the thing:
path() doesn't know the Element in your List, so it'll be LinkedHashMap by default instead of BookDetailsView.class
to overcome it, you can provide TypeReference for this.
java example
List<BookDetailsView> response = ....then()
.extract().jsonPath()
.getObject("content", new TypeRef<List<BookDetailsView>>() {});
kotlin example
#Test
fun `extract nested`() {
var response = RestAssured.given().get("http://localhost:8000/req1")
.then()
.extract()
.jsonPath()
.getObject("content", object : TypeRef<List<BookDetailsView?>?>() {});
println(response)
//[{id=1}, {id=2}]
}

(Problem solved) Set the value of a livedata variable of type <data class> to a list of strings?

How to populate the value of this variable:
private val _urlList = MutableLiveData<List<Url>>()
of type Url:
data class Url(
val imgSrcUrl: String
)
with the incoming list of url strings from a firebase call?
Here is where the magic happens:
private fun getData(){
viewModelScope.launch {
try {
getImagesUrl {
"Here where I need to set the value of the variable to a listOf(it) with it being strings
of urls retrieved from firebase storage"
}
}catch (e: Exception){
"Handling the error"
}
}
}
Edit
The map function #dominicoder provided solved my problem, answer accepted.
Thank you all for your help
Your question is unclear because you're showing a live data of a single Url object but asking to stuff it with a list of strings. So first, your live data object needs to change to a list of Urls:
private val _urlList = MutableLiveData<List<Url>>()
Then, assuming getImagesUrl yields a list of strings, if I understood you correctly, then you would map that to a list of Urls:
getImagesUrl { listOfImageUrlStrings ->
_urlList.value = listOfImageUrlStrings.map { imageUrlString -> Url(imageUrlString) }
}
If that does not answer your question, you really need to review it and clarify.
You can set values on the MutableLiveDataObject in two ways (depends on what you're doing).
Setting the value as normal from the UI thread can be done with:
myLiveData.value = myobject
If you're setting it from a background thread like you might in a coroutine with a suspended function or async task etc then use:
myLiveData.postValue(myObject)
It's not clear from your question whether the LiveData is meant to hold a list as you mention both lists and single values. But your LiveData holds a set the values as a collection like a list, set or map. It's can be treated as a whole object so adding a value later needs to have the whole collection set again like:
myLiveData.value = mutableListOf<Url>()
//Response received and object created
myLiveData.value = myLiveData.value.apply {
add(myObject)
}
Or if the value is mutable updating the existing value (preferred as it's cleaner):
myLiveData.value.add(myObject)
The problem with that approach is you're exposing the map as a mutable/writeable object. Allowing accessors to change the values which you might not want.

adding to a list that is contained in livedata and adding elements to that list

adding to a list that is contained in livedata and adding elements to that list
val resourcesLiveData by lazy { MutableLiveData<List<File>>() }
I thought this should work as my LiveData is a list of files and I just want to add elements to it. But the value of live data is always an empty list. The res is the different file resources I am trying to add
resourceLiveData.value?.toMutableList()?.add(res)
So I tried it more expicity using this version but the list is still empty
val listOfRes = resourceLiveData.value ?: emptyList()
listOfRes.toMutableList().add(res)
resourceLiveData.value = listOfRes.toList()
Can anyone see if I am doing something wrong.
Just want to add to the list that is contained in the value
Agree to #KeyserSoze answer, if you have to use only List then you can do below
resourceLiveData.value = resourceLiveData.value?.toMutableList()?.apply { add(res) }?: emptyList()
You are creating a new object by calling toMutableList() instead of updating the original.
Change your LiveData type to MutableList:
val resourcesLiveData by lazy { MutableLiveData<MutableList<File>>() }
Then, update the value accordingly:
resourceLiveData.value?.add(res)

f# - how to serialize option and DU as value or null (preferably with json.net)

How can i get my json from web api to format only value or null for Option types and Discriminated Unions preferably using Newtonsoft.
I am currently using Newtonsoft and only have to add this to web api for it to work:
config.Formatters.JsonFormatter.SerializerSettings <- new JsonSerializerSettings()
When i consume the data on my side, i can easily convert it back to an F# item using: JsonConvert.DeserializeObject<'a>(json)
The api will be consumed by NON .NET clients as well so i would like a more standard formatted json result.
I would like to to fix my issue, w/o having to add code or decorators to all of my records/DU in order for it to work. I have lots of records with lots of properties, some are Option.
ex (this is how DU is serializing):
// When value
"animal": {
"case": "Dog"
}
// When no value
"animal": null
This is what I need:
// When value
"animal": "Dog"
// When no value
"animal": null
This is how an Option type is serializing:
"DocumentInfo": {
"case": "Some",
"fields": [
{
"docId": "77fb9dd0-bfbe-42e0-9d29-d5b1f5f0a9f7",
"docType": "Monkey Business",
"docName": "mb.doc",
"docContent": "why cant it just give me the values?"
}
]
}
This is what I need:
"DocumentInfo": {
"docId": "77fb9dd0-bfbe-42e0-9d29-d5b1f5f0a9f7",
"docType": "Monkey Business",
"docName": "mb.doc",
"docContent": "why cant it just give me the values?"
}
Thank you :-)
You could try using Chiron. I haven't used it myself so I can't give you an extensive example, but https://neoeinstein.github.io/blog/2015/12-13-chiron-json-ducks-monads/index.html has some bits of sample code. (And see https://neoeinstein.github.io/blog/2016/04-02-chiron-computation-expressions/index.html as well for some nicer syntax). Basically, Chiron knows how to serialize and deserialize the basic F# types (strings, numbers, options, etc.) already, and you can teach it to serialize any other type by providing that type with two static methods, ToJson and FromJson:
static member ToJson (x:DocumentInfo) = json {
do! Json.write "docId" x.docId
do! Json.write "docType" x.docType
do! Json.write "docName" x.docName
do! Json.write "docContent" x.docContent
}
static member FromJson (_:DocumentInfo) = json {
let! i = Json.read "docId"
let! t = Json.read "docType"
let! n = Json.read "docName"
let! c = Json.read "docContent"
return { docId = i; docType = t; docName = n; docContent = c }
}
By providing those two static methods on your DocumentInfo type, Chiron will automatically know how to serialize a DocumentInfo option. At least, that's my understanding -- but the Chiron documentation is sadly lacking (by which I mean literally lacking: it hasn't been written yet), so I haven't really used it myself. So this may or may not be the answer you need, but hopefully it'll be of some help to you even if you don't end up using it.
I have found the solution that allows me to use Newtonsoft (JSON.NET), apply custom converters for my types where needed and not require any changes to my DU's or Records.
The short answer is, create a custom converter for Json.Net and use the Read/Write Json overrides:
type CustomDuConverter() =
inherit JsonConverter() (...)
Unfortunately the ones I have found online that were already created doesn't work as is for my needs listed above, but will with slight modification. A great example is to look at: https://gist.github.com/isaacabraham/ba679f285bfd15d2f53e
To apply your custom serializer in Web Api for every call, use:
config.Formatters.JsonFormatter.SerializerSettings.Converters.Add(new CustomDuConverter())
To deserialize use (example that will deserialize to DU):
JsonConvert.DeserializeObject<Animal>("Dog", customConverter)
ex:
type Animal = Dog | Cat
json:
"animal": "Dog"
This will allow you to create a clean Api for consumers and allow you to consume 3rd party Json data into your types that use Option, etc.