Skip to content

Instantly share code, notes, and snippets.

@lf-araujo
Last active March 31, 2019 10:38
Show Gist options
  • Save lf-araujo/02bbe61dd1d3d122aa5c1f30b4e7bda8 to your computer and use it in GitHub Desktop.
Save lf-araujo/02bbe61dd1d3d122aa5c1f30b4e7bda8 to your computer and use it in GitHub Desktop.
A Cookbook Program to Interact with the SQL Database

This is part of a series of posts about the Genie programming language. I am updating my progress in learning the language from scratch in the hopes it will be useful for anyone also trying to get to programming in the linux/Gtk world. This exercise was taken from a similar one that was posted at Full Circle Magazine course of basic python. I tried to reproduce the same code, now in Genie.

Here is a simple example of how to create small interface that interacts with the cookbook.db3 created in last post.

[indent=4]
uses
    Sqlite
    Gee

def PrintOut(db: Database, which:string)
    var fi = FileStream.open("recipeprint.html", "w+")
    stmt:Statement = null
    db.prepare_v2( "SELECT * FROM Recipes WHERE pkID =" + which, -1, out stmt)
    cols:int = stmt.column_count ()
    var row = new dict of string, string
    item:int = 1
    while stmt.step() == ROW
        for i:int = 0 to (cols - 1)
            row[ stmt.column_name( i ) ] = stmt.column_text( i )
        var lineentry = "<H1>" + row["name"] +"</H1> \n"
        print lineentry
        fi.puts( lineentry )
        lineentry = "<H2>Source: " +row[ "source" ]+ "</H2> \n"
        print lineentry
        fi.puts( lineentry )
        lineentry = "<H2>Servings: "+row[ "servings" ]+"</H2> \n"
        print lineentry
        fi.puts( lineentry )
        fi.puts( "<H3>Ingredient List: </H3> \n" )
        item++

    db.prepare_v2( "SELECT * FROM Ingredients WHERE RecipeID =" + which, -1, out stmt)
    cols = stmt.column_count ()
    item = 1
    while stmt.step() == ROW
        for i:int = 0 to (cols - 1)
            row[ stmt.column_name( i ) ] = stmt.column_text( i )
        var lineentry = "<li>"+row[ "ingredients" ]+"</li> \n"
        print lineentry
        fi.puts( lineentry )
        item++
    fi.puts("<H3>Instructions:</H3> \n")

    db.prepare_v2( "SELECT * FROM Instructions WHERE RecipeID =" + which, -1, out stmt)
    cols = stmt.column_count ()
    item = 1
    while stmt.step() == ROW
        for i:int = 0 to (cols - 1)
            row[ stmt.column_name( i ) ] = stmt.column_text( i )
        var lineentry = "<li>"+row[ "instructions" ]+"</li> \n"
        fi.puts(lineentry)
        item++

    Process.spawn_command_line_sync ("midori recipeprint.html")
    print "Done"

def DeleteRecipe(db:Database, which:string)
    var resp = UserInterface.raw_input("Are You SURE you want to Delete this record? (Y/n) -> ")
    if resp.up() == "Y"
        //statement:Statement
        del_recipe:string="DELETE FROM Recipes WHERE pkID = " + which
        del_instructions:string="DELETE FROM Instructions WHERE recipeID = " + which
        del_ingredients:string="DELETE FROM Ingredients WHERE recipeID = " + which
        PreparedStatements.checked_exec(db, del_recipe)
        PreparedStatements.checked_exec(db, del_instructions)
        PreparedStatements.checked_exec(db, del_ingredients)
        print "Recipe information DELETED"
        UserInterface.raw_input("Press A Key -> ")
    else
        print "Delete Aborted - Returning to menu"

def EnterNew(db:Database)
    var ings = new list of string
    var
        recipename = "" recipesource = "" recipeserves = "" instructions = ""
    var resp = UserInterface.raw_input("Enter Recipe Title (Blank line to exit) -> ")
    if resp != ""  /* continue */
        if resp.contains("'")
            recipename = resp.replace("'","\'")
        else
            recipename = resp
            print "RecipeName will be %s", recipename
        resp = UserInterface.raw_input("Enter Recipe Source -> ")
        if resp.contains("'")
            recipesource = resp.replace("'","\'")
        else
            recipesource = resp
        resp = UserInterface.raw_input("Enter number of servings -> ")
        if resp.contains("'")
            recipeserves = resp.replace("'","\'")
        else
            recipeserves = resp
        print "Now we will enter the ingredient list."
        var cont = true
        while cont == true
            var ing = UserInterface.raw_input("Enter Ingredient ('0' to exit) -> ")
            if ing != "0"
                ings.add(ing)
            else
                cont = false
        resp = UserInterface.raw_input("Enter Instructions -> ")
        instructions = resp
        print "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
        print "Here's what we have so far"
        print "Title: %s", recipename
        print "Source: %s" , recipesource
        print "Serves: %s" , recipeserves
        print "Ingredients:"
        for x in ings
            print x
        print "Instructions: %s" , instructions
        print "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
        resp = UserInterface.raw_input("OK to save? (Y/n) ")
        if resp.up() != "N"
            /* Write the Recipe Record */
            PreparedStatements.insert_nameservingssources(db, recipename, recipeserves, recipesource )
        /* Write the Instruction Record */
        lastid : int64 = db.last_insert_rowid ()
        for x in ings
            PreparedStatements.insert_ingredients(db, x, lastid)
        /* Write the Ingredients records */
        PreparedStatements.insert_instructions(db,instructions , lastid)
        /* Prompt the user that we are done */
        print "Done"
    else
        print "Save aborted"

def SearchForRecipe (db:Database)
    print "-------------------------------"
    print " Search in"
    print "-------------------------------"
    print " 1 - Recipe Name"
    print " 2 - Recipe Source"
    print " 3 - Ingredients"
    print " 4 - Exit"
    searchin:string = UserInterface.raw_input("Enter Search Type -> ")
    search:string = " "
    response:string=" "
    if searchin != "4"
        if searchin == "1"
            search = "Recipe Name"
        else if searchin is "2"
            search = "Recipe Source"
        else if searchin is "3"
            search = "Ingredients"
        else
            print "An Error Occured"
            print "--------------------------------------------------------------------------------------"
            Process.exit (-1)
        parm:string = searchin
        response = UserInterface.raw_input ("Search for what in "+ search +" (blank to exit) -> ")
        if parm == "1" // Recipe Name
            stmt:Statement = PreparedStatements.select_recipe(db, response)
            var row = new dict of string, string
            cols:int = stmt.column_count ()
            item:int = 1
            while stmt.step() == ROW
                for i:int = 0 to (cols - 1)
                    row[ stmt.column_name( i ) ] = stmt.column_text( i )
                stdout.printf( "%-5s", item.to_string( "%03i" ))
                stdout.printf( "%-30s", row[ "name" ])
                stdout.printf( "%-20s", row[ "servings" ])
                stdout.printf( "%-30s\n", row[ "source" ])
                item++
        else if parm is "2" // Recipe Source
            stmt:Statement = PreparedStatements.select_source(db, response)
            var row = new dict of string, string
            cols:int = stmt.column_count ()
            item:int = 1
            while stmt.step() == ROW
                for i:int = 0 to (cols - 1)
                    row[ stmt.column_name( i ) ] = stmt.column_text( i )
                stdout.printf( "%-5s", item.to_string( "%03i" ))
                stdout.printf( "%-30s", row[ "name" ])
                stdout.printf( "%-20s", row[ "servings" ])
                stdout.printf( "%-30s\n", row[ "source" ])
                item++
        else if parm is "3" // Ingredients
            print "%-5s%-30s%-20s%-30s%-30s", "Item", "Name", "Serves", "Source", "Ingredient"
            print "----------------------------------------------------------------------------------------------------------------------------"
            stmt:Statement = PreparedStatements.select_ingredients( db, response)
            cols:int = stmt.column_count ()
            var row = new dict of string, string
            item:int = 1
            while stmt.step() == ROW
                for i:int = 0 to (cols - 1)
                    row[ stmt.column_name( i ) ] = stmt.column_text( i )
                stdout.printf( "%-5s", item.to_string( "%03i" ))
                stdout.printf( "%-30s", row[ "name" ])
                stdout.printf( "%-20s", row[ "servings" ])
                stdout.printf( "%-30s\n", row[ "source" ])
                stdout.printf( "%-30s\n", row["ingredients"])
                item++
            print "Total recipes %s", (item -1).to_string()
            print "--------------------------------------------------------------------------------------"
            UserInterface.raw_input("Press ENTER to leave")

def PrintAllRecipes ( db:Database )
    print "%-5s%-30s%-20s%-30s", "Item", "Name", "Serves", "Source"
    print "--------------------------------------------------------------------------------------"
    stmt:Statement = PreparedStatements.select_all( db )
    cols:int = stmt.column_count ()
    var row = new dict of string, string
    item:int = 1
    while stmt.step() == ROW
        for i:int = 0 to (cols - 1)
            row[ stmt.column_name( i ) ] = stmt.column_text( i )
        stdout.printf( "%-5s", item.to_string( "%03i" ))
        stdout.printf( "%-30s", row[ "name" ])
        stdout.printf( "%-20s", row[ "serves" ])
        stdout.printf( "%-30s\n", row[ "source" ])
        item++
    print "Total recipes %s", (item -1).to_string()
    print "--------------------------------------------------------------------------------------"
    UserInterface.raw_input("Press ENTER to leave")

def PrintSingleRecipe(n_columns:int, values:array of string, column_names:array of string):int
    print "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
    for i:int = 1 to n_columns
        stdout.printf ("%s = %s\n", column_names[i], values[i])
    print "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
    return 0


namespace UserInterface
    def get_input_from_menu():string
        show_menu()
        return raw_input("Enter a selection -> ")

    /*
     *
     * name: raw_input())
     * @string with question
     * @string with answer
     *
     * It is a Genie version of the raw_input function in python.
     *
     */
    def raw_input (query:string = ""):string
        stdout.printf ("%s", query)
        return stdin.read_line ()

    def show_menu()
        print "==================================================="
        print "        RECIPE DATABASE"
        print " 1 - Show All Recipes"
        print " 2 - Search for a recipe"
        print " 3 - Show a Recipe"
        print " 4 - Delete a recipe"
        print " 5 - Add a recipe"
        print " 6 - Print a recipe"
        print " 0 - Exit"
        print "==================================================="


namespace PreparedStatements
    def select_all( db:Database ):Statement
        statement:Statement
        db.prepare_v2( " select name, servings as serves, source from Recipes ", -1, out statement )
        return statement

    def select_recipe (db:Database, res:string) : Statement
        statement:Statement
        db.prepare_v2( "SELECT pkid,name,source,servings FROM Recipes WHERE name like \"%" + res + "%\"", -1, out statement)
        return statement

    def select_source (db:Database, res:string) : Statement
        statement:Statement
        db.prepare_v2( "SELECT pkid,name,source,servings FROM Recipes WHERE source like  \"%" + res + "%\"", -1, out statement)
        return statement

    def select_ingredients (db:Database, response:string):Statement
        statement:Statement
        db.prepare_v2(" SELECT r.pkid,r.name,r.servings,r.source,i.ingredients FROM Recipes r Left Join ingredients i on (r.pkid = i.recipeid) WHERE i.ingredients like \"%" + response + "%\" GROUP BY r.pkid", -1, out statement )
        return statement

    def select_instructions (db:Database):Statement
        statement:Statement
        db.prepare_v2("select name, servings as serves, source from Instructions", -1, out statement)
        return statement

    def insert_nameservingssources( db:Database, name:string, servings:string, sources:string) : Statement
        statement:Statement = null
        sql:string="INSERT INTO Recipes (name,servings,source) VALUES (\"" + name + "\",\"" + servings + "\",\"" + sources +"\")"
        checked_exec(db ,sql)
        return statement

    def insert_ingredients ( db: Database, ingredients: string, lastid:int64):Statement
        statement:Statement =null
        print lastid.to_string()
        sql:string = "INSERT INTO Ingredients (recipeID,ingredients) VALUES ( \"" + lastid.to_string() + "\", \"" + ingredients + "\")"
        print sql
        checked_exec(db,sql)
        param_position : int = statement.bind_parameter_index ("$recipeID")
        statement.bind_int64(param_position,lastid)
        return statement

    def insert_instructions( db: Database, instructions:string, lastid:int64 ):Statement
        statement:Statement = null
        statement.bind_parameter_index ("$recipeID")
        checked_exec(db,"INSERT INTO Instructions (recipeID,instructions) VALUES (\"" + lastid.to_string() + "\", \"" + instructions + "\")")
        return statement

    def check_ok (db : Sqlite.Database, ec : int)
        if (ec != Sqlite.OK)
            stderr.printf ("Error: %d: %s\n", db.errcode (), db.errmsg ())
            Process.exit (-1)
    def checked_exec (db : Sqlite.Database, sql : string)
        check_ok (db, db.exec (sql))

init
    db:Database
    if (Sqlite.Database.open ("cookbook.db3", out db) != Sqlite.OK)
        stderr.printf ("Error: %d: %s \n", db.errcode (), db.errmsg ())
        Process.exit (-1)

    while true
        response:string = UserInterface.get_input_from_menu()
        if response == "1" // Show All Recipes
            PrintAllRecipes(db)
        else if response is "2" // Search for a recipe
            SearchForRecipe(db)
        else if response is "3" //Show a Recipe
            res:string = UserInterface.raw_input("Select a recipe -> ")
            sql:string = "SELECT * FROM Recipes WHERE pkID = " + res
            db.exec(sql, PrintSingleRecipe, null)
            print "Ingredient list"
            sqldois:string = "SELECT * FROM Ingredients WHERE recipeID = " + res
            db.exec(sqldois, PrintSingleRecipe, null)
            print "Instructions"
            sqltres:string = "SELECT * FROM Instructions WHERE recipeID = " + res
            db.exec(sqltres, PrintSingleRecipe, null)
        else if response is "4"//Delete a recipe
            PrintAllRecipes(db)
            print "0 - Return To Menu"
            var res = int.parse(UserInterface.raw_input("Select a Recipe to DELETE or 0 to exit -> "))
            res_string:string= res.to_string()
            if res != 0
                DeleteRecipe(db, res_string)
            else if res == 0
                print "Back To Menu..."
            else
                print "Unrecognized command.  Returning to menu."
        else if response is "5" //Add a recipe
            EnterNew(db)
        else if response is "6" //Print a recipe
            PrintAllRecipes(db)
            print "0 - Return To Menu"
            var res = int.parse(UserInterface.raw_input("Select a Recipe to DELETE or 0 to exit -> "))
            if res != 0
                PrintOut(db, res.to_string())
            else if res == 0
                print "Back To Menu..."
            else
                print "Unrecognized command. Returning to menu."
        else if response is "0" //Exit
            print "Goodbye"
            break
        else
            print "Unrecognized command. Try again."
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment