PureMVC Architects Lounge

Announcements and General Discussion => Architecture => Topic started by: Jiri on April 15, 2008, 02:38:48



Title: AIR - Sqlite Proxy object
Post by: Jiri on April 15, 2008, 02:38:48
Hello list,

first-off I am a bit of a newbie to using pureMVC, but so far it feels very nice to work with. I want to make a small test AIR application to get familiar with the frame work. The app will be using the Sqlite database so I will be creating a SqliteDatabaseProxy.I am just having some design questions.

I am creating a SqliteDatabaseProxy which extends Proxy. This class has a method  initialize(databaseName:String , location:File) which checks if the db file excists if not creates is and opens a Async connection using dbaseConnection.openAsync( dbFile ), where dbaseConnection is an instance of SQLConnection. After all this, a sendNotification is called to notify observers.

Considering the fact that this SqliteDatabaseProxy is only there to establish, verify and serve a database connection, I might need another Proxy object, let call it QueryProxy, that deals with the querys like CREATE,INSERT and UPDATE.
Do I then have to give QueryProxy and instance of SqliteDatabaseProxy and then implement an EventDispatcher in the SqliteDatabaseProxy so that the QueryProxy can addListeners to the SqliteDatabaseProxy and based on that send notifications to the rest of the system.
Or do I have then SqliteDatabaseProxy and the QueryProxy communicate which each other through notifications only.
Or do I just forget about two Proxy objects and just use one that deals with everything, where in this case I give up my goal to create a re-useable SQlite class.

I hope my questions are clear and that somebody can advise me.

Jir


Title: Re: AIR - Sqlite Proxy object
Post by: puremvc on April 15, 2008, 03:08:45
You might take a look at the way thr AIR XML Database utility works. Of course it will differ quite a bit, but it might be a useful exercise.

-=Cliff>


Title: Re: AIR - Sqlite Proxy object
Post by: Jiri on April 15, 2008, 03:43:15
Thank you for the quick reply. I came across it and am using it as a base, I just would like to figure out how to make the SQliteProxy into a reusable object, so up to a certain point I can follow the same logic as in the SerializationProxy. I am just wondering where to put the query logic and if I need to seperate that into a seperate Object.

J


Title: Re: AIR - Sqlite Proxy object
Post by: puremvc on April 15, 2008, 07:10:39
Well, the direction was heading with the XML Database as a suggestion was really not so much its implementation as how it achieves reusability by subclassing.

You might extend your SQLLiteProxy it and override the query methods in your concrete subclasses, rather than putting that logic in a separate class and being concerned about how to collaborate with the database class.

You might even create an ISQLProxy interface which this SQLLiteProxy implements. That would leave room for writing other ISQL Proxy classes (when it becomes possible to talk to something other than SQLLite).

Then, an app using the SQLLiteProxy would really cast and manipulate an ISQLProxy and never an SQLLiteProxy. Later when, say MySQL becomes available to AIR via an Adobe supported driver, a new MySQLProxy is written for it that implements this interface, and bada-bing, you can treat the two interchangably and swap them out without having to refactor the rest of the app.

-=Cliff>


Title: Re: AIR - Sqlite Proxy object
Post by: Jiri on April 15, 2008, 07:33:11
Ok, let me see if I get this correct. Instead of programming to the concrete class SQLLiteProxy, I should program to an interface, namely the ISQLProxy.
This ISQLProxy could define methods like getConnection() , initialize() , doQuery(SQLstatement) , etc.
If i understand this correctly that means that all the database handling is done inside a concreteclass that implements the ISQLProxy. How would I then deal with the possible async nature of the queries. Do I make for every ERROR, UPDATE  ,CREATE etc a command object and register those commands

If I look at the XML example, the Async methods signature defines a responder, this implies that composition is used. So I should probably have a Proxy that holds an instance of ISQLProxy (_dbase:ISQLProxy) and program to that interface. This way _dbase can be changable.
So basically I am then following the logic AIR XML Database utility, because I also intend to use responders and eventListeners.

I need to study that utility again, being more of a flash designer it is a hard and slow process entering the arena of OOP and the whole lot :)

Jiri



Title: Re: AIR - Sqlite Proxy object
Post by: Jiri on April 16, 2008, 09:50:54
To get things clear for myself and to practice, i did a scheme. I was wondering if someone has time to reflect on it and possible give some feedback. It is very crud, but should display my intentions.

Thank you,

Jiri


Title: Re: AIR - Sqlite Proxy object
Post by: Rhysyngsun on April 16, 2008, 10:14:22
Jiri, you'll also have to take into consideration that if you're using an asynchronous connection, methods such as getContacts won't be able to return a value immediately as your proxy will have to listen for a result event (and also error events) on the SQLConnection and then send the value off via a notification. Of course if your query results are expected to be small, you may find you are able to get away with a synchronous connection.


Title: Re: AIR - Sqlite Proxy object
Post by: Jiri on April 16, 2008, 10:38:42
Rhysyngsun, thnx for having a look at it and the comment. I realize the async nature and I am working on how to deal with that. As I see it now the notifications should indeed be called by the SQLProxy . Because the SQLProxy holds a reference to the concrete Class SQLiteDatabase I probably need to addListeners to the SQLiteDatabase i.e. SQLProxy.databaseRef.addEventListener(.onResult / onError) or register a responder like it is done in the Serialization Proxy example. Somehow I cant decide which one is the best one. I feel like adding dispacthers to the SQLiteDatabase that the SQLProxy can listen to is a messy solution and that defining a responder and have it implement an interface is a much cleaner solution.
I am right on this?

Jiri


Title: Re: AIR - Sqlite Proxy object
Post by: Rhysyngsun on April 16, 2008, 10:58:06
I think eitehr way will be fine, the only difference is that with Notifications you would be able let other parts of you application respond to the events in a PureMVC way (i.e., on an error, update the UI to show an error message). The biggest difference is that the proxies are decoupled from each other and you don't have to worry about adding/removing listeners with notifications. Either way, though you're going to need something to discern what kind of result you're getting. I personally might even go so far as to write a custom Event subclass for this, this way I could customize the interaction between the proxies as much as possible.


Title: Re: AIR - Sqlite Proxy object
Post by: puremvc on April 16, 2008, 12:59:22
I might need another Proxy object, let call it QueryProxy, that deals with the querys like CREATE,INSERT and UPDATE.

From the original conversation, I wasn't expecting the ISQLProxy to have methods like AddSmsToArchive. More like add, change, delete. Clearly an ISQlProxy/SQLProxy implemented like this within your app would achieve the benefit of allowing easy migration to another database later. However it wouldn't make ISQLProxy/SQLProxy reusable outside your application domain.


Considering the fact that this SqliteDatabaseProxy is only there to establish, verify and serve a database connection, I might need another Proxy object, let call it QueryProxy, that deals with the querys like CREATE,INSERT and UPDATE.
Do I then have to give QueryProxy and instance of SqliteDatabaseProxy and then implement an EventDispatcher in the SqliteDatabaseProxy so that the QueryProxy can addListeners to the SqliteDatabaseProxy and based on that send notifications to the rest of the system.

Lets go back to the idea of an SQLLiteDatabaseProxy, and make that implement ISQLDatabaseProxy. Its responsibility is as you describe, to establish, verify and serve a database connection. It might even subclass SQLDatabaseProxy which would define the most reusable properties and methods of an ISQLDatabaseProxy implementer. This lets us vary the database implementation at this level.  In your app you would subclass SQLLiteDatabaseProxy as something like SMSAppDatabaseProxy, and initialize it with what is necessary to create the concrete DB from scratch or to access it if it exists. Later SMSAppDatabaseProxy could be changed to extend a MySQLAppDatabaseProxy if such a database migration takes place.

Then you have ISQLQueryProxy, which would manage the preparation and execution of a query via its relationship with an ISQLDatabaseProxy implementer. An abstract SQLQueryProxy class would define things like a protected query property. The data property would be the result set. It would need to have result and fault methods to act as a responder, etc. SQLLiteQueryProxy would subclass SQLQueryProxy to override or add SQLLite specific functionality for the required interface methods. These need to be general methods that are focused on the management of a query or its result set.

Then classes like SMSArchiveProxy or ContactProxy would subclass SQLLiteQueryProxy, which could use their inherited ability to prepare and execute SQLQueries to encapsulate what is needed to manage these entities. These proxies can also add methods like addSmsToArchive. These are manipulated by the Commands, Mediators or other Proxies of the PureMVC app. It isn't necessary for these other actors to make ISQLQueryProxy interface calls. addSmsToArchive might be called by a Command, which internally triggers preparation and execution of the query via ISQLQueryProxy interface methods.

When you do your model preparation, you'd instantiate and register a MySQLAppDatabaseProxy, and likely have it create or connect at to the db at onRegister time. Then you'd create and register SMSArchiveProxy and ContactProxy and any others. They would retrieve the MySQLAppDatabaseProxy by name and use an interface method to execute their queries. The MySQLAppDatabaseProxy would set the ISQLQueryProxy implementers as responders for their calls. Mind your AsyncTokens.

-=Cliff>


Title: Re: AIR - Sqlite Proxy object
Post by: Jiri on April 18, 2008, 03:08:11
Cliff, thank your for the ellaborate explaniation. It is helping me a lot, allthough I am having a hard time to get my head around it! Can you please tell me a bit more about what you mean with this
An abstract SQLQueryProxy class would define things like a protected query property.
Do you mean by that a static var INSERT = 'INSERT INTO ....', or could you give an example?

Then I also dont really understand this in the last sentence.
The MySQLAppDatabaseProxy would set the ISQLQueryProxy implementers as responders for their calls. Mind your AsyncTokens

Here is also a new scheme, am I on the right track?
Jiri



Title: Re: AIR - Sqlite Proxy object
Post by: puremvc on April 18, 2008, 09:05:45
Jiri,

You are on top of it. This diagram is nearly there. The only thing missing (I think), is the thing you call out to for clarification; the abstract SQLQueryProxy class.

Your diagram has ContactProxy implementing ISQLQueryProxy. And it would, so the diagram is not invalid.

I'm suggesting that there would be an SQLQueryProxy utility class that implements this interface. ContactProxy would implement ISQLQueryProxy by extending SQLQueryProxy and overriding the methods it needs.

I think that the SQLQueryProxy will want to have a protected property for its query. So that you can set a query on the Proxy but invoke it at a later time. Or reinvoke the same query more than once.

Also, the any ISQLQueryProxy may want to take an action when its query property is set, perhaps validating it to make sure it the user hasn't attempted an SQL injection in data input, or updating an associated Proxy. Therefore, creating a protected getter and setter for this property on SQLQueryProxy that calls a boolean validate method and only sets the _query property if validate returns true. The SQLQueryProxy's validate method could simply return true. ContactProxy and any other SQLQueryProxy could override this method if it wishes to perform special validation.

If execute is called with no argument, then you validate and execute the query that's in the query property.

The execute method could still take an *optional* string. If present it would set the query property equal to this, validate it, perhaps and then attempt to execute it.

Also, it would be good to provide for parameter replacement in queries with arguments. I don't see if SQLLite can do this or not, but the SQLQueryProxy could do it as an in-Proxy preparation of the query. You'd have a template property and an arguments property. In the same way that the setting of the query property triggers validation, setting the arguments property would do parameter replacement on the template from the arguments, and then set the query property with the replaced parameters, ready to execute.

-=Cliff>


Title: Re: AIR - Sqlite Proxy object
Post by: Jiri on April 19, 2008, 01:48:04
Cliff,

Good to hear that I am on the right track. Just one more question could you please explain or provide an example about this part:

Also, it would be good to provide for parameter replacement in queries with arguments. I don't see if SQLLite can do this or not, but the SQLQueryProxy could do it as an in-Proxy preparation of the query. You'd have a template property and an arguments property. In the same way that the setting of the query property triggers validation, setting the arguments property would do parameter replacement on the template from the arguments, and then set the query property with the replaced parameters, ready to execute.


Title: Re: AIR - Sqlite Proxy object
Post by: puremvc on April 19, 2008, 08:08:30
Parameterized queries could be left off for now if SQLLite doesn't support it.

Such would be a query template like 'SELECT * from %1 WHERE %2 LIKE %3' and you'd pass 3 arguments, which would in order be used to replace the place holders in the template.

-=Cliff>


Title: Re: AIR - Sqlite Proxy object
Post by: Jiri on April 19, 2008, 11:10:02
Ok, thats what you meant and yes SQlite does support it!!


Title: Re: AIR - Sqlite Proxy object
Post by: Rhysyngsun on April 19, 2008, 03:10:15
Jiri, another recommendation I'd make with you SQL code is to code any table or row names as constants and simply concatenate them into your query strings. That'll avoid any typos that could potentially cause issues. This would also allow you to refactor your tables quickly although you'd still have to delete your local data store.


Title: Re: AIR - Sqlite Proxy object
Post by: Jiri on April 21, 2008, 01:30:53
Would it be considered good practice if I would create custom made notifiers that extends the Notification class and have them add to a proxy as responders. Like so
:
ISQLiteErrorResponder extends Notification
ISQLiteResultResponder extends Notification

function doQuery(queryString , ISQLiteErrorResponder , ISQLiteResultResponder):void
{
//do stuff and listen to the sql callback using flash eventlisteners to fire the responders
//only how to remove listeners, without having both responder know about each other
}
Jiri


Title: Re: AIR - Sqlite Proxy object
Post by: Jiri on April 21, 2008, 01:33:43
Rhysyngsun, does one put constants in a UML scheme? I am new to UML, but want to learn. Allready in this thread it has proven me that it is a nice way to communicate code concepts :)

Jiri


Title: Re: AIR - Sqlite Proxy object
Post by: Rhysyngsun on April 21, 2008, 05:45:07
Rhysyngsun, does one put constants in a UML scheme? I am new to UML, but want to learn. Allready in this thread it has proven me that it is a nice way to communicate code concepts :)

Jiri

I'm not sure as I don't use UML myself (I typically diagram on paper). I believe Cliff is more familiar with it than I.

I forgot to mention, those constants should be protected as well since only the Proxy would know about the structure of the database, so no need to expose them publicly.


Title: Re: AIR - Sqlite Proxy object
Post by: puremvc on April 21, 2008, 05:53:43
The custom notification as responder idea doesn't really sound right.

Typically the Proxy is long lived and having it be a responder doesn't lead to any GC issues.


Title: Re: AIR - Sqlite Proxy object
Post by: puremvc on April 21, 2008, 05:55:07
Sure you can put your constants in the UML class diagrams.

-=Cliff>


Title: Re: AIR - Sqlite Proxy object
Post by: skipintro on April 29, 2008, 05:02:40
Hi,

I tried a different approach to access the local sqlLite DB from flex. Rather using proxies to handle my database logic, I let the the proxy only know little about the "service" and wrote the logic to a delegate. This way its easier to reuse the proxy and its logic if you want to exchange the "database service" to a "remoting service" for instance.

The implementation inside the proxy class then looks like this:
:

public class PageDataProxy extends Proxy implements IProxy, IDelegateResponder
{

.....

// service IDs
private static const _LOAD_PAGE:String = "loadPage";

.....

public function loadPage( id:int ):void
{
     // accessing a remote service
     new RemoteDelegate( "GetPageDocument", [id, ""], this, _LOAD_PAGE ).execute();
  
     // or optional

     // accessing a local database
     // new LocalDBDelegate( "SELECT * FROM....",  LocalDBDelegate.MODE_SYNC, this, _LOAD_PAGE ).execute();

}

public function onDelegateResult( serviceid:String, data:Object ):void
{
switch( serviceid )
{
case _LOAD_PAGE:

// parse xml page data to PageVO
parsePageData( data as XML );

// send notification
sendNotification( ApplicationFacade.PROXY_PAGE_LOADED );
break;
}
}

public function onDelegateFault( serviceid:String, data:Object ):void
{
     sendNotification( ApplicationFacade.PROXY_ERROR, serviceid );
}

.....


Please note, that the static LocalDBDelegate.init() method must be called before any DB operations. You can do this within the ModelPrepCommand or at any other point. See attachment for details.

Thomas



Title: Re: AIR - Sqlite Proxy object
Post by: neil on July 31, 2008, 06:14:40
Has anybody had any sucess with any of these suggestions for integrating SQLite?

I'm very new to all this... only started looking at Flex last month and came onto PureMVC 2 days ago.

I've read the Best Practices doc three times so that it is starting to sink in, but there's still a lot of terminology etc. that I still don't understand.

I'm hacking away at the EmployeeAdmin example and would love to know if anyone has got SQLite to populate the data.

I've downloaded the delegates zip from the above post, but really don't know where to start.

Any help would be really appreciated as I'm fumbling around in the dark at the moment!

Many thanks,

Neil


Title: Re: AIR - Sqlite Proxy object
Post by: skipintro on July 31, 2008, 07:06:52
Hi Neil,

the LocalDBDelegate class (or any other delegate) can be used by any class that implements the IDelegateResponder interface.
In PureMVC AIR Projects I usually use them with Proxies in order to write in or retrieve data from the local SQLite DB.

If you dig into the framework at the moment, you might already know that Proxy Classes are generally used to manipulate and read from data entities (VOs). In case you want to retrieve or write from any other location than your programms memory, Delegates can come into play in order to handle more complex data oprations such as remote or local db calls. The key benefit of these "helper classes" is reusability, as you dont have to write db or remote code inside your proxy again and again.

I hope I could help...

Thomas





Title: Re: AIR - Sqlite Proxy object
Post by: neil on July 31, 2008, 08:29:35
Hi Thomas.

Thanks for your reply. Forgive my me sounding stupid, but...
Where do the files in your zip file go in relation to the proxy?
I'm using the EmployeeAdmin demo and I want to be able to pull in the user data from SQLite.

I've put them in the model directory (I don't know if this is right) and I've tried adding:

public class UserProxy extends Proxy implements IProxy, IDelegateResponder

to my proxy as per your example, but I get error:
1044: Interface method onDelegateFault in namespace org.puremvc.as3.demos.flex.employeeadmin.model:IDelegateResponder not implemented by class org.puremvc.as3.demos.flex.employeeadmin.model:UserProxy

I've not come accross delegates before so don't know how they work.

Any nudges in the right direction you could give wuold be appreciated!

Cheers,

Neil




Title: Re: AIR - Sqlite Proxy object
Post by: skipintro on July 31, 2008, 09:07:05
Hi Neil,

I usually put the Delegate Classes inside a "utility" package and import them to my project. Optionally, you can  leave them inside your applications model package for testing purposes. As long as your imports work, thats fine...

in order to make use of the LocalDBDelegate you need to:

1. implement the IDelegateResponder interface ( as you already did )
2. implement the 3 methods, the last 2 defined by the IDelegateResonder interface, similar to this

:
public function loadPage( id:int ):void
{
       new LocalDBDelegate( "CREATE TABLE 'users' .... ",  LocalDBDelegate.MODE_SYNC, this, null ).execute();
}

public function onDelegateResult( serviceid:String, data:Object ):void
{
    // this method is called by the Delegate after the query has been sucessfully executed
}

public function onDelegateFault( serviceid:String, data:Object ):void
{
   // this method is called by the Delegate, if the query has caused an error
}


Your code is probably only missing the "onDelegateFault" method as stated in the error message you received.
Do not forget to call the static "init()" method of the LocalDBDelegate class prior to any db operations.

Good luck ;)
Thomas


Title: Re: AIR - Sqlite Proxy object
Post by: neil on July 31, 2008, 09:41:35
Hi Thomas.

Okay, the errors have gone, but how do I call 'the static "init()" method of the LocalDBDelegate class prior to any db operations'.

This is all very new to me so as simply as possible, please!!

Cheers,

Neil



Title: Re: AIR - Sqlite Proxy object
Post by: skipintro on August 01, 2008, 12:25:36
Hi Neil,

call the static init() Method of the LocalDBDelegate class within the execute method your ModelPrepCommand or any other location prior to any db operationslike this:

:
var file:File = File.applicationStorageDirectory;
LocalDBDelegate.init( file );

greets
thomas


Title: Re: AIR - Sqlite Proxy object
Post by: neil on August 01, 2008, 02:08:41
Hi Thomas.

Okay, I'm getting somewhere. The query is executing, but how do I set the responder?

I can see that LocalDBDelegate gets passed by responder:IDelegateResponder = null

:
public function LocalDBDelegate( query:String, mode:String = MODE_SYNC, responder:IDelegateResponder = null, serviceid:String = "" )
{
super( serviceid, responder );

m_query = query;
m_mode = mode;
}

and that in IDelegateResponder.as we have:

:
public interface IDelegateResponder
{
function onDelegateResult( serviceid:String, data:Object ):void;
function onDelegateFault( serviceid:String, data:Object ):void;
}


but it's not getting to IDelegateResponder.as

I really appreciate your help!

Cheers,

Neil


Title: Re: AIR - Sqlite Proxy object
Post by: skipintro on August 01, 2008, 02:22:53
hi neil,

if you take a look at my previous post ( the one with the loadPage example ) you can see, that "this" is passed to the constructor of the LocalDBDelegate as the "responder". As this class is probably a proxy that implements the interface, this is also the place ( with the onDelegateResult method), where the response is called by the Delegate.

Greets Thomas



Title: Re: AIR - Sqlite Proxy object
Post by: neil on August 01, 2008, 03:08:04
Wow! it's working!  ;D

Thanks a lot Thomas, this will hopefully keep me busy for a while!

I really appreciate your help, I thought I would never get my head around this, but it's slowly sinking in.

Cheers,

Neil



Title: Re: AIR - Sqlite Proxy object
Post by: neil on August 01, 2008, 03:15:30
One more question :D
If I want to pass parameters into the sql, do I just create the sql string e.g.

:
new LocalDBDelegate( "SELECT * FROM tblrooms WHERE iRoomIDPK = " + id, LocalDBDelegate.MODE_SYNC, this, "" ).execute();

Cheers,

Neil


Title: Re: AIR - Sqlite Proxy object
Post by: skipintro on August 01, 2008, 03:43:52
Yeah, you can actually pass an query / variables string to the delegates constructor.

Greets Thomas