SQLite Example

Overview

An example app demonstrating basic SQLite usage in Loom. You can create tables and insert/select from them given default query strings, or customize your own query strings and process any SQLite statements that you wish. The demo also outputs the time that each of your query batches takes.

Try It

Use the following Loom CLI commands to run this example:

loom new MySQLiteExample --example SQLiteExample
cd MySQLiteExample
loom run

Screenshot

SQLiteExample Screenshot

Code

src/SQLiteExample.ls

package
{
    import loom.Application;
    import loom2d.display.StageScaleMode;
    import loom2d.display.Image;
    import loom2d.textures.Texture;
    import loom2d.ui.SimpleLabel;
    import loom2d.events.Event;

    import loom.sqlite.Connection;
    import loom.sqlite.Statement;
    import loom.sqlite.ResultCode;
    import loom.sqlite.DataType;

    import feathers.controls.*;
    import feathers.events.FeathersEventType;
    import feathers.themes.MetalWorksMobileTheme;

    import loom2d.text.TextField;   
    import loom.platform.Timer; 
    import loom2d.text.BitmapFont;

    /**
     *  Simple example to demonstrate SQLite
     */

    public class SQLiteExample extends Application
    {
        const numRows:int = 9;
        const numColumns:int = 8;

        var connection:Connection;
        var statement:Statement;
        var queryInput:TextInput;
        var countInput:TextInput;
        var timeLabel:Label;
        var tableNameLabel:Label;
        var outputLabel:Label;
        var param1Input:TextInput;
        var param2Input:TextInput;
        var param3Input:TextInput;
        var loadingOverlay:Image;
        var grid:Vector.<Vector.<Button>> =[];      
        var paramInputs:Vector.<TextInput> = [];
        var theme:MetalWorksMobileTheme;

        override public function run():void
        {
            TextField.registerBitmapFont(BitmapFont.load("assets/arialComplete.fnt"), "SourceSansPro");
            TextField.registerBitmapFont(BitmapFont.load("assets/arialComplete.fnt"), "SourceSansProSemibold");
            theme = new MetalWorksMobileTheme();  

            stage.scaleMode = StageScaleMode.LETTERBOX;

            //initialize the UI
            initTemplateButtons();
            initInputControls();
            initOutputGrid();
            initRestOfUI();

            loadingOverlay = new Image(Texture.fromAsset("assets/loading_bg.png"));
            loadingOverlay.scale = 2;
            loadingOverlay.alpha = 0;
            stage.addChild(loadingOverlay);


            //create / open connection
            openConnection();

            //select the whole table to display in our grid
            if (prepareStatement("SELECT * FROM EXAMPLE_TABLE", false) == 0)
                return;
            displayData(); 
        }

        private function newLabel(width:Number, height:Number, x:Number, y:Number, text:String=""):Label
        {
            var label = new Label();
            label.width = width;
            label.height = height;
            label.x = x;
            label.y = y;
            label.text = text;
            stage.addChild(label);

            return label;
        }


        private function newButton(width:Number, height:Number, x:Number, y:Number, label:String="", f:Function=null):Button
        {
            var button = new Button();
            button.width = width;
            button.height = height;
            button.x = x;
            button.y = y;
            button.label = label;
            button.addEventListener(Event.TRIGGERED,f);
            stage.addChild(button);

            return button;
        }


        private function newInputBox(width:Number, height:Number, x:Number, y:Number, prompt:String=""):TextInput
        {
            var inputBox = new TextInput();
            inputBox.width = width;
            inputBox.height = height;
            inputBox.x = x;
            inputBox.y = y;    
            inputBox.prompt = prompt;
            inputBox.maxChars = 100; 
            inputBox.isEditable = true;  

            stage.addChild(inputBox);

            return inputBox;
        }

        private function initRestOfUI()
        {
            var runQueryButton = newButton(150, 45, 12.5, 215, "run query", startQuery);
            timeLabel = newLabel(250, 45, 300, 230, "Query duration:");
            tableNameLabel = newLabel(500, 55, 12.5, 275, "Table name:");
            outputLabel = newLabel(stage.stageWidth-25, 45, 12.5, 600, "");
        }

        private function initTemplateButtons()
        {
            var createQueryButton = newButton(100, 40, 12, 5, "CREATE", function(){queryInput.text = "CREATE TABLE example_table(id varchar(255), name varchar(255), surname varchar(255))";});
            var selectQueryButton = newButton(100, 40, 117, 5, "SELECT", function(){queryInput.text = "SELECT * FROM example_table";});
            var insertQueryButton = newButton(100, 40, 222, 5, "INSERT",insertTemplate);
            var dropQueryButton = newButton(100, 40, 327, 5, "DROP", function(){queryInput.text = "DROP TABLE example_table";});
            var clearQueryButton = newButton(100, 40, stage.stageWidth-112.5, 5, "CLEAR", function(){queryInput.text = "";});
        }

        private function initInputControls()
        {
            queryInput = newInputBox(stage.stageWidth - 25, 100, 12.5, 50, "SQL query");
            queryInput.maxChars = 300;

            for (var i = 0; i<numColumns;i++)
            {
                var paramInput = newInputBox(114, 40, 12.5 + 117 * i, 165, "param" + (i+1).toString());
                paramInputs.push(paramInput);
            }

            countInput = newInputBox(100, 40, 175, 220, "run count");                    
            countInput.maxChars = 7; 
        }

        private function insertTemplate()
        {
            queryInput.text = "INSERT INTO example_table VALUES (?,?,?)";
            paramInputs[0].text = "1";
            paramInputs[1].text = "Joe";
            paramInputs[2].text = "Soap";
        }

        //Bring up loading overlay then run query
        private function startQuery()
        {
            loadingOverlay.alpha = 0.75;
            var timer = new Timer(50);
            timer.start();
            timer.onComplete = function(){runQuery();};
        }

        //Runs query, analyzes SQL string to determine SQLite function then calls relevent functions
        private function runQuery()
        {
            //Get the run count from the input box and validate it
            var runCount = 1;
            if (!String.isNullOrEmpty(countInput.text))
            {
                runCount = Number.fromString(countInput.text);
            }
            if (runCount == 0)
            {
                runCount = 1;
                countInput.text = "1";
            }

            var queryString = queryInput.text.toLocaleUpperCase();
            var start = 0;
            var time = 0;

            //if the query is not a select, check if it is an insert so we can bind the parameters
            if (queryString.indexOf("SELECT ") == -1)
            {
                start = Platform.getTime();
                 if (queryString.indexOf("INSERT ") > -1)
                 {
                    var paramCount = queryString.split("?").length - 1;
                    connection.beginTransaction();
                    if (prepareStatement(queryString) == 0)
                        return;
                    for (var i = 0; i < runCount; i++) 
                    {
                        for (var l = 1; l <= paramCount; l++)
                        {
                            statement.bindString(l, paramInputs[l-1].text);
                        }

                        statement.step();
                        statement.reset();
                    }
                    connection.endTransaction();
                 }
                 else //Other SQLite functions
                 {
                    if (prepareStatement(queryString)== 0)
                        return;
                    statement.step();
                 }
                 statement.finalize();
                 time = Platform.getTime() - start;

                //select the whole table to display in our grid
                if (prepareStatement("SELECT * FROM EXAMPLE_TABLE", false) == 0)
                    return;
                displayData(); 
            }
            else
            {
                start = Platform.getTime();
                if (prepareStatement(queryString)== 0)
                    return;
                for (var j = 0; j < runCount; j++) 
                {
                    if (statement.step() != ResultCode.SQLITE_ROW)
                    {
                        statement.reset();
                    }
                };
                time = Platform.getTime() - start;
                displayData(); 
            }

            timeLabel.text = "Query duration: " +  time + "ms";
            loadingOverlay.alpha = 0; 

        }

        //Create connection
        private function openConnection()
        {
            connection = Connection.open("MyTestDB.db", Connection.FLAG_CREATE | Connection.FLAG_READWRITE );
        }

        //Prepare the statement, handle necessary errors and output results
        private function prepareStatement(sqlString:String, display:Boolean=true):int
        {
            statement = connection.prepare(sqlString);

            var sqlType:String = "PREPARE";

            if (sqlString.indexOf("SELECT") > -1)
            {
                sqlType = "SELECT";
                tableNameLabel.text = "Table Name: " + getTableName(sqlString);
            }
            else  if (sqlString.indexOf("INSERT") > -1)
            {
                sqlType = "INSERT";
            }
            else  if (sqlString.indexOf("DROP") > -1)
            {
                sqlType = "TABLE DROP";
            }   
            else  if (sqlString.indexOf("CREATE") > -1)
            {
                sqlType = "TABLE CREATE";
            }


            if(connection.errorCode != ResultCode.SQLITE_OK)
            {
                if (display)
                    outputLabel.text = sqlType + " ERROR: " + connection.errorMessage;
                loadingOverlay.alpha = 0;
                clearGrid();
                return 0;
            }
            else
            {
                if (display)
                {
                    outputLabel.text = sqlType + " SUCCESS";
                }
                return 1;
            }
        }

        //Get table name from SQL string
        private function getTableName(sqlString:String):String
        {
            var index = sqlString.indexOf("FROM") + 5;
            return sqlString.substr(index, sqlString.length - index);
        }

        //step through the results, display output
        private function displayData()
        {
            clearGrid();
            getColumnNames();
            statement.reset();
            var rowCount = 1;
            while (statement.step() == ResultCode.SQLITE_ROW && rowCount < numRows)
            {
                for (var i = 0; i < numColumns; i++) 
                {
                    var currentColType = statement.columnType(i);

                    switch (currentColType)
                    {
                        case DataType.SQLITE_INTEGER    : grid[rowCount][i].label = statement.columnInt(i).toString();
                            break;
                        case DataType.SQLITE_FLOAT      : grid[rowCount][i].label = statement.columnDouble(i).toString();
                            break;
                        case DataType.SQLITE_TEXT       : grid[rowCount][i].label = statement.columnString(i);
                            break;
                        case DataType.SQLITE_BLOB       : grid[rowCount][i].label = "BLOB";
                            break;
                        case DataType.SQLITE_NULL       : grid[rowCount][i].label = "";
                            break;
                    }
                };  
                rowCount++;
            }
            statement.finalize(); 
        }

        //Get column names, display in grid
        private function getColumnNames()
        {
            for (var i = 0; i < numColumns; i++) 
            {
                grid[0][i].label = statement.columnName(i) ;
            };
        }

        //Clear output grid
        private function clearGrid()
        {
            for (var i = 0; i < numRows; i++) 
            {
                for (var j = 0; j < numColumns; j++) 
                {
                    grid[i][j].label = "";
                };
            };
        }

        //Initialize outputgrid
        private function initOutputGrid()
        {
            for (var j = 0; j < numRows; j++) 
            {
                var row:Vector.<Button> = [];
                for (var i = 0; i < numColumns; i++) 
                {
                    var button = newButton(117, 30, 117 * i + 10, 305 + (30 * j));
                    button.isEnabled = false;
                    row.push(button);       
                }
                grid.push(row);
            }
        }
    }
}

: