Blogs Jelle's blog
(0 votes)

I never liked writing SQL INSERT and UPDATE statements. Not that it's hard, but it's time consuming and I don't like how it clutters my code.
In PHP I had a nice wrapper for that made by ricocheting.

So I decided to create one just like it for SQLite in Python. I haven't been using Python for long, and I wrote this in a few hours, so it's possible a bit too rough for your use, but still...

How can you use it?

# Import and create an object like this
import litepiesql
db = litepiesql.Database('filename.db')

# This will produce a list with a dictionary for every row, containing the column names
result = db.query('SELECT * FROM stocks')
print result

"""
Will result in something like this:
[{'date': u'2006-01-05', 'symbol': u'RHAT', 'trans': u'BUY', 'price': 35.140000000000001, 'qty': 103.0},
{'date': u'2011-04-18', 'symbol': None, 'trans': u'SELL', 'price': None, 'qty': None}]
"""

How can you insert data in a table?

# You can use the insert function.
# Its parameters are the tablename and the dictionary with unescaped data
# It will return the ID of the inserted row.

# For example: Create a new dictionary
data = {}
data['date'] = '2011-04-19'
data['symbol'] = 'TEST'
rowid = db.insert('tablename', data)

# You can also use special values, like:
new = {}
new['date'] = 'now()'
new['symbol'] = 'null'
newrowid = db.insert('tablename', new)

#Do note, now() will insert the UNIX timestamp, not a date.

How can you update something?

# You can use the update function.
# Its parameters are the tablename, the dictionary with unescaped data and the ESCAPED WHERE parameter (without the actual WHERE)

# For example: Create a new dictionary
change = {}
change['date'] = '2011-04-19'
change['symbol'] = 'UPDATED'
db.update('tablename', change, 'symbol = "TEST"')

# You can use the same special values here, but there's an extra one:
newchange = {}
newchange['qty'] = 'increment(1)'
db.update('tablename', newchange, 'qty > 0')

# This will increment the qty field with 1. You can also use negative numbers, of course.

How can you empty a table?

# You can use the truncate() function to empty a table and reset the autoincrement counter.
db.truncate('tablename')

Why LitePieSQL?

Because I love pies. And cakes are nothing but lies, so there you have it.

The code:

#!/usr/bin/env python
"""
Name: Database.singleton.php
File Description: SQLite Wrapper for Python providing easy access to basic functions.
Author: Jelle De Loecker (skerit)
Inspired by: ricocheting's MySQL Wrapper for PHP
Web: http://www.kipdola.com/
Update: 2011-04-19
Version: 0.1
Copyright 2011 kipdola.com

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see .
"""

import sqlite3
import itertools
import re
import time

class Database:

    def __init__(self, dbfile):
        self.conn = sqlite3.connect(dbfile)
        self.conn.row_factory = sqlite3.Row
        
    def insert(self, tablename, data):
        """
        Insert data into a table.
        The data does not have to be escaped.
        """
        
        # Create a new cursor
        tc = self.conn.cursor()
        
        tablelist = ""
        valueholder = ""
        valuelist = []
        
        for key, value in data.items():
            if len(tablelist) > 0:
                tablelist += ', '
                valueholder += ', '
                
            # Add to table list
            tablelist += key
            
            # Add a holder
            valueholder += '?'
            
            # Look for the increment() function
            increment = re.match("^increment\((\-?\d+)\)$",str(value))

            if(str(value).lower() == 'null'):
                valuelist.append(None)
            elif(str(value).lower() == 'now()'):
                valuelist.append(str(int(time.time())))
            else:
                valuelist.append(value)
                
        
        # Perform and commit the insert
        self.query("INSERT INTO " + tablename + " (" + tablelist + ") VALUES (" + valueholder + ");", valuelist)
        
        # Get the last inserted id
        id = self.query('SELECT last_insert_rowid();')[0]['last_insert_rowid()']
        
        # Close this connection
        tc.close()
        
        # Return the id
        return id
    
    def query(self, query, escapeList=None):
        """
        Perform a query. When an escapeList is provided it'll be used for
        variable substitution.
        
        Returns a list with dictionaries containing the result of your SELECT,
        or an empty list after an INSERT or UPDATE.
        """
        
        # Create a new cursor
        tc = self.conn.cursor()
        
        # Execute our query with or without values to escape
        if(escapeList):
            tc.execute(query, tuple(escapeList))
        else:
            tc.execute(query)
        
        # Make an empty result list
        result = []
    
        # A description is only set after a SELECT statement
        # Even when there are no results.
        if(tc.description):
            # Fetch the field names out of our cursor
            field_names = [d[0].lower() for d in tc.description]
            
            # Generate a dictionary
            while True:
                rows = tc.fetchmany()
                if not rows: break
                for row in rows:
                    result.append(dict(itertools.izip(field_names, row)))
        else:
            # If there is no description this must mean we're doing an insert
            # or update. Anything that needs a commit.
            self.conn.commit()
        
        # Close the cursor        
        tc.close()

        # Return the list with the dictionaries
        return result
    
    def update(self, tablename, data, where):
        """
        Update a table.
        The WHERE variable you give has to be escaped
        """
        
        # Create a new cursor
        tc = self.conn.cursor()
        
        # Store all the field names we'll be updating in order
        updatelist = ""
        
        # Add all the updates values to a list in order,
        # which we'll convert to a tuple when needed.
        valuelist = []
        
        for key, value in data.items():
            if len(updatelist) > 0:
                updatelist += ', '
            
            # Look for the increment() function
            increment = re.match("^increment\((\-?\d+)\)$",str(value))
            
            if(str(value).lower() == 'null'):
                updatelist += key + "=?"
                valuelist.append(None)
            elif(increment):
                updatelist += key + "=" + key + '+' + list(increment.groups(0))[0]
            elif(str(value).lower() == 'now()'):
                updatelist += key + "=?"
                valuelist.append(str(int(time.time())))
            else:
                updatelist += key + "=?"
                valuelist.append(value)
        
        self.query("UPDATE " + tablename + " SET " + updatelist + " WHERE " + where + ";", valuelist)
        
        tc.close()
    
    def truncate(self, tablename):
        """
        Delete all rows from a table and reset the autoincrement
        """
        
        # Create a new cursor
        tc = self.conn.cursor()
        
        # Clear the table
        tc.execute("delete from "+ tablename + ";")
        
        # Reset the autoincrement
        tc.execute("delete from sqlite_sequence where name='"+ tablename + "';")
        
        tc.close()

Add a comment
(0 votes)
The feedback button in Firefox 4.0 beta

Firefox 4 lets you report when something makes you happy or sad. It's a very cute idea (although looking at the actual submissions can also make you quite sad). I wondered how long it would take until I had to use it, but here it is:

My bookmarks toolbar in Firefox 4.0 beta

You couldn't store a bookmark without a name in previous Firefox versions, but you could delete it afterwards. After that you would only see the favicon of the bookmark on your toolbar, which saves LOTS of space.
However, someone must have thought that this was unwanted behaviour and decided to display the URL if there is no name. Messing up my toolbar

Yes, you can still use a simple space in the name field, but that still makes your icon 50% longer than it should be.

Buttons with a space as a name
Add a comment
(1 vote)

For an entire week I've been working on a canvas/html5 project of mine: the Kiflea Engine.

"What's that?", you ask?

It stands for "Kipdola's Flat Earth" Engine. It's a tiled based engine on which you can build a game. Or at least: that's the goal of the project. I'm not there yet, even though I feel like I've already made huge advancements.

The maps are built using Tiled. Any tileset you load in there will load in the engine. The HUD is built using a simple JSON file, ... As you can see in the image above, I've just finished my pathfinding algorithm.

The Kiflea engine showing a pathfinding example

If you want to try the engine in its current state out, you can do so here.

If you would like to download the source, I've set up an SVN repository over here:
http://kipdola.be/trac/repos/
You can download the code by executing this SVN command:
svn co http://kipdola.be/svn/kiflea/

I would really apreciate any feedback, ideas, code optimization (did I tell you this is my first ever JavaScript program?), patches, ... Don't ask my why you can't kill anything, though. It's an engine, not a game (yet).

Add a comment
(1 vote)

On the main page ofour Kipdola site is a flash video just under the menu.
When a menu expands, it unfortunately hides behind the flash file. That's incredibly annoying.

I searched for a few fixes. Some suggested to adjust the z-index of the menu, but that still did not work. At least not in Firefox.
And then I found out you actually have to add a few parameters to the object itself.
These, to be precise:

    <param name="wmode" value="transparent" />

This goes in the <object> element. For it to work on both Firefox and IE you have to add another one to the <embed> element. Like this:

<embed src="http://some.url/flash.swf" wmode="transparent">

So the video in the showcase section on our frontpage has this code:

<object width="400" height="225">
    <param name="wmode" value="transparent" />
    <param name="allowfullscreen" value="true" />
    <param name="allowscriptaccess" value="always" />
    <param name="movie" value="http://vimeo.com/moogaloop.swf?clip_id=11104140&server=vimeo.com&show_title=1&show_byline=1&show_portrait=0&color=00ADEF&fullscreen=1"  />
    <embed src="http://vimeo.com/moogaloop.swf?clip_id=11104140&server=vimeo.com&show_title=1&show_byline=1&show_portrait=0&color=00ADEF&fullscreen=1"
        type="application/x-shockwave-flash"
        allowfullscreen="true"
        allowscriptaccess="always"
        width="400"
        height="225"
        wmode="transparent">
    </embed>
</object>

It also does what it says: makes the flash object transparent. Vimeo, for example, shows a little animation while loading the video. With transparency turned on this isn't drawn on a black background, but directly on your page. Which is pretty

Add a comment
(1 vote)

Have you ever had a bunch of subdirectories each filled with only one zip file? Or have you ever had a task that needed to be done in the same way?
Well here's a handy little line of code that will help you on your way!

find -name '*.zip' | xargs -n1 echo unzip

This doesn't actually do anything yet, it searches for .zip files in every subdirectory relative to the one you're currently in and then echoes what it'll do to those files once you remove the `echo` command
So actually typing:

find -name '*.zip' | xargs -n1 unzip

Will perform the command. Another example, if you want to copy lots of files from the subdirectory of one map to another, you can do this:

find /home/user/map/ -name "*.txt" | xargs -i cp -v {} .

This will copy every .txt file under any directory, starting from /home/user/map/, to your current directory. (No matter where you are)

I love it, and it has saved me lots of time!

Add a comment
(1 vote)

Binny V A over at Bin-Blog has written something marvellous: a print_r function for Javascript.

What does it do? It takes an array (or hash or object) and prints out every key with its value. If it comes along another array, it does the same thing again. It's such a useful feature in PHP, it's a great debugger-friend.

There are a few code snippets out there that do the same job, but I thought this one was quite small and compact.
Don't forget to wrap it in a <pre> tag to get a nice layout.


/**
 * Function : dump()
 * Arguments: The data - array,hash(associative array),object
 *    The level - OPTIONAL
 * Returns  : The textual representation of the array.
 * This function was inspired by the print_r function of PHP.
 * This will accept some data as the argument and return a
 * text that will be a more readable version of the
 * array/hash/object that is given.
 * Docs: http://www.openjs.com/scripts/others/dump_function_php_print_r.php
 */
function dump(arr,level) {
  var dumped_text = "";
  if(!level) level = 0;
  
  //The padding given at the beginning of the line.
  var level_padding = "";
  for(var j=0;j \"" + value + "\"\n";
      }
    }
  } else { //Stings/Chars/Numbers etc.
    dumped_text = "===>"+arr+"<===("+typeof(arr)+")";
  }
  return dumped_text;
}
Add a comment
(1 vote)

I've only recently gotten into Javascript, thanks to the <canvas> element. I'm currently building a 2D tile-based render engine for a game. (What better way to learn something new than to build a game, right?)

Ofcourse, this game also has to respond to the keyboard. I got tired of looking up keycodes real quick and decided to just create an associative array out of them, for the hell of it. My IDE even autocompletes them. Here's the list:

// A var storing all useful keys for easy access
var key = {
    'Backspace': 8,
    'Tab': 9,
    'Enter': 13,
    'Shift': 16,
    'Ctrl': 17,
    'Alt': 18,
    'Pause': 19,
    'Capslock': 20,
    'Esc': 27,
    'Pageup': 33,
    'Pagedown': 34,
    'End': 35,
    'Home': 36,
    'Leftarrow': 37,
    'Uparrow': 38,
    'Rightarrow': 39,
    'Downarrow': 40,
    'Insert': 45,
    'Delete': 46,
    '0': 48,
    '1': 49,
    '2': 50,
    '3': 51,
    '4': 52,
    '5': 53,
    '6': 54,
    '7': 55,
    '8': 56,
    '9': 57,
    'a': 65,
    'b': 66,
    'c': 67,
    'd': 68,
    'e': 69,
    'f': 70,
    'g': 71,
    'h': 72,
    'i': 73,
    'j': 74,
    'k': 75,
    'l': 76,
    'm': 77,
    'n': 78,
    'o': 79,
    'p': 80,
    'q': 81,
    'r': 82,
    's': 83,
    't': 84,
    'u': 85,
    'v': 86,
    'w': 87,
    'x': 88,
    'y': 89,
    'z': 90,
    '0numpad': 96,
    '1numpad': 97,
    '2numpad': 98,
    '3numpad': 99,
    '4numpad': 100,
    '5numpad': 101,
    '6numpad': 102,
    '7numpad': 103,
    '8numpad': 104,
    '9numpad': 105,
    'Multiply': 106,
    'Plus': 107,
    'Minut': 109,
    'Dot': 110,
    'Slash1': 111,
    'F1': 112,
    'F2': 113,
    'F3': 114,
    'F4': 115,
    'F5': 116,
    'F6': 117,
    'F7': 118,
    'F8': 119,
    'F9': 120,
    'F10': 121,
    'F11': 122,
    'F12': 123,
    'equal': 187,
    'Coma': 188,
    'Slash': 191,
    'Backslash': 220
}

Now you can use things like "key.Uparrow" in your code in stead of it's corresponding number. For example:


// Bind the onKeyDown function to the onkeydown event.
window.onkeydown = onKeyDown;

/**
 *This function is called whenever a key is pressed on the keyboard
 *@param    key     {int}   The key
 */
function onKeyDown(keypress) {
    
    // Select the correct key and execute its functions
    switch (keypress.keyCode) {

        case key.Uparrow:
            // Do  something
            break;

        case key.Rightarrow:
            // Do  something
            break;

        case key.Downarrow:
            // Do  something
            break;
        
        case key.Leftarrow:
            // Do something
            break;
    }
}
Add a comment

Bekijk onze kortfilm "Zin"

Scroll To Top