Gnucash.idl (was: Gnucash Data Access API)
Thu, 04 Apr 2002 15:08:05 -0500

This is a multipart MIME message.

Content-Type: text/plain; charset=us-ascii

> Derek Atkins writes :
> > [ ... snip ... ]               Moreover, the data files SHOULD NOT
> > be accessed directly by users or other applications...  They should
> > use the Gnucash API.
> To date I have had trouble finding any good information about the
> Gnucash API which I might use for accessing the data. I want/need
> to access the data in a read-only manner (therefore I won't futz
> up the data itself) but am reduced to simply snarfing up the XML
> to get the job done. That works fine, but is NOT what I would 
> consider to be ideal.
> I sincerely don't care what the API might be. I just want to find
> a usable API which is documented. The comments made by Derek above
> give me hope that it _does_ exist, and that someone will point me in
> the right direction. :)
> How about it?? I need access to the accounts, the category definitions,
> and the transactions themselves. Can I do this ... easily? If so, do
> please point me at the documentation which tells me how.

At this point, I don't think there is any such thing.

Probably the easiest way to get at it would be to be running the PostgreSQL 
back end, where a couple of SELECTs should get at the data.

That's definitely not ideal, particularly if you're not running that back end.

Quite a while back (file timestamp says it was last touched in December 2000!) 
I wrote up a draft of some CORBA IDL.  I'll attach that below.  It's NOT 
complete, and hasn't been touched in at least 15 months; it should be 
considered a "strawman proposal" for people to poke holes in.  (It has some 
big holes in it; it's not worth bothering to finish it without it getting 

In these "more modern" days, SOAP is the "protocol-du-jour" (I'm working on a 
book on it at the moment); to a great extent, it represents a 
"worse-is-better" solution which has various ways in which it is quite a bit 
worse than CORBA.  But it's pretty popular, hot in the market, and has an 
XML-based "schema language" called WSDL.

If someone proposed writing up interfaces in a form not unlike gwrap, where 
the resultant bit of quasi-Scheme code would then be processed three different 
ways to generate:
a) gwrap scripts,
b) CORBA IDL corresponding to this,
c) WSDL corresponding to this,

I'd by all means be willing to go along with that idea.  There's no sense in 
writing three or four different interface descriptions by hand when it's 
likely not more difficult to automate it.

At any rate, here's the would-be IDL...
(concatenate 'string "cbbrowne" "")
Rules of the Evil Overlord #37. "If my trusted lieutenant tells me my
Legions of Terror are losing a  battle, I will believe him. After all,
he's my trusted lieutenant." <>

Content-Type: text/plain ; name="gnucash.idl"; charset=us-ascii
Content-Description: gnucash.idl
Content-Disposition: attachment; filename="gnucash.idl"

module GnuCash {
  interface Query {
    enum QueryOp { AND, OR, NAND, NOR, XOR };
    enum amtmatcht { AMT_MATCH_ATLEAST, AMT_MATCH_ATMOST, 
    enum amtmatchsgnt { AMT_SGN_MATCH_EITHER, AMT_SGN_MATCH_CREDIT, 
    struct DatePredicateData {
      long          usestart;
      Timespec     start;
      long          useend;
      Timespec     end;
    struct AmountPredicateData {
      amtmatcht     how;
      amtmatchsgnt amt_sgn;
      double          amount;
    struct AccountPredicateData {
      acctmatcht how;
      Accounts::AccountList accounts;
      // Note that this references a type from
      // module "Accounts"
    struct StringPredicateData {
      strmatching behavior;  /* what kind of search? */
      string matchstring;
      // regex_t        compiled;  // Compilation isn't part of the interface
    } StringPredicateData;
    struct MiscPredicateData {
      long how;  /* Shouldn't this use one of the enums? */
      long data; /* What is this? */
    struct ClearedPredicateData {
      long how;
    union PredicateData switch (pdtypet) {
    case DATE:
      DatePredicateData date;
    case AMOUNT:
      AmountPredicateData amount;
    case ACCOUNT: 
      AccountPredicateData acct;
    case STRING:  
      StringPredicateData str;
    case CLEARED: 
      ClearedPredicateData cleared;
    case MISC: 
      MiscPredicateData misc;  
    struct QueryTerm {
      Predicate p;  /* What is this type supposed to be? */
      PredicateData data;
      long sense;
    /* Something is wrong with the following; I am somehow not correctly
       understanding what the Predicate type is...  I'll punt and
       pretend that a Query consists of a binary tree of QueryTerm
       elements... */
    struct Query {
      QueryTerm qt;
      QueryOp combinethus;
      Query subquery;
    // Locally, there would be the whole host of "Query Construction"
    // functions to build up a complex query.
    void InvokeQuery (in query q, 
		      out Transactions::TransactionList txns);
    /* Note that this references, from the "Transactions" module, the
       "TransactionList" typedef, which would reflect a sequence of
       transactions... */
  interface Commodities {
    struct Commodity {
      string fullname;
      string namespace;
      string mnemonic;
      string exchange;
      long long numerator;
      long long denominator;
  interface Accounts {
    enum AccTypes { BANK, STOCK, CREDIT, INCOME /* and others */   };
    typedef sequence<Account> AccountList;
    struct Account {
      string GUID;
      string accountName;
      string accountCode;
      string description;
      AccTypes accountType;
      Commodity currency;
      Commodity security;
      long currencyscu;
      long securityscu;
      AccountList parent;
      AccountList children;
      Splits::SplitList splits;
    add_account (in Account Acc);
    add_accounts (in AccountList Accs);
    find_account (in string GUID, out Account Acc);
    search_accounts (in string name, in string code, 
		     in string descr, in AccTypes acctype,
		     out AccountList Accs);
    /* There perhaps ought to be a more flexible search, allowing
       constructing a complex search.  Perhaps even including an SQL
       query string. */
  interface Transactions {
    /* Define a "transaction" structure */
    /* And operators to query and update them */
    generateGUID (in string hostname, out string GUID);
  interface Splits {
    /* Localizing the definition of a "split" */
    /* And defining SplitList, referred to up above */
    /* Although it's perhaps *NOT* meaningful to publish
       operations for Splits as such; that should instead probably be
       tied to transactions.  You don't, not publicly, update splits.
       Instead, you update complete transactions */