rivet/packages/simpledb/simpledb.tcl (289 lines of code) (raw):

# simpledb.tcl -- provides a simple tcl database. # Copyright 2003-2004 The Apache Software Foundation # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # $Id$ package provide simpledb 0.1 namespace eval ::simpledb { set oid 0 } # simpledb::createtable -- # # Creates a table and its associated columns. # # Arguments: # table - name of the table. # args - column names. # # Side Effects: # Creates internal namespace and arrays. # # Results: # None. proc simpledb::createtable { table args } { namespace eval $table {} array set ${table}::cols {} # Currently active oids. array set ${table}::goodoids {} foreach col $args { # Each key gets its own namespace. namespace eval ${table}::${col} {} # In that namespace we have an array that maps oids->data. array set ${table}::${col}::data {} # And an array that maps data->oids. array set ${table}::${col}::values {} set ${table}::cols($col) 1 } } # simpledb::deltable -- # # Delete table. # # Arguments: # table - table to delete. # # Side Effects: # Deletes table namespace. # # Results: # None. proc simpledb::deltable { table } { namespace delete $table } # simpledb::tables -- # # Return a list of all tables. # # Arguments: # None. # # Side Effects: # None. # # Results: # A list of all tables that exist in the database. proc simpledb::tables {} { set res {} foreach ns [namespace children [namespace current]] { lappend res [namespace tail $ns] } return $res } # simpledb::createitem -- # # Create an item in the table. # # Arguments: # table - table name. # properties - a list of keys and their corresponding values. # Keys must correspond to those listed in 'createtable'. # # Side Effects: # Creates a new table item. # # Results: # None. proc simpledb::createitem { table properties } { variable oid incr oid set ${table}::goodoids($oid) 1 foreach {col data} $properties { set ${table}::${col}::data($oid) $data lappend ${table}::${col}::values($data) $oid } return $oid } # simpledb::getitem -- # # Fetches an item from the database based on its oid. # # Arguments: # table - table name. # oid - identity of the item to fetch. # # Side Effects: # None. # # Results: # Returns information as a list suitable to pass to 'array set'. proc simpledb::getitem { table oid } { foreach col [array names ${table}::cols] { lappend res $col [set ${table}::${col}::data($oid)] } return $res } # simpledb::setitem -- # # Set the values of given keys. # # Arguments: # table - table name. # oid - item's unique id. # properties - list of keys and values. # # Side Effects: # The old value of the item is lost. # # Results: # None. proc simpledb::setitem { table oid properties } { upvar $properties props foreach {col data} $properties { if { [info exists ${table}::${col}::data($oid)] } { set oldval [set ${table}::${col}::data($oid)] set item [lsearch [set ${table}::${col}::values($oldval)] $oid] if { $item >= 0 } { set ${table}::${col}::values($oldval) \ [lreplace ${table}::${col}::values($oldval) $item $item] } if { [llength [set ${table}::${col}::values($oldval)]] == 0 } { unset ${table}::${col}::values($oldval) } } set ${table}::${col}::data($oid) $data lappend ${table}::${col}::values($data) $oid } return $oid } # simpledb::delitem -- # # Delete an item from the database. This is slow because of the # lsearch. # # Arguments: # table - table name. # oid - object's unique id. # # Side Effects: # Deletes item from the database. # # Results: # None. proc simpledb::delitem { table oid properties } { upvar $properties props foreach col [array names ${table}::cols] { unset ${table}::${col}::data($oid) set item [lsearch ${table}::${col}::values($props($col)) $oid] set ${table}::${col}::values($props($col)) \ [lreplace ${table}::${col}::values($props($col)) $item $item] } unset ${table}::goodoids($oid) return $oid } # simpledb::finditems -- # # Find items that match the given "properties" - a list of keys # and the sought values. Glob patterns are accepted as # 'values'. # # Arguments: # table - table name. # propertymatch - list of keys and values to search on. # # Side Effects: # None. # # Results: # A list of the id's of matching item. proc simpledb::finditems { table propertymatch } { array set res {} foreach {col value} $propertymatch { foreach {value oids} [array get ${table}::${col}::values $value] { foreach oid $oids { if { [info exists res($oid)] } { incr res($oid) } else { set res($oid) 1 } } } } set retlist {} foreach {oid num} [array get res] { if { $res($oid) == [llength $propertymatch] / 2 } { lappend retlist $oid } } return $retlist } # simpledb::items -- # # Fetch all the items from a particular table. # # Arguments: # table. # # Side Effects: # None. # # Results: # A list of lists, with the sublists being key/value lists of # column names and their value for the oid in question. proc simpledb::items {table} { set reslist {} set collist [array names ${table}::cols] foreach oid [array names ${table}::goodoids] { set oidlist {} foreach col $collist { if { [info exists ${table}::${col}::data($oid)] } { lappend oidlist $col [set ${table}::${col}::data($oid)] } } lappend reslist $oidlist } return $reslist } # simpledb::synctostorage -- # # Writes the database to a file. The storage format, for the # moment is Tcl code, which isn't space efficient, but is easy # to reload. # # Arguments: # savefile - file to save database in. # # Side Effects: # None. # # Results: # None. proc simpledb::synctostorage {savefile} { set fl [open $savefile w] foreach ns [namespace children] { # Let's store the goodoids array. set collist [array names ${ns}::cols] puts $fl "namespace eval $ns \{" puts $fl " array set cols \{ [array get ${ns}::cols] \}" puts $fl " array set goodoids \{ [array get ${ns}::goodoids] \}" foreach col $collist { puts $fl " namespace eval ${col} \{" puts $fl " array set data [list [array get ${ns}::${col}::data]]" puts $fl " array set values [list [array get ${ns}::${col}::values]]" puts $fl " \}" } puts $fl "\}" } close $fl } # simpledb::syncfromstorage -- # # Reloads database from file. # # Arguments: # savefile - file to read. # # Side Effects: # Creates database. # # Results: # None. proc simpledb::syncfromstorage {savefile} { source $savefile }