How to Specify field MongoDB Definition dynamically using a string in F# - mongodb

I started out using quite strongly typed definitions
let coll: IMongoCollection<NZPostDataItem> = MongoUtil.getNzpostCollection()
let filter = Builders<NZPostDataItem>.Filter.And(
Builders<NZPostDataItem>.Filter.Gte((fun n -> n.dateLodged),DateTime(2020,10,1)),
Builders<NZPostDataItem>.Filter.Eq((fun n -> n.eshipMatched.Value) , true)
)// ... etc
The problem is, I need to dynamically run a query because one of the objects contains a BSONDocument
let coll: IMongoCollection<NZPostDataItem> = MongoUtil.getNzpostCollection()
let t = Nullable<bool> true
let filter =
FilterDefinition<BsonDocument>.op_Implicit(
"{
eshipMatched:true,
'eship.order.carrier_service_code':'TDEAUS',
dateLodged: {$gte: new Date('01-Oct-2020')}}
)"
)
Which works directly on MongoDB. But when I try and query it, I get a compile time error.
let results = coll.Find(filter).Limit(10000).ToList<NZPostDataItem>()
Severity Code Description Project File Line Suppression State
Error FS0041 No overloads match for method 'Find'.
Known type of argument: FilterDefinition
Available overloads:
- (extension) IMongoCollection.Find<'TDocument>(filter: FilterDefinition<'TDocument>,?options:
FindOptions) : IFindFluent<'TDocument,'TDocument> // Argument 'filter' doesn't match
- (extension) IMongoCollection.Find<'TDocument>(filter:
Linq.Expressions.Expression<Func<'TDocument,bool>>,?options: FindOptions) :
IFindFluent<'TDocument,'TDocument> // Argument 'filter' doesn't match
So - I can sort of see what is wrong - maybe 2 types of definitions - but I need to filter dynamically but return a strongly typed object.

As you said, you want the filter to be both dynamic and strongly-typed, so that's what you should create:
let filter =
FilterDefinition<NZPostDataItem>.op_Implicit("{ ... }")

Related

NSRegularExpressions - Non Capture Group not working

Hello I am having trouble using the Non-Capture group feature of regex in NSRegularExpressions
Heres some code to capture matches:
func matches(for regex: String, in text: String) -> [String] {
do {
let regex = try NSRegularExpression(pattern: regex);
let results = regex.matches(in: text,
range: NSRange(text.startIndex..., in: text));
return results.map {
String(text[Range($0.range, in: text)!]);
};
} catch let error {
print("invalid regex: \(error.localizedDescription)")
return [];
};
};
So now moving onto the regex, I have a string of text that is in the form workcenter:WDO-POLD should be very easy to make this work but the regex string ((?:workcenter:)(.{0,20})) does not return what I need
I get no errors on running but I get a return of the same string that I input - I am trying to retrieve the value that would be after workcenter: which is (.{0,20})
The first problem is with your regular expression. You do not want the outer capture group. Change your regular expression to:
(?:workcenter:)(.{0,20}) <-- outer capture group removed
The next problem is with how you are doing the mapping. You are accessing the full range of the match and not the desired capture group. Since you have a generalized function for handling any regular expression, it's hard to deal with all possibilities but the following change solves your immediate example and should work with regular expressions that have no capture group as well as those with one capture group.
Update your mapping line to:
return results.map {
regex.numberOfCaptureGroups == 0 ?
String(text[Range($0.range, in: text)!]) :
String(text[Range($0.range(at: 1), in: text)!])
}
This checks how many capture groups are in your regular expression. If none, it returns the full match. But if there is 1 or more, it returns just the value of the first capture group.
You can also get your original mapping to work if you change your regular expression to:
(?<=workcenter:)(.{0,20})
There's a much simpler solution here.
You have a lot of extra groups. Remove the outermost and no need for the non-capture group. Just use workcenter:(.{0,20}). Then you can reference the desired capture group with $1.
And no need for NSRegularExpression in this case. Use a simple string replacement.
let str = "workcenter:WDO-POLD"
let res = str.replacingOccurrences(of: "workcenter:(.{0,20})", with: "$1", options: .regularExpression)
This gives WDO-POLD.

How to use subscripts in an Optional Array of Dictionary

I am attempting to read a csv file on linux using the CSwiftV library, however the returned type that interests me the most is an optional array of dictionaries. I have been struggling to understand how to use subscripting to access the contents of the Array. Using the library most basic example (if you have marathon installed, just copy on a file and marathon run):
import CSwiftV // marathon: https://github.com/Daniel1of1/CSwiftV.git
let inputString = "Year,Make,Model,Description,Price\r\n1997,Ford,E350,descrition,3000.00\r\n1999,Chevy,Venture,another description,4900.00\r\n"
let csv = CSwiftV(with: inputString)
let rows = csv.rows // [
// ["1997","Ford","E350","descrition","3000.00"],
// ["1999","Chevy","Venture","another description","4900.00"]
// ]
let headers = csv.headers // ["Year","Make","Model","Description","Price"]
let keyedRows = csv.keyedRows // [
// ["Year":"1997","Make":"Ford","Model":"E350","Description":"descrition","Price":"3000.00"],
// ["Year":"1999","Make":"Chevy","Model":"Venture","Description":"another, description","Price":"4900.00"]
// ]
print(csv.rows)
print(csv.headers)
print(csv.keyedRows)
So far so good, but now when I try print(csv.keyedRows[0][0]) or print(csv.keyedRows[[0]]) I get something like:
- 24:16: value of optional type '[[String : String]]?' must be unwrapped to refer to member 'subscript' of wrapped base type '[[String : String]]'
How can I access the dictionary data in this case (I am thinking on something similar to csv.keyedRows[0]["Year"]) ?
For this:
print(csv.keyedRows[0]["Year"])
You can use optional binding:
if let keyedRows = csv.keyedRows {
print(keyedRows[0]["Year"])
} else {
// keyedRows is nil!
}
Or you can use the postfix ? operator:
print(csv.keyedRows?[0]["Year"] as Any)
// or
print(csv.keyedRows?[0]["Year"] ?? "")

How to pass and get multiple URLQueryItems in Swift?

Ok, I am working in an iMessage app and am trying to parse more than 1 url query item from the selected message here- I have been successful getting/sending just 1 value in a query:
override func willBecomeActive(with conversation: MSConversation) {
// Called when the extension is about to move from the inactive to active state.
// This will happen when the extension is about to present UI.
if(conversation.selectedMessage?.url != nil) //trying to catch error
{
let components = URLComponents(string: (conversation.selectedMessage?.url?.query?.description)!)
//let val = conversation.selectedMessage?.url?.query?.description
if let queryItems = components?.queryItems {
// process the query items here...
let param1 = queryItems.filter({$0.name == "theirScore"}).first
print("***************=> GOT IT ",param1?.value)
}
}
When I just have 1 value, just by printing conversation.selectedMessage?.url?.query?.description I get an optional with that 1 value, which is good. But with multiple I cant find a clean way to get specific values by key.
What is the correct way to parse a URLQueryItem for given keys for iMessage?
When you do conversation.selectedMessage?.url?.query?.description it simply prints out the contents of the query. If you have multiple items then it would appear something like:
item=Item1&part=Part1&story=Story1
You can parse that one manually by splitting the string on "&" and then splitting the contents of the resulting array on "=" to get the individual key value pairs in to a dictionary. Then, you can directly refer to each value by key to get the specific values, something like this:
var dic = [String:String]()
if let txt = url?.query {
let arr = txt.components(separatedBy:"&")
for item in arr {
let arr2 = item.components(separatedBy:"=")
let key = arr2[0]
let val = arr2[1]
dic[key] = val
}
}
print(dic)
The above gives you an easy way to access the values by key. However, that is a bit more verbose. The way you provided in your code, using a filter on the queryItems array, is the more compact solution :) So you already have the easier/compact solution, but if this approach makes better sense to you personally, you can always go this route ...
Also, if the issue is that you have to write the same filtering code multiple times to get a value from the queryItems array, then you can always have a helper method which takes two parameters, the queryItems array and a String parameter (the key) and returns an optional String value (the value matching the key) along the following lines:
func valueFrom(queryItems:[URLQueryItem], key:String) -> String? {
return queryItems.filter({$0.name == key}).first?.value
}
Then your above code would look like:
if let queryItems = components?.queryItems {
// process the query items here...
let param1 = valueFrom(queryItems:queryItems, key:"item")
print("***************=> GOT IT ", param1)
}
You can use iMessageDataKit library. It makes setting and getting data really easy and straightforward like:
let message: MSMessage = MSMessage()
message.md.set(value: 7, forKey: "user_id")
message.md.set(value: "john", forKey: "username")
message.md.set(values: ["joy", "smile"], forKey: "tags")
print(message.md.integer(forKey: "user_id")!)
print(message.md.string(forKey: "username")!)
print(message.md.values(forKey: "tags")!)
(Disclaimer: I'm the author of iMessageDataKit)

How to build a query object for Realm

I am building an iOS app using Swift.
I am using Realm as database.
I am currently building a search functionality for a tableview.
This is my filter query
items = realm.objects(Book).filter(predicate).filter("state IN {'pending','activated','completed','closed'}")
I am saving what states a user wants to filter on in another model called Filter.
How can I build this {'pending','activated','completed','closed'} from the output of the following filter query (title is the attribute)? What is this object called?
realm.objects(Filter).filter("type = 'filter' AND activated = 'true'")
The right-hand side of the IN operator can take a substitution placeholder (%#) that can have an NSArray (or other enumerable object) substituted in.
Assuming your Filter model looks something like:
class Filter: Object {
dynamic var type: String = ""
dynamic var activated: bool = false
dynamic var state: String = ""
}
You can do something like the following to construct the query you're after:
let activeFilters = realm.objects(Filter).filter("type = 'filter' AND activated = 'true'")
let activeStates = activeFilters.valueForKey("state") as! [String]!
let items = realm.objects(Book).filter(predicate).filter("state IN %#", activeStates)

Frama-C: Add Annotation in Plugin

I am writing a Frama-C-plugin. In this plugin, I want to add annotations to functions (e.g. if function name = "test", add a requires clause, saying parameter == 1).
I found the function Annotations.add_requires, but I don't know some of the parameters (Emitter.t, Identified_predicates). Is the string-parameter the function name or an own name for the predicate?
How do I use this function?
Can anyone show an example?
The emitter identify your plugin and has to declare what it is suppose to modify. In your case, as you want to add properties to the specifications, you can build it with:
let emitter = Emitter.create "My plugin" [ Emitter.Funspec ]
~correctness:[] ~tuning:[]
Now, for a kernel_function this is an example of how to build a precondition saying that the first parameter is equal to one:
let add_pre kf = match Kernel_function.get_formals kf with
| [] -> ()
| c_var::_ ->
let l_var = Cil.cvar_to_lvar c_var in
let var_term = Logic_const.tvar l_var in
let cnst_term = Logic_const.tinteger 1 in
let eq_pred = Logic_const.prel (Cil_types.Req, var_term, cnst_term) in
let pred = Logic_const.new_predicate eq_pred in
let bname = Cil.default_behavior_name in
Annotations.add_requires emitter kf ~behavior:bname [pred]