Storing objects in the Google Firebase cloud with TMS Cloud Pack

Tuesday, June 20, 2017

Since the latest release of TMS Cloud Pack, there is now also built-in support to use Google Firebase for cloud data storage. The architecture of Google's Firebase is quite simple. It offers storage of JSON data in the cloud. The JSON data has a unique identifier in a table and via access with this unique identifier, this JSON data can be read, updated or deleted. In addition, indexing rules can be set to perform query on the data in a Firebase table, for example, retrieve all JSON objects where a field X has value Y.

To make it really easy use to use data on Google Firebase from a Delphi or C++Builder application, we have added capabilities to put objects or generic lists of objects in a Firebase table. This is done via the non-visual component TFirebaseObjectDatabase that you can put on the form.



To demonstrate this, consider a class we want to use in the Delphi application that descends from TFirebaseObject:

  TFirebaseCustomer = class(TFirebaseObject)
  private
    FName: string;
    FStreet: string;
    FZIP: integer;
    FDoB: TDate;
    FCity: string;
  public
    constructor Create; override;
    destructor Destroy; override;
  published
    property Name: string read FName write FName;
    property Street: string read FStreet write FStreet;
    property City: string read FCity write FCity;
    property ZIP: integer read FZIP write FZIP;
    property DoB: TDate read FDoB write FDoB;
  end;

Now, after we have retrieved a connection for TAdvFirebaseObjectDataBase to Firebase via:

  AdvFirebaseObjectDatabase1.DatabaseName := 'TMS';
  AdvFirebaseObjectDatabase1.TableName := 'Customers';
  AdvFirebaseObjectDatabase1.Connect;
we can create and put TFirebaseCustomer objects in the Google Firebase realtime data cloud:

var
  cst: TFireBaseCustomer;
begin
  cst := TFireBaseCustomer.Create;
  try
    cst.Name := 'Bill Gates';
    cst.Street := 'Microsoft Av';
    cst.ZIP := 2123;
    cst.City := 'Redmond';
    cst.DoB := EncodeDate(1969,04,18);
    cst.ID := '1240';
    AdvFirebaseObjectDatabase1.InsertObject(cst);
  finally
    cst.Free;
  end;
end;

All published properties of the object will be automatically persisted on the Google Firebase cloud. This is how the data looks when inspecting it on the Firebase console

Note that we have explicitly set the unique ID of the object via the cst.ID property. When the ID is set at application level, it is the responsibility of the app to use unique IDs. When no ID is set, the AdvFirebaseObjectDatabase will automatically create a GUID as ID.

In this example, we have created a rather simple object with simple data types. But nothing prevents you from using class properties as in this example:

  TCareerPeriod = class(TPersistent)
  private
    FFinish: integer;
    FStart: integer;
  published
    property Start: integer read FStart write FStart;
    property Finish: integer read FFinish write FFinish;
  end;

  TFirebaseCustomer = class(TFirebaseObject)
  private
    FName: string;
    FStreet: string;
    FZIP: integer;
    FDoB: TDate;
    FCity: string;
    FPicture: TFireBasePicture;
    FCareer: TCareerPeriod;
    procedure SetCareer(const Value: TCareerPeriod);
  public
    constructor Create; override;
    destructor Destroy; override;
  published
    property Name: string read FName write FName;
    property Street: string read FStreet write FStreet;
    property City: string read FCity write FCity;
    property ZIP: integer read FZIP write FZIP;
    property DoB: TDate read FDoB write FDoB;
    property Career: TCareerPeriod read FCareer write SetCareer;
  end;

And now this code can be used to persist this slightly more complex object:
var
  cst: TFireBaseCustomer;
begin
  cst := TFireBaseCustomer.Create;
  try
    cst.Name := 'Elon Musk';
    cst.Street := '3500 Deer Creek Road';
    cst.ZIP := 2123;
    cst.City := 'Palo Alto';
    cst.DoB := EncodeDate(1975,03,21);
    cst.ID := '1241';
    cst.Career.Start := 2011;
    cst.Career.Finish := 2017;
    AdvFirebaseObjectDatabase1.InsertObject(cst);
  finally
    cst.Free;
  end;
end;

As you can see, more complex classes can be easily & automatically persisted in the Google Firebase cloud.


With respect to types of fields, there is one caveat though, Google Firebase doesn't offer out of the box support for binary blobs. Imagine that we'd want to persist a Delphi object that has a TPicture property. The TPicture is internally streamed in a custom way to the DFM (via the DefineProperties(Filer: TFiler); override) and the JSON persister does not automatically get this data. There is however an easy workaround to add a published string property to a class descending from TPicture and use this string to hold hex encoded binary data of the picture. The DataString property getter & setter methods use the StreamToHex() and HexToStream() functions that are included in the unit CloudCustomObjectFirebase:

  TFireBasePicture = class(TPicture)
  private
    function GetDataString: string;
    procedure SetDataString(const Value: string);
  published
    property DataString: string read GetDataString write SetDataString;
  end;


{ TFireBasePicture }

function TFireBasePicture.GetDataString: string;
var
  ms: TMemoryStream;
begin
  ms := TMemoryStream.Create;
  try
    SaveToStream(ms);
    Result := StreamToHex(ms);
  finally
    ms.Free;
  end;
end;

procedure TFireBasePicture.SetDataString(const Value: string);
var
  ms: TMemoryStream;
begin
  ms := HexToStream(Value);
  try
    LoadFromStream(ms);
  finally
    ms.Free;
  end;
end;


This way, we can extend the class to have a picture property:

  TFireBaseCustomer = class(TFirebaseObject)
  private
    FName: string;
    FStreet: string;
    FZIP: integer;
    FDoB: TDate;
    FCity: string;
    FPicture: TFireBasePicture;
    FCareer: TCareerPeriod;
    procedure SetPicture(const Value: TFireBasePicture);
    procedure SetCareer(const Value: TCareerPeriod);
  public
    constructor Create; override;
    destructor Destroy; override;
  published
    property Name: string read FName write FName;
    property Street: string read FStreet write FStreet;
    property City: string read FCity write FCity;
    property ZIP: integer read FZIP write FZIP;
    property DoB: TDate read FDoB write FDoB;
    property Career: TCareerPeriod read FCareer write SetCareer;
    property Picture: TFireBasePicture read FPicture write SetPicture;
  end;

and persist the object with picture via:

var
  cst: TFireBaseCustomer;
begin
  cst := TFireBaseCustomer.Create;
  try 
    cst.Name := 'Tim Cook';
    cst.Street := '1 Infinite Loop';
    cst.ZIP := 2123;
    cst.City := 'Cupertino';
    cst.DoB := EncodeDate(1975,03,21);
    cst.ID := '1242';
    cst.Picture.LoadFromFile('tim_cook.jpg');
    cst.Career.Start := 2006;
    cst.Career.Finish := 2017;

    AdvFirebaseObjectDatabase1.InsertObject(cst);
  finally
    cst.Free;
  end;
end;

To retrieve the objects back that were persisted, we can use:

var
  fbo: TFirebaseObject;
begin
  fbo := AdvFirebaseObjectDatabase1.ReadObject('1240');

  if Assigned(fbo) then
  begin
    if (fbo is TFirebaseCustomer) then
      ShowMessage((fbo as TFirebaseCustomer).Name+';'+(fbo as TFirebaseCustomer).City);
    fbo.Free;
  end;
end;



To persist a property change of the object, for example to change the career date of customer 1241 to 2018, we could write:

var
  fbo: TFirebaseObject;
begin
  fbo := AdvFirebaseObjectDatabase1.ReadObject('1241');

  if Assigned(fbo) then
  begin
    if (fbo is TFirebaseCustomer) then
    begin 
      ((fbo as TFirebaseCustomer).Career.Finish := 2018;
      AdvFirebaseObjectDatabase1.WriteObject(fbo);
    end;
  end;
end;

Working with generic lists


The previous samples all showed how to perform CRUD operations on single objects in the Google Firebase cloud. Our component TAdvFirebaseObjectDatabase also facilitates dealing with generic lists of objects. Imagine you want to persist a score table of game and have following simple classes to store this:

  TSimpleClass = class(TFirebaseObject)
  private
    FName: string;
    FScore: integer;
  published
    property Name: string read FName write FName;
    property Score: integer read FScore write FScore;
  end;

  TSimpleList = TList<TSimpleClass>;


With this class and its generic list, we can add a list of data at once in the Google Firebase cloud:

var
  sl: TFirebaseObjectList;
  sc: TSimpleClass;
  I: Integer;
begin
  sl := TFirebaseObjectList.Create;
  try
    sc := TSimpleClass.Create;
    sc.Name := 'Bruno';
    sc.Score := 48;
    sc.ID := '1';
    sl.Add(sc);

    sc := TSimpleClass.Create;
    sc.Name := 'Nancy';
    sc.Score := 83;
    sc.ID := '2';
    sl.Add(sc);

    sc := TSimpleClass.Create;
    sc.Name := 'Pieter';
    sc.Score := 17;
    sc.ID := '3';
    sl.Add(sc);

    sc := TSimpleClass.Create;
    sc.Name := 'Bart';
    sc.Score := 299;
    sc.ID := '4';
    sl.Add(sc);

    sc := TSimpleClass.Create;
    sc.Name := 'Wagner';
    sc.Score := 55;
    sc.ID := '5';
    sl.Add(sc);

    AdvFirebaseObjectDatabase1.TableName:= 'List';
    AdvFirebaseObjectDatabase1.InsertList(sl);

    for I := 0 to sl.Count - 1 do
      sl[I].Free;
  finally 
    sl.Free;
  end;
end;

Inspecting this on the Google Firebase console results in:



If at a later time we'd like to retrieve the score of Bart, we could use the code:

var
  c: TFirebaseObjectList;
  I: Integer;

begin
  AdvFirebaseObjectDatabase1.TableName := 'List';
  c:= AdvFirebaseObjectDatabase1.QueryList('Name', 'Bart');
  if Assigned(c) then
  begin
    for I := 0 to c.Count - 1 do
    begin
      ShowMessage((c[I] as TSimpleClass).Score.ToString);
      c[I].Free;
    end;
    c.Free;
  end;
end;

This performs a query on the List table for value 'Bart' set in the 'Name' field. The result of the query is a generic list (in case multiple matching results are found).

This was a glimpse at the TAdvFirebaseObjectDataBase component as an introduction for the new Google Firebase access features in the TMS Cloud Pack. Explore the full set of powerful capabilities of TAdvFirebaseObjectDataBase and the many other components in TMS Cloud Pack to make consuming cloud services in Delphi & C++Builder a piece of cake.


Bruno Fierens


Bookmarks: 

This blog post has received 5 comments. Add a comment.



TMS WebGMaps brings submarkers and extra options to load POI files

We're pleased to announce TMS WebGMaps v2.9 has been released today. TMS WebGMaps is our VCL component that exposes a myriad of geographical functions for integration in Delphi or C++Builder Windows applications.

In this new version, we introduce submarkers. When at a given position, more than one interesting item can be highlighted, it is now possible to add multiple items via submarkers at the same position and when the main marker is clicked, the submarkers are displayed.

In the sample, we've coupled different interesting items to see in Florida via submarkers for the marker at Florida. When the marker is clicked, different submarkers are displayed showing POIs such as Disney park, Cape Canaveral, Orlando resort... This technique keeps the number of simultaneously displayed markers light and only shows the detail when the user is interested and clicks the main marker.



Adding a marker with submarkers is very easy as this code snippet shows:

var
  m: TMarker;
  sm: TSubMarker;
begin
  m := WebGMaps1.Markers.Add(WebGMaps1.MapOptions.DefaultLatitude, WebGMaps1.MapOptions.DefaultLongitude);
  m.Title := 'Florida Landmarks';

  sm := m.SubMarkers.Add;
  sm.Title := 'Walt Disney World';

  sm := m.SubMarkers.Add;
  sm.Title := 'Cape Canaveral';

  ....

end;

In the new version, we have also refined the functions to load & save markers in POI file format. A POI file is a file that contains geocoordinates and description of places of interest. Now it is also possible to specify custom marker images when loading POI files. TMS WebGMaps can handle the POI file format as used by well-known navigation software such as Garmin, Tomtom, Route66, Becker, ...
There is a wealth of already existing POI files you can directly use with TMS WebGMaps. A resource of millions of POI files for 221 countries is for example www.poiplaza.com. In our sample, we have demonstrated this by loading a POI containing for example the IBIS hotels and movie theatres in Germany.



The code needed for this is just two lines:

    WebGMaps1.Markers.LoadFromPOI(FilePath + 'D-Cinema.csv', FilePath + 'projector_24.png');
    WebGMaps1.Markers.LoadFromPOI(FilePath + 'D-IbisHotel.csv', FilePath + 'ibis_24.png');

It refers to the POI filename and the (local) marker image to use. The WebGMaps component does all the needed things to show the custom Ibis image marker on the map in Germany for the Ibis hotel locations and the movie theatre image for the movie theatre locations.

We look forward to learn about your interesting integrations of TMS WebGMaps in your applications!

Bruno Fierens


Bookmarks: 

This blog post has not received any comments yet. Add a comment.



Browser push notifications for announcements from tmssoftware.com

Monday, June 19, 2017

We are pleased to inform that from today, there is an additional channel, you can opt-in for, to keep in the loop with the news from tmssoftware.com.
For some time already, all our news is announced on our social media channels Twitter, Facebook, Google+ and LinkedIn and via a mailing list:

   

and from now on, for users with an account on our website, there is also the possibility to be informed via browser push notifications:



These browser push notifications are at this time a built-in notification mechanism of the Google Chrome and Firefox browsers. When you login on our website, you can opt-in to receive these push notifications when clicking "Allow" on the prompt:



With the new notification system inplace, you'll be aware of news from tmssoftware.com when you just open your browser, so you really can't miss news anymore!

Bruno Fierens


Bookmarks: 

This blog post has not received any comments yet. Add a comment.



Generating customer loyalty cards, event tickets, coupons, boarding passes for the smartphone with TMS PassKit

With iOS 9 and iPhone 6, Apple introduced the digital wallet on your smartphone. It is a system that holds passes to redeem rewards, get movie tickets, use discount coupons, get boarding passes for transport, offer prepaid cards etc.. An introduction to using the iPhone Wallet on an iPhone or iPod touch can be found here.
The pass for the iPhone or iPod is nothing more than a digitally signed file that can be distributed via a download, attached to an email, shared via AirDrop, ...

To facilitate generating such wallet PassKit files, we have released a new product TMS PassKit. TMS PassKit handles all the complexities of the signing of the files and has support for all PassKit type passes: coupons, tickets, store cards, traffic pass, generic pass ... It makes generating a wallet file as easy as setting up properties and call TMSPassKitBuilder.Generate() to generate the file. This component can make is really easy to automatically send out a wallet file with a loyalty card to all your customers, send tickets for inviting people to an event, create payment cards for employees and more...

This is an example wallet file that was created with TMS PassKit for a sample event: TMS training day 2017:

PassKit frontPassKit back

As you can see the wallet file can have both a front and back side. The appearance of the front can be customized via various settings, images can be added and as can be seen here, optionally, it can include a barcode in different formats.
The back of the card can contain additional fields and when these fields include an email, phone number, URL, date, ... this can be used to link to the mail app, calendar app, phone, ...

Wallet files have more important features, such as location sensitivity, beacon sensitivity, NFC coupling. With these features, supported from TMS PassKit, it is possible to make a pass only active in the neighbourhood of a specific location or beacon and do a transaction via NFC.
Finally, a wallet pass file also has built-in support for localization. Content for multiple languages for the wallet pass can be setup via TMS PassKit. Users with their smartphone configured in a specific language will see the wallet pass in their language of choice.

We are pleased that from today, TMS PassKit is released and available as standalone product but it is also part of the TMS VCL Subscription and TMS ALL-ACCESS. So, customers with an active subscription to either of these subscriptions have received this product for free today.
Head over to the TMS PassKit product page and discover the new possibilities you can add to your Delphi applications for creating wallet files for your users, customers, employees, network, friends, ..

Bruno Fierens


Bookmarks: 

This blog post has received 2 comments. Add a comment.



Function approximation with TMS Analytics and Physics numerical tools

The problem of data approximation (curve fitting, surface fitting) arises from many areas: economics, physics, informatics and many others. There are many libraries, realizing numerical tools for using the approximation in software applications. The TMS Analytics and Physics pack contains the approximation numerical tool which has one unique feature – it is totally integrated with symbolic calculus. Using symbolic expressions with the numerical approximation gives the developer many advantages.

Let us consider a simple case of using the approximation tool for curve fitting (one-dimensional approximation). For this case we have a set of points Pi=(xi,yi), i=1..N. From the programming point of view we just have two arrays of real values, say X and Y. The approximation problem is to build a function y=f(x) which is close to the set of points. The most popular approach of the approximation is the linear least squares (https://en.wikipedia.org/wiki/Linear_least_squares_(mathematics)). With TMS approximation tool the problem can be solved in five lines of code:

var
  approximator: TLinearApproximator;
  basis: TLinearBasis;
  variables: TArray;
  functions: TArray;
  cValues: TArray;
begin
  variables:= TArray.Create('x'); // 1
  functions:= TArray.Create('e^x', 'sin(x)', 'e^-x', 'x^2', '3^x',   'sinh(2*x)'); // 2
  basis:= TLinearScalarBasis.Create(variables, 'C', nil, functions); // 3
  approximator:= TLinearLeastSquares.Create; // 4
  cValues:= approximator.Approximate(basis, X, Y); // 5
  
  // Using the basis with optimal coefficient values.
end;
Line 1: Create the array of variable names, as this is 1D approximation, there is one variable name ‘x’ in the array.
Line 2: Create the array of approximation functions (basis functions). The functions only depend on the ‘x’ variable. The type and the number of the basis functions can be arbitrary.
Line 3: Create the basis instance with the specified arguments. The ‘C’ argument specifies the name of approximation coefficients. The ‘nil’ argument tells that there is no parameters in the functions.
Line 4: Create the appropriate approximator instance. For the linear least squares approximation it is ‘TLinearLeastSquares’;
Line 5: Calculate the approximation coefficients for the specified basis and arrays of points ‘X’ and ‘Y’.

After the optimal coefficients found, we can evaluate the basis in any point and make other analytical manipulations. As example, here is the plotted approximation function with the original data points on the picture.

The main feature of the TMS numerical tools is they are totally integrated with the symbolic calculus. It brings the following advantages to the developer:
- Minimal code writing, because there is no need to write special classes for the function method references (delegates) as in other numerical libraries.
- Convenient data representation for the developer and user as math expressions, not as programming code.
- Easily using the user input data (string data) for manipulations in programming code.
- Almost unlimited choice of math expressions for manipulations, including special functions.
- Easily transfer input data and the output results via network as strings, easily storing and serializing the data.

The result of the approximation can be easily used with other numerical tools. For example, we can analyze the approximation function for the roots and special points – extremums. The code for the analysis is the following:
var
  f: string;
  sf1D: TSymbolicFunction1D;
  opt: TSolverOptions;
  points: TArray;
begin
  f:= basis.Evaluate(cValues); // 1 
  sf1D:= TSymbolicFunction1D.Create('x', f); // 2 
  opt:= TSolverOptions.Create(true);  // 3
  points:= TFunctionAnalyser.Analyse(sf1D, TNewton, opt, -2, 3, 10); // 4 
  
  // Using the points array.
end;

Line 1: Make the function expression with optimal coefficient values.
Line 2: Create the symbolic function instance for the analysis.
Line 3: Create default options for the nonlinear solver (which used for the function analysis).
Line 4: Finding all function's special points on the interval [-2..3]. The Newton’s method used for finding roots and extremums of the function which specified with the second argument.

The result of the analysis – function’s roots and extremums, presented on the picture below.

The TMS Analytics and Physics pack includes the library with 5 ready-to-use numerical tools totally integrated with analytical features, such as symbolic derivatives. The version can be downloaded from the product page. There is the source code example for all numerical tools with the new version download.

Bruno Fierens


Bookmarks: 

This blog post has not received any comments yet. Add a comment.




Previous  |  Next  |  Index