Patch title: Release 85 bulk changes
Abstract:
File: /pliant/appli/database/prototype.pli
Key:
    Removed line
    Added line
abstract
  [Pliant database engine is based on an abstract interface (a set of generic methods) used to access real datas which type is not known by the application that access them. ] ; eol
  [This module defines the interface methods.]

# Copyright  Hubert Tonneau  hubert.tonneau@pliant.cx
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 2
# as published by the Free Software Foundation.
#
# 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
# version 2 along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

module "/pliant/language/compiler.pli"
module "/pliant/language/data/string_cast.pli"
module "/pliant/util/encoding/html.pli"

module "/pliant/language/compiler/type/inherit.pli"
module "/pliant/language/data/cache.pli"

constant autocreate false

public

(gvar TraceSlot database_trace) configure "database"

type DataInterface_
  void

flagset DatabaseFlags
  database_loading
  database_modified
  database_compressed
  database_autoclose

type Database_
  inherit CachePrototype
  field Pointer:Sem sem
  field Str path
  field DatabaseFlags flags

CachePrototype maybe Database_

type DataScanBuffer
  field Int int
  field Address adr
  field Arrow arrow


#--------------------------------------------------------------------------

doc
  fixed [Data_ ] ; [is pointer to a data in the database.] ; eol
  [It contains:]
  list
    item
      [The address of the true data (but the true data type is unknown). See] ; fixed [ DataInterface_ ] ; [below.]
    item [An arrow to the object that contains the data. This will prevent the data to be freed as long as we have a pointer to it.]
    item [The interface that is an object that contains the generic methods that will be used to access the data.]
    item [The base is the pointer to database the data belongs to.]
    item [The data path (a string like a file path that identify the object and can be used to get an access to it) is stored in two parts for speed reasons.]


type Data_
  field Address adr
  field Arrow object
  field Link:DataInterface_ interface
  field Link:Database_ base
  field Link:Str path1
  field Pointer:Str path2


gvar DataInterface_ empty_interface
gvar Database_ empty_database
gvar Sem empty_sem
empty_database sem :> empty_sem
gvar Str empty_string

function build d
  arg_w Data_ d
  d adr := null
  d interface :> empty_interface
  d base :> empty_database
  d path1 :> empty_string
  d path2 :> null map Str

gvar Data_ data_null

method d key -> k
  arg Data_ d ; arg Str k
  if (exists d:path2)
    k := html_decode (d:path2 1 d:path2:len)
  else
    var Int i := d:path1 search_last "/" -1
    k := html_decode (d:path1 i+1 d:path1:len)

method d dbpath -> p
  arg Data_ d ; arg Str p
  if (exists d:path2)
    p := d:path1+d:path2
  else
    p := d:path1

method d path -> p
  arg Data_ d ; arg Str p
  if (exists d:path2)
    p := d:base:path+d:path1+d:path2
  else
    p := d:base:path+d:path1


#--------------------------------------------------------------------------

doc
  [The data that pointed by] ; fixed [ Data_ ] ; [is of an unknown real type, so we must use generic methods to access it. ]
  [Also the data pointed is not always a true object (a field in a record is not, for memory compactness reasons), so instead od calling the generic method on the data directely, we use the link to the] ; fixed [ DataInterace_ ] ; [object which is stored in the] ; fixed [ Data_ ] ; [pointer, and call the generic method in this one.] ; eol
  [You could see the] ; fixed [ DataInterface_ ] ; [as a functions array.]


method di type d -> t
  oarg DataInterface_ di ; arg Data_ d ; arg_R Type t
  generic
  # get the physical type of the data associated with this node
  t :> Void

method di get d adr type -> status
  oarg DataInterface_ di ; arg Data_ d ; arg Address adr ; arg Type type ; arg Status status
  generic
  # try to read the data associated with this node, and cast it to the specify type
  status := failure
  #
  # the following seems to be both buggy (using 'object' instead of 'adr') and of no use,
  # I just comment it out since I can't remember why I wrote it, so it might be of some use anyway.
  # 
  # if d:object<>null
  #   if type=(entry_type d:object)
  #     type copy_instance d:object adr
  #   else
  #     var Str s := to_string d:object (entry_type d:object) "db"
  #     from_string adr type s "db"

method di set d adr type -> status
  oarg_rw DataInterface_ di ; arg_rw Data_ d ; arg Address adr ; arg Type type ; arg Status status
  generic
  # try to set the data associated with this node to the provided typed value
  status := failure

method di reset d -> status
  oarg_rw DataInterface_ di ; arg_rw Data_ d ; arg Status status
  generic
  # resets the subtree starting at this node
  status := failure


method di search d k -> d2
  oarg DataInterface_ di ; arg Data_ d ; arg Str k ; arg Data_ d2
  generic
  # get a link to the node at the end of the edge with the provided name
  d2 := data_null
  d2 base :> d base
  d2 path1 :> new Str d:dbpath+"/"+html_encode:k
  d2 path2 :> null map Str


method di first d start stop buf -> d2
  oarg DataInterface_ di ; arg Data_ d ; arg Str start stop ; arg_w DataScanBuffer buf ; arg Data_ d2
  generic
  # get a link to the first son in the tree which key is >=start and <stop
  # (stop is ignore if it's len is zero)
  # (returns data_null node if none is matching the constains)
  d2 := data_null

method di next d start stop buf -> d2
  oarg DataInterface_ di ; arg Data_ d ; arg Str start stop ; arg_rw DataScanBuffer buf ; arg Data_ d2
  generic
  # get a link to the next son that still match the constains

method di count d start stop -> count
  oarg_rw DataInterface_ di ; arg Data_ d ; arg Str start stop ; arg Int count
  generic
  # get the number of sons that match the constains
  count := 0


method di create d k -> status
  oarg_rw DataInterface_ di ; arg_rw Data_ d ; arg Str k ; arg Status status
  generic
  # creates a new node
  status := failure

method di delete d k -> status
  oarg_rw DataInterface_ di ; arg_rw Data_ d ; arg Str k ; arg Status status
  generic
  # deletes the subtree starting at the node at the end of the edge with the provided name
  status := failure


#--------------------------------------------------------------------------


method di search d k createit -> d2
  oarg_rw DataInterface_ di ; arg_rw Data_ d ; arg Str k ; arg CBool createit ; arg Data_ d2
  d2 := di search d k
  if d2:adr=null and createit
    if (di create d k)=success
      d2 := di search d k


method di first_to_store d start stop buf -> d2
  oarg DataInterface_ di ; arg Data_ d ; arg Str start stop ; arg_w DataScanBuffer buf ; arg Data_ d2
  generic
  d2 := di first d start stop buf

method di next_to_store d start stop buf -> d2
  oarg DataInterface_ di ; arg Data_ d ; arg Str start stop ; arg_rw DataScanBuffer buf ; arg Data_ d2
  generic
  d2 := di next d start stop buf


method di pre_delete d k
  arg DataInterface_ di ; arg Data_ d ; arg Str k
  generic


#--------------------------------------------------------------------------

doc
  [The] ; fixed [ Database_ ] ; [type defines the generic methods that a] ; fixed [ Data_ ] ; [will use to notify the database that a data has been modifyed.]

method db drop
  oarg_rw Database_ db
  generic

method db get_root d
  arg Database_ db ; arg_w Data_ d
  generic
  d := data_null

method db notify_set d adr type
  arg_rw Database_ db ; arg Data_ d ; arg Address adr ; arg Type type
  generic

method db notify_reset d
  arg_rw Database_ db ; arg Data_ d
  generic

method db notify_create d k
  arg_rw Database_ db ; arg Data_ d ; arg Str k
  generic

method db notify_delete d k
  arg_rw Database_ db ; arg Data_ d ; arg Str k
  generic

method db query command -> answer
  oarg Database_ db ; arg Str command answer
  generic
  answer := ""

method db configure command -> status
  oarg_rw Database_ db ; arg Str command ; arg Status status
  generic
  status := failure