How to query the additional column (other than siblings) added to pivot table? - swift

Here is my RecipeIngredientPivot table schema to which I added an addition quantity column.
-----------------------------------------------------
id | ingredientID | recipeID | quantity
-----------------------------------------------------
| 1 | A001 | R001 | 100 |
| 2 | A002 | R001 | 50 |
| 3 | C004 | R001 | 23 |
| 4 | A001 | R002 | 75 |
I was able to create a quantity column to the Pivot table which has the ingredient_id and recipe_id as siblings by only using Pivot instead of ModifiablePivot.
extension RecipeIngredientPivot: Pivot {
init(_ recipe: Recipe, _ ingredient: Ingredient, _ quantity: Double) throws {
self.recipeID = try recipe.requireID()
self.ingredientID = try ingredient.requireID()
self.quantity = quantity
}
}
However, I am not sure how to query and get quantities of a recipe.
extension Recipe {
var ingredients: Siblings<Recipe, Ingredient, RecipeIngredientPivot> {
return siblings()
}
var quantities: [Double] {
// Not sure how to get this.
}
}
Any help is much appreciated.

I figured it out. I had to do query(on.req) & pivot(on: req) on the siblings() and wait for both to complete successfully before mapping on the results.
let ingredientFuture = try recipe.ingredients.query(on: req).all()
let pivotFuture = try recipe.ingredients.pivots(on: req).all()
return ingredientFuture.and(pivotFuture).map { ingredients, pivots in
for (ingredient,pivot) in zip(ingredients, pivots) {
print("\(ingredient) - \(pivot.quantity)")
}
}

Related

What is the beat way to solve "mutable borrow occurs here" in this situation?

I am a beginner in rust.
I know what happened, spend a whole afternoon to try, and finally, could not find any solution...
Need help from kind people T_T
use kafka::client::{FetchOffset, GroupOffsetStorage, KafkaClient};
fn main() {
let mut client = KafkaClient::new(vec!["localhost:9092".to_owned()]);
client.load_metadata_all().unwrap();
client.set_group_offset_storage(GroupOffsetStorage::Kafka);
for topic in client.topics().names() {
let topic_offsets = client.fetch_topic_offsets(topic, FetchOffset::Latest).unwrap();
println!("{:?}", topic_offsets);
let group_topic_offsets = client.fetch_group_topic_offsets("test", topic).unwrap();
println!("{:?}", group_topic_offsets);
for (partition_index, tp_offset) in topic_offsets.iter().enumerate() {
println!("partition {}'s lag = {}", partition_index, tp_offset.offset - group_topic_offsets[partition_index].offset)
}
}
}
error[E0502]: cannot borrow `client` as mutable because it is also borrowed as immutable
--> src/main.rs:11:31
|
7 | for topic in &mut client.topics().names() {
| ----------------------------
| | |
| | immutable borrow occurs here
| immutable borrow later used here
...
11 | let group_topic_offsets = client.fetch_group_topic_offsets("test", topic).unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
error: aborting due to 2 previous errors

Tabular Data to Nested JSON

I am trying to convert tabular query output to nested JSON using MuleSoft. My query output is like below:
----------------------------------
Customer | Order | Items
----------------------------------
C | Order1 | Itm1
C | Order1 | Itm2
C | Order2 | Itm1
C | Order2 | Itm4
C | Order3 | Itm3
C | Order3 | Itm4
and using Mule4 dataweave I am trying to convert it in flowing JSON output:
Customer: C
Orders: {
Order1:{
Items: {
Item: Item1
Item: Item2
}
}
Order2:{
Items: {
Item: Item1
Item: Item4
}
}
Order3:
}
So far I have tried code like below with no luck:
%dw 2.0
output application/json
---
payload map ((st, stindex) -> {
Customer: st.Customer,
Orders: payload filter(($.Customer == st.Customer) and ($.Order == st.Order)) map ((f, fIndex) ->{
Order: f.Order
Items : payload filter (($.ItemName == f.ItemName) and ($.Order == f.Order)) map ((i, iIndex) -> {
item: i.ItemName
})
})
})
it seems I am missing something important. Appreciate your help!!
I needed a multilevel groupBy(), mapObjects and a reduce() for the item.
%dw 2.0
output application/json
---
(payload map {
Customer: $.Customer,
Order: $.Order,
Items: $.Items
} groupBy (item) -> item.Customer)
mapObject ((value, key, index) -> {
Customer : key,
Orders: (value groupBy (orders)->orders.Order)
mapObject ((value1, key1, index1) -> {
"$(key1)": value1 reduce ((item, accumulator={}) -> accumulator ++ {Item: item.Items} )
}
)
}
)
Output:
{
"Customer": "C",
"Orders": {
"Order2": {
"Item": "Itm1",
"Item": "Itm4"
},
"Order1": {
"Item": "Itm1",
"Item": "Itm2"
},
"Order3": {
"Item": "Itm3",
"Item": "Itm4"
}
}
}
The indenting of the script is bad but it is too late for me to fix it.

How to group Postgres data correctly

In PostgreSQL, I have such table:
| QUESTION_TEXT | CATEGORY | AGREE_PERCENT | DISAGREE_PERCENT |
|----------------------------------------|----------|---------------|------------------|
| Do you support the President's policy? | Policy | 50 | 50 |
| Do you support Democrats? | Policy | 32 | 68 |
| Do you support the Lannisters? | Cinema | 45 | 55 |
| Do you support Spielberg's work? | Cinema | 60 | 40 |
In my Go application with the help of gorm library I make SQL request to PostgreSQL database like that:
type Entry struct {
QuestionText string `json:"question_text"`
Category string `json:"category"`
AgreePercent float64 `json:"agree_percent"`
DisagreePercent float64 `json:"disagree_percent"`
}
rows, _ := database.DBGORM.Raw("SELECT * FROM SPECIFICATION").Rows()
for rows.Next() {
entry := &Entry{}
if err = rows.Scan(&entry.QuestionText, & entry.Category, &entry.AgreePercent, &entry.DisagreePercent); err != nil {
utils.Logger().Println(err)
}
}
How to get a similar result? As you can see each object inside the array is grouped by value in the category column:
[
{
category: "Policy",
questions: ["Do you support the President's policy?", "Do you support Democrats?"],
series: [
{
name: "Agree, %",
data: [50, 32]
},
{
name: "Disagree, %",
data: [50, 68]
},
]
},
{
category: "Cinema",
questions: ["Do you support the Lannisters?", "Do you support Spielberg's work?"],
series: [
{
name: "Agree, %",
data: [45, 60]
},
{
name: "Disagree, %",
data: [55, 40]
},
]
},
]
Well, I can't say that it's elegant way, but finally I solve my task:
// Create struct called "Series".
type Series struct {
Name string `json:"name"`
Data []float64 `json:"data"`
}
// Create struct called "Specification".
type Specification struct {
Category string `json:"category"`
Questions []string `json:"questions"`
Series []Series `json:"series"`
}
// Initialize an array of struct.
var specifications []Specification
// Initialize several variables.
var catogoryName string
var arrayQuestionText []string
var arrayAgreePercent []float64
var arrayDisagreePercent []float64
for rows.Next() {
// Check the change in the name of the category.
if entry.Category == catogoryName {
// Add new elements to arrays.
arrayQuestionText = append(arrayQuestionText, entry.QuestionText)
arrayDisagreePercent = append(arrayDisagreePercent, entry.DisagreePercent)
arrayAgreePercent = append(arrayAgreePercent, entry.AgreePercent)
} else {
if len(catogoryName) > 0 {
// Fill the struct with data.
specification := Specification{
Category: catogoryName,
Questions: arrayQuestionText,
Series: []Series{
{
Name: "Agree, %",
Data: arrayAgreePercent,
},
{
Name: "Disagree, %",
Data: arrayDisagreePercent,
},
},
}
// Add new struct to array.
specifications = append(specifications, specification)
}
}
// Update data in arrays.
catogoryName = entry.Category
arrayQuestionText = nil
arrayQuestionText = append(arrayQuestionText, entry.QuestionText)
arrayDisagreePercent = nil
arrayDisagreePercent = append(arrayDisagreePercent, entry.DisagreePercent)
arrayAgreePercent = nil
arrayAgreePercent = append(arrayAgreePercent, entry.AgreePercent)
}

Swift4 displaying Parser result in an NSOutlineView

I wrote a TLV parser that returns results like the following tag length value:
<e1> 53 <9f1e0831 36303231 343337ef…>
<9f1e> 8 <31363032 31343337>
<ef> 18 <df0d084d 3030302d 4d5049df 7f04312d 3232>
<df0d> 8 <4d303030 2d4d5049>
<df7f> 4 <312d3232>
<ef> 20 <df0d0b4d 3030302d 54455354 4f53df7f 03362d35>
<df0d> 11 <4d303030 2d544553 544f53>
<df7f> 3 <362d35>
I want to display this in an OutlineView, but I'm not familiar how the store object should look like and how to fill it up. Somehow it needs to be something like below:
class Node: NSObject {
var isConstructed = false
var tag = „Tag“
var length = 0
var value = „Value“
var children = [Node]()
weak var parent: Node?
override init() {
super.init()
}
init(tag: String) {
self.tag = tag
}
init(length: Int) {
self.length = length
}
init(value: String) {
self.value = value
}
init(isConstructed: Bool) {
self.isConstructed = isConstructed
}
func isLeaf() -> Bool {
return children.isEmpty
}
}
The TLV parser demo
TLVparser
Should look like this:
TLV parse result in NSOutlineView
Finally got some time to work on this question today. Putting this on an NSOutlineView is the easy part. The hard part is to define a data model for your TLV data and parse the Data into it.
TLVNode.swift
This class stores the TLV data. Your code looks like converted C and then it's not very good C either.
import Foundation
// Since we use Cocoa Bindings, all properties need to be
// dynamically dispatch hence #objCMembers declaration
// Its ability to handle erroneous data is not tested. That
// is left for the OP as an exercise.
#objcMembers class TLVNode: NSObject {
var tag: Data
var length: Int
var value: Data
var isConstructed: Bool
var children = [TLVNode]()
// Convert `tag` from Data to a string of hex for display
var displayTag: String {
// Pad the hex value with 0 so it outputs `0d` instead of just `d`
return tag.map { ("0" + String($0, radix: 16)).suffix(2) }.joined()
}
// Convert `value` from Data to string of hex
var displayValue: String {
let hexValues = value.map { ("0" + String($0, radix: 16)).suffix(2) }
var str = ""
for (index, hex) in hexValues.enumerated() {
if index > 0 && index % 4 == 0 {
str += " " + hex
} else {
str += hex
}
}
return str
}
convenience init?(dataStream: Data) {
var size = 0
self.init(dataStream: dataStream, offset: 0, size: &size)
}
static func create(from dataStream: Data) -> [TLVNode] {
var size = 0
var offset = 0
var nodes = [TLVNode]()
while let node = TLVNode(dataStream: dataStream, offset: offset, size: &size) {
nodes.append(node)
offset += size
}
return nodes
}
/// Intialize a TLVNode object from a data stream
///
/// - Parameters:
/// - dataStream: The serialized data stream, in TLV encoding
/// - offset: The location from which parsing of the data stream starts
/// - size: Upon return, the number of bytes that the node occupies
private init?(dataStream: Data, offset: Int, size: inout Int) {
// A node must have at least 3 bytes
guard offset < dataStream.count - 3 else { return nil }
// The number of bytes that `tag` occupies
let m = dataStream[offset] & 0x1F == 0x1F ?
2 + dataStream[(offset + 1)...].prefix(10).prefix(while: { $0 & 0x80 == 0x80 }).count : 1
// The number of bytes that `length` occupies
let n = dataStream[offset + m] & 0x80 == 0x80 ? Int(dataStream[offset + m] & 0x7f) : 1
guard n <= 3 else { return nil }
self.tag = Data(dataStream[offset ..< (offset + m)])
self.length = dataStream[(offset + m) ..< (offset + m + n)].map { Int($0) }.reduce(0) { result, element in result * 0x100 + element }
self.value = Data(dataStream[(offset + m + n) ..< (offset + m + n + length)])
self.isConstructed = dataStream[offset] & 0x20 == 0x20
size = m + n + length
if self.isConstructed {
var childOffset = 0
var childNodeSize = 0
while let childNode = TLVNode(dataStream: self.value, offset: childOffset, size: &childNodeSize) {
self.children.append(childNode)
childOffset += childNodeSize
}
}
}
private func generateDescription(indentation: Int) -> String {
return "\(String(repeating: " ", count: indentation))\(tag as NSData) \(length) \(value as NSData)\n"
+ children.map { $0.generateDescription(indentation: indentation + 4) }.joined()
}
// Use this property when you need to quickly dump something to the debug console
override var description: String {
return self.generateDescription(indentation: 0)
}
// A more detailed view on the properties of the current instance
// Does not include child nodes.
override var debugDescription: String {
return """
TAG = \(tag as NSData)
LENGTH = \(length)
VALUE = \(value as NSData)
CONSTRUCTED = \(isConstructed)
"""
}
}
View Controller
import Cocoa
class ViewController: NSViewController {
#objc var tlvNodes: [TLVNode]!
override func viewDidLoad() {
super.viewDidLoad()
let data = Data(bytes:
[ 0xe1,0x35,
0x9f,0x1e,0x08,0x31,0x36,0x30,0x32,0x31,0x34,0x33,0x37,
0xef,0x12,
0xdf,0x0d,0x08,0x4d,0x30,0x30,0x30,0x2d,0x4d,0x50,0x49,
0xdf,0x7f,0x04,0x31,0x2d,0x32,0x32,
0xef,0x14,
0xdf,0x0d,0x0b,0x4d,0x30,0x30,0x30,0x2d,0x54,0x45,0x53,0x54,0x4f,0x53,
0xdf,0x7f,0x03,0x36,0x2d,0x35,
// A repeat of the data above
0xe1,0x35,
0x9f,0x1e,0x08,0x31,0x36,0x30,0x32,0x31,0x34,0x33,0x37,
0xef,0x12,
0xdf,0x0d,0x08,0x4d,0x30,0x30,0x30,0x2d,0x4d,0x50,0x49,
0xdf,0x7f,0x04,0x31,0x2d,0x32,0x32,
0xef,0x14,
0xdf,0x0d,0x0b,0x4d,0x30,0x30,0x30,0x2d,0x54,0x45,0x53,0x54,0x4f,0x53,
0xdf,0x7f,0x03,0x36,0x2d,0x35
])
// The Tree Controller won't know when we assign `tlvNode` to
// an entirely new object. So we need to give it a notification
let nodes = TLVNode.create(from: data)
self.willChangeValue(forKey: "tlvNodes")
self.tlvNodes = nodes
self.didChangeValue(forKey: "tlvNodes")
}
}
Interface Builder Setup
We will use Cocoa Bindings since populating an Outline View manually can be quite tedious (see my other answer) and your example screenshot look like you are already heading in that direction. A word of caution: while Cocoa Binding is very convenient, it should be considered an advanced topic since it's rather hard to troubleshoot. On your storyboard:
From the Object library on the right, add a Tree Controller to your scene
Select the Tree Controller, in the Attributes inspector, set Children = children
Drag out an Outline View and configure it with 3 columns. We will name them Tag, Length and Value
Open the Bindings Inspector, for the 5 highlight objects, set their bindings as follow:
| IB Object | Property | Bind To | Controller Key | Model Key Path |
|-----------------|-------------------|-----------------|-----------------|--------------------------|
| Tree Controller | Controller Array | View Controller | | self.tlvNodes |
| Outline View | Content | Tree Controller | arrangedObjects | |
| Table View Cell | Value | Table Cell View | | objectValue.displayTag |
| (Tag column) | | | | |
| Table View Cell | Value | Table Cell View | | objectValue.length |
| (Length column) | | | | |
| Table View Cell | Value | Table Cell View | | objectValue.displayValue |
| (Value column) | | | | |
Result:

how to execute join query in realm with swift?

I want to execute join query
table1)
class student
{
name:String
classcode:Int
}
table2)
class classcode
{
classcode:Int
name:String
}
Data example
student:
| name | classcode |
| john | 001 |
| Kim | 002 |
classcode:
| classcode | name |
| 001 | computer |
| 002 | Math |
I want to get output -? john,computer
How can I execute the query in Realm?
Realm is an object-based database, so the concept of joins in queries doesn't apply to it.
In this particular case, it would be appropriate to set up classcode objects as a list in the student class. Like so:
class Class: Object {
dynamic var classCode = 0
dynamic var name = ""
}
class Student: Object {
dynamic var name = ""
let classes = List<Class>()
}
---
let realm = try! Realm()
let computerClass = Class()
computerClass.classCode = 1
computerClass.name = "Computer"
let newStudent = Student()
newStudent.name = "John"
newStudent.classes.append(computerClass)
try! realm.write {
realm.add(computerClass)
realm.add(newStudent)
}
Realm List objects do not store copies of Object instances; they only store references to the corresponding Object in its table. In this way, it replicates the same sort of setup you'd expect in a join query.
Let me know if you need anymore clarification! :)