/* Test/demo script for the Fossil v2 th1ish bindings. */
[import {test-common.th1ish}]
scope { /* Some generic test code... */
const FI = Fossil.file
assert [Fossil.file.isAccessible __FILE]
assert ![Fossil.file.isAccessible __FILE + '.nope']
assert [FI.isFile __FILE]
assert ![FI.isFile __FILE + '.baz']
assert 0 < [FI.size __FILE]
[print "This script's name: " __FILE ' ==canonical==> ' [FI.canonicalName __FILE]]
//[print __SRC ': mtime of this script: ' [strftime '%c' [FI.mtime __FILE]]]
var repoDb = ARGV.flags.r
const f = [Fossil.createContext object{
traceSql: ARGV.flags.S,
repoDb: repoDb,
checkout: ARGV.flags.c ? [getenv 'PWD'] : undefined
}]
if(repoDb){
[print __SRC ': Repo db: ' f.db.repo]
}
var x = [f.selectVal {
SELECT value FROM ckout.vvar WHERE name='repository'
}]
[print 'selectVal = ' x]
assert f inherits Fossil.Context
[print __SRC ': f=' f ', f.db=' f.db]
//[api.ob.push]
if(1 && f.db){
var list = array['repo', 'checkout']
const n = [list.length]
for{var k, name, i = 0}{i<n}{i+=1}{
k = list.(i)
name = f.db.(k)
name || continue
[print __SRC ": Db details: " k name]
//name = db.name
[print "\tDB file: " name]
[print '\tSize:\t' [FI.size name]]
[print '\tmtime:\t' [strftime '%c' [FI.mtime name]]]
}
}
//[api.ob.pop]
assert f.db
if(f.db.repo){
[print "Stash entries:" f.selectVal]
[f.dumpQuery
{SELECT stashid AS stashid,
vid AS vid,
datetime(ctime) AS ctime,
comment AS comment
FROM stash
ORDER BY stashid DESC
}
undefined // bind parameter(s, array)
'\t' // record separator
]
[f.closeRepo]
assert !f.db.repo
assert 'exception' === typename catch{[f.closeRepo]}
}
//[f.finalize] // optional (or let GC take care of it)
/**
[f.openDb ...] works slightly differently than
[Fossil.openDb]. If a FossilContext is the 'this' of
an openDb() call then the db connection gets the array
of fossil-specific DB functions installed and it may
(depending on how it's called) require that the db
be a valid repo. The "extra features" include that the
db will use the Fossil Context's traceSql setting.
*/
/**
openMode is a string which describes how to open/interpret a db file.
The string can contain any of the characters 'r', 'w', 'c', 'v'.
The default access mode is 'rwc' (largely for historical
reasons). If the string contains 'w', write mode is added, and
'c' means "create if not exists"
and implies 'w'. The 'v' flag means to verify that the db is
a repository. This validation currently only works when the db
is opened via Context.openDb(), not Fossil.openDb() (they are
the same function, they just interpret the 'this' argument
differently).
*/
var openMode = 'c'
var db = [f.openDb
//":memory:"
__FILE+'.db'
openMode
]
[print __SRC ': db=' db]
var ex = catch {
[db.execMulti {
BEGIN;
DROP TABLE IF EXISTS t;
CREATE TABLE t(a,b);
COMMIT;
}]
var st = [db.prepare "INSERT INTO t (a,b) VALUES (?,?)"]
[print __SRC ": Prepared statement: " st]
assert 2 === st.parameterCount
assert 0 === st.columnCount
var buf = [api.Buffer 5]
[buf.append 'bbb']
[st.bind 1 'aaa']
[st.bind 2 buf]
[st.step]
[st.reset]
if(0){
const FI = Fossil.file
[buf.capacity [FI.size __FILE] + 2]
[buf.length 0]
[buf.readFile __FILE]
var sz = [buf.length]
assert sz > 0
[buf.compress]
[st.bind array['ccc',buf]]
}else{
[st.bind array['ccc','ddd']]
}
unset buf
[st.step]
[st.finalize]
assert 304 === catch{[st.finalize]}.code
st = [db.prepare "SELECT a a,b b FROM t WHERE ? ORDER BY ROWID"]
assert 2 === st.columnCount
assert 1 === st.parameterCount
assert 2 === [st.columnNames.length]
[st.bind 1 1]
assert [st.step]
assert 'aaa' === [st.get 0]
var b = [st.get 1]
('buffer'===typename b) && (b = [b.toString])
assert 'bbb' === b
[st.reset]
var a = [st.stepArray]
assert 'array' === typename a
assert 'aaa' === a.0
b = a.1
('buffer'===typename b) && (b = [b.toString])
assert 'bbb' === b
[st.reset]
var o = [st.stepObject]
assert 'object' === typename o
assert 'aaa' === o.a
b = o.b
('buffer'===typename b) && (b = [b.toString])
assert 'bbb' === b
[st.finalize]
}
ex && throw ex//[print __SRC ": EXCEPTION:" ex]
const stringify = proc(v){
var b = [api.Buffer]
[b.appendf '%1$J' v]
return [b.toString]
}
var list = array[]
db.each(object{
sql: {SELECT a a, b b FROM t WHERE ?},
bind: true,
mode: 1, //1==array (default), 0==object
callback:proc(){
assert 2 === [columnNames.length]
assert 'a' === columnNames.0
assert 'b' === columnNames.1
assert rowNumber > 0
/** BUG: when this callback is a string,
the script name is unknown in assertion trace
and exceptions here, and line/col are relative to
this callback string. This is because that level
of script bindings doesn't have the call location
info and the script engine cannot figure it out
because of how src locations/script names are
figured out on demand. Not sure how to fix that
(needs to be done (or enabled) at the th1ish
level).
*/
/* __SRC is also (of course) wrong here if callback
is-a String/Buffer.
*/
[list.push [clone this]]
[print __SRC ': row #' rowNumber '=' this]
}
})
[print 'Collected results:' list]
[db.close]
assert 304 === catch{[db.close]}.code
}
0 && scope {
// Holy cow, zlib is a memory hog: it mallocs 64k
// for each de/compression op.
const FI = Fossil.file
var b = [api.Buffer [FI.size __FILE] + 2]
[b.readFile __FILE]
assert b inherits api.prototypes.Buffer
var sz = [b.length]
assert sz > 0
[b.compress]
var szC = [b.length]
assert szC < sz
print("Compressed buffer: ",sz," ==> ",szC)
var zFile = __FILE+'.z';
[b.writeToFile zFile]
print("Compressed copy written to ",zFile);
assert szC === [FI.size zFile]
[b.uncompress]
assert sz === [b.length]
print("Decompressed buffer: ",szC," ==> ",sz)
//print(b.toString())
}
0 && scope {
var b = [api.Buffer 100]
[b.append {abcdefghijklm}]
var bb = [clone b]
assert [bb.length] === [b.length]
//assert bb === b // fixme: Buffer.compare should === here.
//print('compare',[b.compare bb])
//assert 0 === [b.compare bb]
for {var i = 0, sz=[bb.length]}{i<sz}{i+=1}{
assert [b.byteAt i] === [bb.byteAt i]
}
}