CMCc Some code to map metakit views to arrays of dictionaries
namespace eval dattach { variable debug 0 proc Write {view selector array var el op} { upvar $var val variable debug if {$debug} { puts stderr "Write: '$view' '$selector' '$array' '$var' '$el' '$op'" puts stderr "V: $val($el)" catch {[dict get $val($el)]} err puts stderr "Err: $err" } set row [::mk::select $view $selector $el] if {[llength $row]} { eval ::mk::set ${view}.$row [dict get $val($el)] $selector $el } else { eval ::mk::row append $view [dict get $val($el)] $selector $el } } proc Read {view selector array var el op} { upvar $var val variable debug if {$debug} { puts stderr "Read: '$view' '$selector' '$array' '$var' '$el' '$op'" } set row [::mk::select $view $selector $el] if {[llength $row]} { set val($el) [eval dict create [::mk::get ${view}.$row]] } else { error "dattach can't read \"${array}\(${el}\): no such element in array" } } proc Unset {view selector array var el op} { upvar $var val variable debug if {$debug} { puts stderr "Unset: '$view' '$selector' '$array' '$var' '$el' '$op'" } if {$el == ""} { puts stderr "Trace: unset1 $view" ::mk::loop el1 ${view} { #catch {puts stderr "Trace: unset2 $el1 [::mk::get $el1]"} catch {::mk::row delete $el1} } puts stderr "Trace: unset done" } else { set row [::mk::select $view $selector $el] ::mk::row delete ${view}.$row } } proc attach {view array {selector ""}} { if {$selector == ""} { set selector [lindex [::mk::view layout $view] 0] } variable debug if {$debug} { puts stderr "dattach: $array to $view $selector" } upvar $array a set a() "" unset a() trace add variable a unset [list ::dattach::Unset $view $selector $array ] trace add variable a read [list ::dattach::Read $view $selector $array ] trace add variable a write [list ::dattach::Write $view $selector $array ] } proc snort {view array {selector ""}} { uplevel ::dattach::attach $view $array $selector upvar $array a ::mk::loop el1 ${view} { set sel [eval dict create [::mk::get $el1]] set a([dict get $sel $selector]) $sel } } namespace export attach snort }
and here are a few tests:
if {$argv0 == [info script]} { package require Mk4tcl #set ::dattach::debug 1 proc dumpit {heading {var shoesize}} { puts "*** $heading" upvar $var array foreach last [array names array] { if {[catch {puts "$last: $array($last)"} error]} { puts "error on $var element $last: $error" } } puts "---" } set db [mk::file open db /tmp/datafile.mk] set vw [mk::view layout db.people {last first shoesize:I}] # fill in some db rows mk::row append $vw last "Lennon" first "John" shoesize 44 mk::row append $vw last "Gordon" first "Flash" shoesize 42 mk::row append $vw last "Hendrix" first "Jimi" shoesize 49 mk::file commit db ::dattach::attach $vw shoesize last dumpit "attach gets rows lazily - so this will be empty" set x $shoesize(Lennon) set x $shoesize(Gordon) dumpit "Fetch some attached values" set shoesize(Cass) [dict create first Mama shoesize 40 alive n] dumpit "Create a new Row" shoesize dict set shoesize(Cass) last Lennon ;# note, this will have no effect dumpit "changing the key field has no effect" ::dattach::snort $vw shoes last dumpit "snort gets all rows in existence at creation time" shoes dict set shoes(Lennon) shoesize -1 dumpit "changing a different attached variable has an effect on all" shoes # note - we take the first match on key ::dattach::snort $vw size shoesize dumpit "By Shoesize" size dict set shoesize(Cass) shoesize 44 dumpit "array names can get out of sync on snorted arrays\n*** Note: this could be fixed, if trace array was." size }