Is there a computation expression builder for Promises? - promise

async function showSampleText(context: vscode.ExtensionContext): Promise<void> {
let sampleTextEncoded = await vscode.workspace.fs.readFile(vscode.Uri.file(context.asAbsolutePath('sample.txt')));
let sampleText = new TextDecoder('utf-8').decode(sampleTextEncoded);
let doc = await vscode.workspace.openTextDocument({ language: 'plaintext', content: sampleText });
vscode.window.showTextDocument(doc);
}
I translated the above Typecript snippet to the following Fable code.
type ITextDecoder =
abstract member decode: ?input: Uint8Array * ?options: {| stream : bool |} -> string
[<Emit("new TextDecoder($0)")>]
let TextDecoder label : ITextDecoder = jsNative
let show_sample_text (ctx : Vscode.ExtensionContext) =
async {
let! sampleTextEncoded = Vscode.workspace.fs.readFile(statics.Uri.file(ctx.asAbsolutePath("sample.txt"))) |> Async.AwaitPromise
let sampleText = TextDecoder("utf-8").decode(sampleTextEncoded);
let! doc = workspace.openTextDocument(options= !!{| language="plaintext"; content=sampleText |}) |> Async.AwaitPromise
let! _ = window.showTextDocument(document=doc,options=undefined) |> Async.AwaitPromise
return ()
} |> Async.StartAsPromise
It bothers me how I am explicitly converting between Async and Promises. Is there builder specifically for Promises somewhere?

Fable does support promise via Fable.Promise package.
If you add Fable.Promise package to your project then you can do things like that:
let private getRandomUser () = promise {
// Do something here
// ...
return ()
}

Related

Unable to read from NEAR's rocksDB

I'm trying to iterate through NEAR's RocksDB,
I've downloaded the small backup from s3 and using the code below to iterate through col33 (transactions)
But it doesn't print anything as RocksDB would be empty (but it is not obviously),
could you please point me out what I'm doing wrong?
Thanks
use std::env;
use rocksdb::{ColumnFamilyDescriptor, DB, IteratorMode, Options};
fn col_name(col: i32) -> String {
format!("col{}", col)
}
fn main() {
println!("Hello, RocksDB!");
let args: Vec<String> = env::args().collect();
let path = if args.len() > 1 {
args.get(1).unwrap().clone()
} else {
String::from("./data")
};
println!("data dir={}", &path);
let opts = Options::default();
let mut cfs:Vec<ColumnFamilyDescriptor> = Vec::new();
for col in 33..34 {
cfs.push(
rocksdb::ColumnFamilyDescriptor::new(col_name(col),opts.clone()));
}
let db = DB::open_cf_descriptors_read_only(
&opts,&path, cfs, false,
).unwrap();
let iter = db.iterator(IteratorMode::Start);
for (key, value) in iter {
println!("Saw {:?} {:?}", key, value);
let k = String::from_utf8(key.to_vec()).unwrap();
let v = String::from_utf8(value.to_vec()).unwrap();
println!("Saw {:?} {:?}", k, v);
}
let _ = DB::destroy(&Options::default(), &path);
}
I've found what was wrong,
as Asad Awadia mentioned, I'm using iterator over default column family here.
I've used iterator_cf instead and got some data:
let cf_handle = db.cf_handle("col33").unwrap();
let iter = db.iterator_cf(cf_handle, IteratorMode::Start);

Are cross contract call atomic?

Take for example this code:
#[payable]
pub fn add_liquidity(&mut self, min_liquidity: u128, max_tokens: u128) -> U128 {
let deposit = env::attached_deposit();
let contract_near_balance = env::account_balance();
let user_address = env::predecessor_account_id();
let contract_address = env::current_account_id();
let token_amount = max_tokens;
println!("{}", token_amount);
let initial_liquidity = contract_near_balance;
println!("initial liquidity{}", initial_liquidity);
self.uni_totalsupply = initial_liquidity;
let balance_option = self.uni_balances.get(&user_address);
match balance_option {
Some(_) => {
self.uni_balances.insert(&user_address, &initial_liquidity);
}
None => {
self.uni_balances.insert(&user_address, &initial_liquidity);
}
}
Promise::new(self.avrit_token_id.clone()).function_call(
b"transfer_from".to_vec(),
json!({"owner_id":contract_address, "new_owner_id":"avrit.testnet", "amount": U128(token_amount)}).to_string().as_bytes().to_vec(),
DEPOSIT,
env::prepaid_gas() - GAS_FOR_SWAP,
);
initial_liquidity.into()
}
Even if the promise fails, will it set uni_balances in the storage? How can I make the transaction atomic?
Contract calls are not atomic. In order to make the chain of promises atomic is to use a then callback which is called after the initial promise. In the callback function you can check the success of the previous promise like here:
pub fn check_promise(&mut self) {
match env::promise_result(0) {
PromiseResult::Successful(_) => {
env::log(b"Check_promise successful");
self.checked_promise = true;
}
_ => panic!("Promise with index 0 failed"),
};
}
At this point you can make a state change that is final and could only happen if the whole transaction was successful.

Not Executing Function at The Right Time, But Executed After Completion Block

Need help in figuring out why my function is not executing when I thought it should but it executed after the completion block in the code. I am fairly new to Xcode so please excuse me if things sound confusing here. Below is my code.
class ImageDownloader{
typealias completionHandler = (Result<Set<ARReferenceImage>, Error>) -> ()
typealias ImageData = (image: UIImage, orientation: CGImagePropertyOrientation, physicalWidth: CGFloat, name: String)
static let URLDic = [ReferenceImagePayload]()
class func getDocumentData(completion:#escaping ([ReferenceImagePayload]) -> ()) {
var documentCollection: [ReferenceImagePayload] = []
db.collection("Users").getDocuments {(snapshot, error) in
if error == nil && snapshot != nil {
var index = 0
for document in snapshot!.documents {
let loadData = document.data()
index += 1
if loadData["Target URL"] != nil {
let url = loadData["Target URL"]
let urlString = URL(string: "\(String(describing: url ?? ""))")
let urlName = loadData["Target Image"]
documentCollection.append(ReferenceImagePayload(name: urlName as! String, url: urlString!))
if snapshot!.documents.count == index {
// After finished, send back the loaded data
completion(documentCollection)
}
}
}
}
}
}
static var receivedImageData = [ImageData]()
class func downloadImagesFromPaths(_ completion: #escaping completionHandler) {
// THE LINE BELOW WHERE I CALL THE FUNCTION IS NOT EXECUTED WHEN THIS CLASS IS INITIALLY CALLED. BUT AS THE CODE RUNS, THIS LINE BELOW IS EXECUTED AFTER THE COMPLETIONOPERATION = BLOCKOPERATION IS COMPLETED.
let loadedDataDic: () = getDocumentData { (URLDic) in
print(URLDic.self, "Got it")
}
let operationQueue = OperationQueue()
operationQueue.maxConcurrentOperationCount = 6
let completionOperation = BlockOperation {
OperationQueue.main.addOperation({
completion(.success(referenceImageFrom(receivedImageData)))
// LINE "let loadedDataDic: () = getDocumentData" ONLY GOT EXECUTED AT THIS POINT
})
}
URLDic.forEach { (loadData) in
let urlstring = loadData.url
let operation = BlockOperation(block: {
do{
let imageData = try Data(contentsOf: loadData.url)
print(imageData, "Image Data")
if let image = UIImage(data: imageData){
receivedImageData.append(ImageData(image, .up, 0.1, loadData.name))
}
}catch{
completion(.failure(error))
}
})
completionOperation.addDependency(operation)
}
operationQueue.addOperations(completionOperation.dependencies, waitUntilFinished: false)
operationQueue.addOperation(completionOperation)
}
}

Observable from more than one BehaviorRelay RxSwift

I am trying to achieve a subscription of 3 different BehaviorRelay using RxSwift. The idea is following:
let disposeBag = DisposeBag()
class ClassA{
var br1 = BehaviorRelay(value: "BR1_1")
var br2 = BehaviorRelay(value: "BR2_1")
var br3 = BehaviorRelay(value: "BR3_1")
/* Some other variables */
}
let classA = ClassA()
class ClassB:CustomStringConvertible{
let classA:ClassA
var description: String{
return "\(br1.value), \(br2.value), \(br3.value)"
}
var br1:BehaviorRelay<String>{
return classA.br1
}
var br2:BehaviorRelay<String>{
return classA.br2
}
var br3:BehaviorRelay<String>{
return classA.br3
}
init(classA:ClassA) {
self.classA = classA
}
}
let classB = ClassB(classA: classA)
classB.br1.asObservable().subscribe { (value) in
print(value)
}
classA.br1.accept("BR1_2")
It prints:
next(BR1_1)
next(BR1_2)
By doing that I am "populating" my ClassB with objects from ClassA and by setting a subscription to the objects in ClassB i can react to the next events.
However, I would like to create a function such as:
func reactingFunction(br1:BehaviorRelay<String>, br2:BehaviorRelay<String>, br3:BehaviorRelay<String>){
/**/
}
to be called every time any of the br produces onNext event. Can I create a mix subscription for all of them?
Thank you
I have found out a solution by implementing CombineLast:
Observable.combineLatest(classB.br1, classB.br2, classB.br3).subscribe(onNext: { (br1, br2, br3) in
reactingFunction(br1: br1, br2: br2, br3: br3)
}).disposed(by: disposeBag)
Then I have changed the reactingFunction to accept only the values:
func reactingFunction(br1:String, br2:String, br3:String){
print("Reacting Function -> \(br1) & \(br2) \(br3)")
}
From the example:
classA.br1.accept("BR1_2")
classA.br1.accept("BR1_3")
classA.br1.accept("BR1_4")
classA.br1.accept("BR1_5")
classA.br2.accept("BR2_2")
classA.br3.accept("BR3_2")
classA.br2.accept("BR2_3")
It prints:
Reacting Function -> BR1_1 & BR2_1 BR3_1
Reacting Function -> BR1_2 & BR2_1 BR3_1
Reacting Function -> BR1_3 & BR2_1 BR3_1
Reacting Function -> BR1_4 & BR2_1 BR3_1
Reacting Function -> BR1_5 & BR2_1 BR3_1
Reacting Function -> BR1_5 & BR2_2 BR3_1
Reacting Function -> BR1_5 & BR2_2 BR3_2
Reacting Function -> BR1_5 & BR2_3 BR3_2

Swift 3.0 NSFetchRequest error [duplicate]

In Swift 2 the following code was working:
let request = NSFetchRequest(entityName: String)
but in Swift 3 it gives error:
Generic parameter "ResultType" could not be inferred
because NSFetchRequest is now a generic type. In their documents they wrote this:
let request: NSFetchRequest<Animal> = Animal.fetchRequest
so if my result class is for example Level how should I request correctly?
Because this not working:
let request: NSFetchRequest<Level> = Level.fetchRequest
let request: NSFetchRequest<NSFetchRequestResult> = Level.fetchRequest()
or
let request: NSFetchRequest<Level> = Level.fetchRequest()
depending which version you want.
You have to specify the generic type because otherwise the method call is ambiguous.
The first version is defined for NSManagedObject, the second version is generated automatically for every object using an extension, e.g:
extension Level {
#nonobjc class func fetchRequest() -> NSFetchRequest<Level> {
return NSFetchRequest<Level>(entityName: "Level");
}
#NSManaged var timeStamp: NSDate?
}
The whole point is to remove the usage of String constants.
I think i got it working by doing this:
let request:NSFetchRequest<NSFetchRequestResult> = NSFetchRequest(entityName: "Level")
at least it saves and loads data from DataBase.
But it feels like it is not a proper solution, but it works for now.
The simplest structure I found that works in 3.0 is as follows:
let request = NSFetchRequest<Country>(entityName: "Country")
where the data entity Type is Country.
When trying to create a Core Data BatchDeleteRequest, however, I found that this definition does not work and it seems that you'll need to go with the form:
let request: NSFetchRequest<NSFetchRequestResult> = Country.fetchRequest()
even though the ManagedObject and FetchRequestResult formats are supposed to be equivalent.
Here are some generic CoreData methods that might answer your question:
import Foundation
import Cocoa
func addRecord<T: NSManagedObject>(_ type : T.Type) -> T
{
let entityName = T.description()
let context = app.managedObjectContext
let entity = NSEntityDescription.entity(forEntityName: entityName, in: context)
let record = T(entity: entity!, insertInto: context)
return record
}
func recordsInTable<T: NSManagedObject>(_ type : T.Type) -> Int
{
let recs = allRecords(T.self)
return recs.count
}
func allRecords<T: NSManagedObject>(_ type : T.Type, sort: NSSortDescriptor? = nil) -> [T]
{
let context = app.managedObjectContext
let request = T.fetchRequest()
do
{
let results = try context.fetch(request)
return results as! [T]
}
catch
{
print("Error with request: \(error)")
return []
}
}
func query<T: NSManagedObject>(_ type : T.Type, search: NSPredicate?, sort: NSSortDescriptor? = nil, multiSort: [NSSortDescriptor]? = nil) -> [T]
{
let context = app.managedObjectContext
let request = T.fetchRequest()
if let predicate = search
{
request.predicate = predicate
}
if let sortDescriptors = multiSort
{
request.sortDescriptors = sortDescriptors
}
else if let sortDescriptor = sort
{
request.sortDescriptors = [sortDescriptor]
}
do
{
let results = try context.fetch(request)
return results as! [T]
}
catch
{
print("Error with request: \(error)")
return []
}
}
func deleteRecord(_ object: NSManagedObject)
{
let context = app.managedObjectContext
context.delete(object)
}
func deleteRecords<T: NSManagedObject>(_ type : T.Type, search: NSPredicate? = nil)
{
let context = app.managedObjectContext
let results = query(T.self, search: search)
for record in results
{
context.delete(record)
}
}
func saveDatabase()
{
let context = app.managedObjectContext
do
{
try context.save()
}
catch
{
print("Error saving database: \(error)")
}
}
Assuming that there is a NSManagedObject setup for Contact like this:
class Contact: NSManagedObject
{
#NSManaged var contactNo: Int
#NSManaged var contactName: String
}
These methods can be used in the following way:
let name = "John Appleseed"
let newContact = addRecord(Contact.self)
newContact.contactNo = 1
newContact.contactName = name
let contacts = query(Contact.self, search: NSPredicate(format: "contactName == %#", name))
for contact in contacts
{
print ("Contact name = \(contact.contactName), no = \(contact.contactNo)")
}
deleteRecords(Contact.self, search: NSPredicate(format: "contactName == %#", name))
recs = recordsInTable(Contact.self)
print ("Contacts table has \(recs) records")
saveDatabase()
This is the simplest way to migrate to Swift 3.0, just add <Country>
(tested and worked)
let request = NSFetchRequest<Country>(entityName: "Country")
Swift 3.0 This should work.
let request: NSFetchRequest<NSFetchRequestResult> = NSManagedObject.fetchRequest()
request.entity = entityDescription(context)
request.predicate = predicate
I also had "ResultType" could not be inferred errors. They cleared once I rebuilt the data model setting each entity's Codegen to "Class Definition". I did a brief writeup with step by step instructions here:
Looking for a clear tutorial on the revised NSPersistentContainer in Xcode 8 with Swift 3
By "rebuilt" I mean that I created a new model file with new entries and attributes. A little tedious, but it worked!
What worked best for me so far was:
let request = Level.fetchRequest() as! NSFetchRequest<Level>
I had the same issue and I solved it with the following steps:
Select your xcdatamodeld file and go to the Data Model Inspector
Select your first Entity and go to Section class
Make sure that Codegen "Class Definition" is selected.
Remove all your generated Entity files. You don't need them anymore.
After doing that I had to remove/rewrite all occurences of fetchRequest as XCode seem to somehow mix up with the codegenerated version.
HTH
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
func loadItemsCategory() {
let request: NSFetchRequest<Category> = Category.fetchRequest()
do {
categoryArray = try context.fetch(request)
} catch {
print(error)
}
tableView.reloadData()
}

Resources