Cache by Device Parameters

To execute a uniform request to resource without loading to database, create the HHFWCashByParams application, which uses framework methods:

Method name Brief description
initWithCredentials (_: host: environment: project: device:) The method initializes the framework.
auth (_: password:) The method authenticates the user by login and password.
openBase (_: key:) The method opens connection with database at the specified path.
resources (_: handler:) The method gets schemes of available resources and automatically creates corresponding tables in the database.
tableStream (_: transactionID: requestCallParams: handler:) The method loads table data to local database.
getTablesName (_: resourceName: requestParams:) The method returns table name in local database.
dropCache (_: resourceName: requestParams:) The method deletes tables from database.

Auxiliary methods:

Method name Brief description
getURL (for:) The method returns URL for the file with the specified name in the Documents folder.
Type of returned data: URL

Before creating an application make sure that the resource is available in PostgreSQL data source. The table contains information about fruits.

A mobile platform server contains the fruits_get and fruits_insert_delete resources that address the same table on a remote PostgreSQL server. The fruits_get resource requests and saves data on a mobile device. The fruits_insert_delete resource inserts and deletes rows at remote PostgreSQL server. The response returns the refreshed table that is written into local database.

The HHFWCashByParams application includes one screen, the UITextField text box, the UITextView text view, and UIButton buttons:

NOTE. When the application is initialized, authentication is executed, the buttons are not available. If the authentication is executed successfully, the buttons are available, and the text box displays the text "Authentication and resources load success".

To execute the example:

  1. Click the TableStream Without Params button.

Clicking the button gets data from the fruits_get resource.

When a local database is opened, any appropriate editor displays the fruits_get_<some_stuff>_output_table table where:

  1. Enter the 9999 value to the text box to add a row via the fruits_insert_delete resource. The value is used in parameters sent in the request {"upsert_rows": [["9999", "NewApple9999"]], "delete_ids": null}.

  2. Click the TableStream Insert button.

Clicking the button returns the changed table with other name.

A new table is created in the local database for the fruits_insert_delete resource, in which a row with the 9999 identifier is added.

Parameters were sent during the tableStream request, hash in table name was not changed.

NOTE. When a new row is added, a new table with other hash is created. If a request is sent with equal parameters, the new table is not created, and the current table is overwritten.

  1. Click the TableStream Without Params button to refresh the table of the fruits_get resource.

A new row with the 9999 identifier is created for the fruits_get resource in the table.

  1. Enter the 9999 value to the text box to delete the row with the same identifier.

  1. Click the TableStream Delete button. The request contains parameters {"upsert_rows": null, "delete_ids": [["9999"]]}.

Clicking the button returns the new changed table, as well as on adding a row.

The new table appeared in the local database, which does not contain a row with the 9999 identifier.

  1. Enter the 9999 value to the text box to get table names.

  1. Click the Get Table Name button.

Clicking the button returns names of the tables created in the request to the fruits_insert_delete resource with the parameters {"upsert_rows": null, "delete_ids": [["9999"]]}.

  1. Click the Drop Cache button.

Clicking the button deletes tables from the local database, which were created in the request to the fruits_insert_delete resource with the parameters {"upsert_rows": null, "delete_ids": [["9999"]]}.

The local database does not contain the table created on adding a new row.

Application code:

import UIKit
 
class ViewController: UIViewController {
 
    // Determine output variables
    @IBOutlet weak var resultTextView: UITextView!
    @IBOutlet weak var valueTextField: UITextField!
    @IBOutlet weak var tableStreamButton: UIButton!
    @IBOutlet weak var tableStreamInsertButton: UIButton!
    @IBOutlet weak var tableStreamDeleteButton: UIButton!
    @IBOutlet weak var getTableName: UIButton!
    @IBOutlet weak var dropCacheButton: UIButton!
 
    // Redetermine method
    override func viewDidLoad() {
        super.viewDidLoad()
        self.deactivateButtons()
        self.initializeFramework()
        self.auth {
            let databaseName = "database.sqlite"
            if self.openDatabase(databaseName) {
                self.loadResourcesScheme(databaseName) {
                    self.activateButtons()
                    self.resultTextView.text = "Authentication and load resources success"
                }
            }
        }
    }
 
    // Set method that will be executed on button click
    @IBAction func viewTapped(_ sender: UITapGestureRecognizer) {
        self.valueTextField.resignFirstResponder()
    }
 
    @IBAction func tableStreamPressed(_ sender: UIButton) {
        let databaseName = "database.sqlite"
        self.tableStreamWithoutParams(databaseName) { (jsonResult) in
            self.resultTextView.text = String(format: "%@", jsonResult)
        }
    }
 
    @IBAction func tableStreamInsertPressed(_ sender: UIButton) {
        let databaseName = "database.sqlite"
        self.tableStreamInsert(databaseName) { (jsonResult) in
            self.resultTextView.text = String(format: "%@", jsonResult)
        }
    }
 
    @IBAction func tableStreamDeletePressed(_ sender: UIButton) {
        let databaseName = "database.sqlite"
        self.tableStreamDelete(databaseName) { (jsonResult) in
            self.resultTextView.text = String(format: "%@", jsonResult)
        }
    }
 
    @IBAction func getTableNamePressed(_ sender: UIButton) {
        let databaseName = "database.sqlite"
        self.resultTextView.text = self.getTableName(databaseName)
    }
 
    @IBAction func dropCachePressed(_ sender: UIButton) {
        let databaseName = "database.sqlite"
        self.resultTextView.text = self.dropCache(databaseName)
    }
 
    // Initialize framework
    private func initializeFramework() {
        let apiVersion: String = "v1"
        let host: String = "http://testmasterfmp.fsight.cloud/"
        let environment: String = "Leonid_environment"
        let project: String = "Leonid_project"
        let device: String = (UIDevice.current.identifierForVendor?.uuidString)!
        HHFWController.sharedInstance().initWithCredentials(
            apiVersion,
            host: host,
            environment: environment,
            project: project,
            device: device
        )
    }
 
    // Authenticate
    private func auth(completion: @escaping ()->()) {
        let username: String = "Leonid"
        let password: String = "123123"
        HHFWController.sharedInstance().auth(username, password: password){ (jsonResult) in
            if let jsonDict = jsonResult as? NSDictionary,
                let status = jsonDict["status"] as? String, status == "ok" {
                print("Auth success")
                completion()
            } else {
                print("Auth error")
            }
        }
    }
 
    // Open or create a database
    private func openDatabase(_ databaseName: String) -> Bool {
        let fullDatabaseURL = self.getURL(for: databaseName)
        return HHFWController.sharedInstance().openBase(fullDatabaseURL.path, key: "")
    }
 
    // Load resources scheme
    private func loadResourcesScheme(_ databaseName: String, completion: @escaping ()->()) {
        HHFWController.sharedInstance().resources(databaseName) { (jsonResult) in
            if let jsonDict = jsonResult as? NSDictionary,
                let status = jsonDict["status"] as? String, status == "ok" {
                print("Load resources success")
                completion()
            } else {
                print("Load resources error")
            }
        }
    }
 
    // Perform the TableStream request
    private func tableStreamWithoutParams(_ databaseName: String, completion: @escaping (NSDictionary)->()) {
        let resourceName = "fruits_get"
        let requestCallParams = RequestCallParams(defaultDb: ())
        let fullDatabaseURL = self.getURL(for: databaseName)
        requestCallParams?.dataBasePath = fullDatabaseURL.path
        HHFWController.sharedInstance().tableStream(resourceName, transactionID: nil, tableCallParams: requestCallParams) { (jsonResult) in
            if let jsonDict = jsonResult as? NSDictionary,
                let status = jsonDict["status"] as? String, status == "ok" {
                print("Load table success")
                completion(jsonDict)
            } else {
                print("Load table error")
            }
        }
    }
 
    private func tableStreamInsert(_ databaseName: String, completion: @escaping (NSDictionary)->()) {
        guard let value = self.valueTextField.text else {return}
        let resourceName = "fruits_insert_delete"
        let requestCallParams = RequestCallParams(defaultDb: ())
        let fullDatabaseURL = self.getURL(for: databaseName)
        requestCallParams?.dataBasePath = fullDatabaseURL.path
        requestCallParams?.data = "{\"upsert_rows\": [[\"" + value + "\", \"NewApple" + value + "\"]], \"delete_ids\": null}"
        HHFWController.sharedInstance().tableStream(resourceName, transactionID: nil, tableCallParams: requestCallParams) { (jsonResult) in
            if let jsonDict = jsonResult as? NSDictionary,
                let status = jsonDict["status"] as? String, status == "ok" {
                print("Load table success")
                completion(jsonDict)
            } else {
                print("Load table error")
            }
        }
    }
 
    private func tableStreamDelete(_ databaseName: String, completion: @escaping (NSDictionary)->()) {
        guard let value = self.valueTextField.text else {return}
        let resourceName = "fruits_insert_delete"
        let requestCallParams = RequestCallParams(defaultDb: ())
        let fullDatabaseURL = self.getURL(for: databaseName)
        requestCallParams?.dataBasePath = fullDatabaseURL.path
        requestCallParams?.data = "{\"upsert_rows\": null, \"delete_ids\": [[\"" + value + "\"]]}"
        HHFWController.sharedInstance().tableStream(resourceName, transactionID: nil, tableCallParams: requestCallParams) { (jsonResult) in
            if let jsonDict = jsonResult as? NSDictionary,
                let status = jsonDict["status"] as? String, status == "ok" {
                print("Load table success")
                completion(jsonDict)
            } else {
                print("Load table error")
            }
        }
    }
 
    // Get table names in local database
     private func getTableName(_ databaseName: String) -> String? {
        guard let value = self.valueTextField.text else {return nil}
        let resourceName = "fruits_insert_delete"
        let params = "{\"upsert_rows\": [[\"" + value + "\", \"NewApple" + value + "\"]], \"delete_ids\": null}"
         return HHFWController.sharedInstance().getTablesName("/Documents/\(databaseName)", resourceName: resourceName, requestParams: params, tableName: "")
    }
 
    // Clear cache
     private func dropCache(_ databaseName: String) -> String? {
        guard let value = self.valueTextField.text else {return nil}
        let resourceName = "fruits_insert_delete"
        let params = "{\"upsert_rows\": [[\"" + value + "\", \"NewApple" + value + "\"]], \"delete_ids\": null}"
         return HHFWController.sharedInstance().dropCache("/Documents/\(databaseName)", resourceName: resourceName, requestParams: params)
    }
 
    // Call auxiliary classes
    private func getURL(for fileName: String) -> URL {
        let paths: [URL] = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
        let fileURL: URL = paths[0].appendingPathComponent(fileName)
        return fileURL
    }
 
    // Set methods to display application user interface elements
    private func deactivateButtons() {
        self.tableStreamButton.isEnabled = false
        self.tableStreamInsertButton.isEnabled = false
        self.tableStreamDeleteButton.isEnabled = false
        self.getTableName.isEnabled = false
        self.dropCacheButton.isEnabled = false
    }
 
    private func activateButtons() {
        self.tableStreamButton.isEnabled = true
        self.tableStreamInsertButton.isEnabled = true
        self.tableStreamDeleteButton.isEnabled = true
        self.getTableName.isEnabled = true
        self.dropCacheButton.isEnabled = true
    }
}

See also:

Examples of iOS Framework Use | Examples of Working with Resources