1%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    2%    Authors:       Nicos Angelopoulos
    3%    E-mail:        Nicos Angelopoulos http://stoics.org.uk/~nicos/sware/contact.html
    4%    Copyright (C): Nicos Angelopoulos, 2015-2025
    5%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    6/*
    7   This program is free software; you can redistribute it and/or
    8    modify it under the terms of the MIT license
    9
   10    This program is distributed in the hope that it will be useful,
   11    but WITHOUT ANY WARRANTY; without even the implied warranty of
   12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
   13
   14*/
   15:- module( bio_db, [
   16                % This interface has now being split according to 
   17                % biological organisms, see files in cell/
   18                % 1. housekeeping:
   19                % bio_db/0,
   20                bio_db_close/1,
   21                bio_db_db_predicate/1,
   22                bio_db_data_predicate/4,
   23                bio_db_info/2,
   24                bio_db_info/3,
   25                bio_db_info/4,
   26                bio_db_interface/1,
   27                bio_db_interface/2,
   28                bio_db_install/2, bio_db_install/3,
   29                bio_db_organism/1, bio_db_organism/2, bio_db_organism/3,
   30                bio_db_organism_alias/2,
   31                bio_db_org_in_opts/2,
   32                bio_db_paths/0,
   33                bio_db_source/2,
   34                bio_db_version/2,
   35                bio_db_citation/2,
   36                bio_db_close_connections/0,
   37                % 2 derived
   38                % A.symbols
   39                is_symbol/2,
   40                ncbi_symb/3,
   41                % B. gene ontology
   42                go_id/2,          % +/-Go, -/+Int
   43                go_id/3,          % +GoOrInt, -Go, -Int
   44                % C. string edges
   45                org_edge_strg_symb/4  % ?Org, ?Symb1, ?Symb2, -W
   46             ] ).   47
   48:- dynamic( bio_db_handle/5 ).   49
   50:- dynamic( '$bio_db_handle'/2 ). % this is needed for the asserted server preds 
   51
   52
   53% auto-load (& other system) libraries
   54:- use_module(library(lists)).   55:- use_module(library(apply)).   56:- use_module(library(debug)).     % /1,3.
   57:- use_module(library(archive)).   % archive_extract/3.
   58:- use_module(library(filesex)).   59
   60:- use_module(library(lib)).   61
   62% :- ensure_loaded('../src/bio_db_data_predicate').
   63
   64:- lib(source(bio_db), homonyms(true)).   65
   66:- lib(stoics_lib:date_two_digit_dotted/1).   67:- lib(bio_db_data_predicate/4).   68:- lib(go_id/2).   69:- lib(is_symbol/2).   70:- lib(ncbi_symb/3).   71:- lib(org_edge_strg_symb/4).   72:- lib(bio_db_org_in_opts/2).   73:- lib(end(bio_db)).   74
   75% :- initialization( lib(& bio_db, load_main(false)), after_load ).
   76:- initialization( lib(@(bio_db)), after_load ).
 bio_db_organism(?Org)
Colloquial name for organisms supported by bio_db.

Human is considered the default organism and returned first.

?- bio_db_organism(Org).
Org = human ;
Org = chicken ;
Org = mouse ;
Org = multi ;
Org = pig.
author
- nicos angelopoulos
version
- 0:2 2019/4/8
- 0:3 2022/12/29, changed to colloquials and added chicken, were hs and mouse.
- 0:4 2023/6/3, added pig

*/

  100bio_db_organism(human).      % defaulty
  101bio_db_organism(chicken).    % 2022/12/21
  102bio_db_organism(mouse).
  103bio_db_organism(multi).      % 2023/9/15
  104bio_db_organism(pig).        % 2023/6/2
 bio_db_organism(?KnownAs, ?Canon)
 bio_db_organism(?KnownAs, ?Token, ?Canon)
Canon is the canonical, colloquial, representation of organism KnownAs and Token is a 4 letter bio_db representation of that organism.

KnownAs is either a known colloquial name tabled in bio_db_organism/1, an alias to an organism or an organism token. Token is the token used in bio_db predicate, file and directory names for this organism.

?- bio_db_organism(KnownAs,Org), write(KnownAs:Org), nl, fail.
hs:human
gallus:chicken
gallus_gallus:chicken
gg6a:chicken
human:human
chicken:chicken
mouse:mouse
galg:chicken
homs:human
musm:mouse
suss:pig
mult:multi

?- bio_db_organism(hs, Org).
Org = human.

?- bio_db_organism(KnownAs, Token, human).
KnownAs = hs,
Token = homs ;
KnownAs = human,
Token = homs ;
KnownAs = Token, Token = homs.

?- hgnc_homs_symb_hgnc( 'LMTK3', Hgnc ).
Hgnc = 19295.
author
- nicos angelopoulos
version
- 0.2 2019/5/2
- 0.3 2022/12/25, added /3 version, and added many aliases

*/

  149bio_db_organism( Alias, Org ) :-
  150     bio_db_organism( Alias, _Token, Org ).
  151
  152bio_db_organism( Alias, Token, Org ) :-
  153    ( ground(Alias) -> Backtrack = false; Backtrack = true ),
  154    bio_db_organism_alias( Alias, Org ),
  155    ( Backtrack == false -> !; true ),
  156    bio_db_organism_token( Org, Token ).
  157bio_db_organism( Org, Token, Canon ) :-
  158    ( ground(Org) -> Backtrack = false; Backtrack = true ),
  159    bio_db_organism( Org ),
  160    bio_db_organism_token( Org, Token ),
  161    ( Backtrack == false -> !; true ),
  162    Canon = Org.
  163bio_db_organism( TokenIs, Token, Canon ) :-
  164    ( ground(TokenIs) -> Backtrack = false; Backtrack = true ),
  165    bio_db_organism_token( Canon, TokenIs ),
  166    ( Backtrack == false -> !; true ),
  167    Token = TokenIs.
  168
  169bio_db_organism_known( A, T, O ) :-
  170     bio_db_organism( A, T, O ),
  171     !.
  172bio_db_organism_known( A, T, O ) :-
  173     throw( un_known(bio_db_organism(A,T,O)) ).
  174     
  175
  176bio_db_organism_token(chicken, galg).
  177bio_db_organism_token(  human, homs).
  178bio_db_organism_token(  mouse, musm).
  179bio_db_organism_token(  multi, mult).
  180bio_db_organism_token(    pig, suss).
 bio_db_organism_alias(?Alias, -Org)
Alias is a known and supported alternative name for the canonical Org name for an organism.
?- bio_db_organism_alias( human, hs ).
true.

Note this used to be bio_db_organism/2 which has now (19.05.02) changed.

author
- nicos angelopoulos
version
- 0:1 2019/5/2
- 0:2 2022/12/20, gallus also known as chicken and gallus_gallus */
  198bio_db_organism_alias( hs, human ).
  199bio_db_organism_alias( gallus, chicken ).
  200bio_db_organism_alias( gallus_gallus, chicken ).
  201bio_db_organism_alias( gg6a, chicken ).
  202bio_db_organism_alias( gg7w, chicken ).
  203
  204% this search path can be added to requires
  205% bio_db_map/2,
  206% ncbi_homs_ensp_unip/2,
  207% ncbi_homs_ensp_ensg/2,
  208
  209/* was:
  210bio_db_interface_atom( prolog ).
  211bio_db_interface_atom( prosqlite ).
  212bio_db_interface_atom( berkeley ).
  213*/
  214bio_db_interface_atom( Iface ) :-
  215    bio_db_interface_extensions( Iface, _ ).
  216
  217bio_db_interface_initialisation( null ). % so it exists, fixme: should nt this be prolog ?
  218bio_db_interface_initialisation( prosqlite ) :-
  219    use_module( library(prosqlite) ).
  220bio_db_interface_initialisation( berkeley ) :-
  221    use_module( library(bdb) ).
  222bio_db_interface_initialisation( rocks ) :-
  223    use_module( library(rocksdb) ).
  224
  225bio_db_default_interface( prolog ).
  226
  227:- Opts = [access(read_write),type(atom),keep(true)],
  228   bio_db_default_interface( Def ),
  229   create_prolog_flag( bio_db_interface, Def, Opts ).  230
  231:- Opts = [access(read_write),type(atom),keep(true)],
  232   create_prolog_flag( bio_db_pl_from_zip, user, Opts ).  % true/false/user
  233
  234:- Opts = [access(read_write),type(atom),keep(true)],
  235   create_prolog_flag(bio_db_del_zip, user, Opts).        % true/false/user, only asked for pl files
  236
  237:- use_module( library(lib) ).  238:- lib(source(bio_db), homonyms(true)).  239
  240:- lib(options).  241:- lib(pack_errors).  242
  243:- lib(stoics_lib:at_con/3).  244:- lib(stoics_lib:portray_clauses/2).  245:- lib(stoics_lib:url_file/3).  246:- lib(stoics_lib:message_report/3).  247
  248:- lib(ui_yes_no/5).  249:- lib(bio_db_map/2).  250:- ensure_loaded('../auxil/build_repo/lib/bio_db_pl_info').   % /2.
  251:- lib(end(bio_db)).  252
  253stoics( 'https://stoics.org.uk/~nicos/sware/packs/bio_db_repo/data' ).

Access, use and manage big, biological datasets.

Bio_db gives access to pre-packed biological databases and simplifies management and translation of biological data to Prolog friendly formats.

There are currently 2 major types of data supported: maps, and graphs. Maps define product mappings, translations and memberships, while graphs define interactions which can be visualised as weighed graphs (see bio_db_data_predicate/4 for a full list of statically generated list of bio_db data predicates).

There are 2 prolog flags (see current_prolog_flag/2) that can control the behaviour of the library: bio_db_qcompile (def: true) and bio_db_interface (def: prolog). When the first one is set to false, it can disable the compilation to

Bio_db itself does include any of the datasets. You can either download the separate pack(bio_db_repo) which contains all of the Prolog datasets or let pack(bio_db) download the data file one at the time- as needed. As of version v4.4 there are 144 associated data predicates serving 76398976 records.

This pack can be installed as per usual via

?- pack(bio_db_repo).

However, please note this will download all available tables (zipped) with a total download of 477Mb (v4.4). The first time a table is interrogated it is unzipped ot the .pl version and the interpreter automatically also create a .qlf. When the all the tables have been access at least once, the pack will take around 6.3Gb (v4.4).

If you do not want to install all datasets, you should not install the pack as above. Instead pack(bio_db) will download individual data tables the first time you try to access some of its data. Auto-downloading works transparently to the user, where a data set is downloaded by simply calling the predicate.

For example

?- hgnc_homs_symb_hgnc( 'LMTK3', Hgnc ).
% prolog DB:table hgnc:hgnc_homs_symb_hgnc/2 is not installed, do you want to download (Y/n) ?
% Trying to get: url_file(http://www.stoics.org.uk/bio_db_repo/data/maps/hgnc/hgnc_homs_symb_hgnc.pl,/usr/local/users/nicos/local/git/test_bio_db/data/maps/hgnc/hgnc_homs_symb_hgnc.pl)
% Loading prolog db: /usr/local/users/nicos/local/git/test_bio_db/data/maps/hgnc/hgnc_homs_symb_hgnc.pl
Hgnc = 19295.

?- bio_db_interface( prosqlite ).
% Setting bio_db_interface prolog_flag, to: prosqlite
true.

?- hgnc_homs_prev_symb( Prv, Symb ).
% prosqlite DB:table hgnc:hgnc_homs_prev_symb/2 is not installed, do you want to download (Y/n) ?
% Trying to get: url_file(http://www.stoics.org.uk/bio_db_repo/data/maps/hgnc/hgnc_homs_prev_symb.sqlite,/usr/local/users/nicos/local/git/test_bio_db/data/maps/hgnc/hgnc_homs_prev_symb.sqlite)
false.

?- hgnc_homs_prev_symb( Prv, Symb ).
% prosqlite DB:table hgnc:hgnc_homs_prev_symb/2 is not installed, do you want to download (Y/n) ?
% Trying to get: url_file(http://www.stoics.org.uk/bio_db_repo/data/maps/hgnc/hgnc_homs_prev_symb.sqlite,/usr/local/users/nicos/local/git/test_bio_db/data/maps/hgnc/hgnc_homs_prev_symb.sqlite)
% Loading prosqlite db: /usr/local/users/nicos/local/git/test_bio_db/data/maps/hgnc/hgnc_homs_prev_symb.sqlite
Prv = 'A1BG-AS',
Symb = 'A1BG-AS1' .

See bio_db_data_predicate/4 for a way to enumerate all data predicates. The source of which is in src/bio_db_data_predicate.pl which also includes in the comments the cell structure.

As of version 2.0 bio_db is formed of a number of hierarchically organised cells that can be loaded independently. This is because there now too many predicates and is also a devise for better supporting organism specific data. There are currently two main cells, hs (human) and mouse. Each sub-celled by data source of origin.

?- use_module(library(bio_db)).

Loads the whole interface (all cells), without the user needing to be aware of anything. The only difference is that the user will not be able to see all the module predicates at the first line of file pack(bio_db/prolog/bio_db.pl)).

?- lib(bio_db).

Also loads everything.

?- lib(& bio_db).

Loads the skeleton of the module (cells usually laod the module dependencies like this).

?- lib(& bio_db(hs)).

Loads hs cell (and skeleton). hs comprises of a number of sub-cells.

?- lib(& bio_db(hs(hgnc))).

Loads the hs/hgnc primary cell (and the skeleton).

In both the above loads, the following becomes available, however, the former load also loads additional predicates for human, but non hgnc based.

?- hgnc_homs_hgnc_symb( Hgnc, 'LMTK3' ).
Hgnc = 19295.

The following

?- use_module( pack('bio_db/cell/hs/hgnc') ).

also loads just the HGNC part of the human section of bio_db, but it is not a recommended way to do so.

Organisms

galg
Gallus gallus (red junglefowl), colloquial: chicken
homs
Homo sapiens, colloquial: human
mult
covers multiple organisms, longer form: multi
musm
Mus musculus, colloquial: mouse
suss
Sus scrofa (wild boar or Eurasian boar) colloquial: pig

Databases

Ensembl=ense
Homo sapiens genes and proteins. Genes and trascripts mappings along with mapping to genomic location (latter not included in release yet)
HGNC=hgnc
Hugo Gene Nomenclature Committee, http://www.genenames.org/
NCBI=ncbi
NCBI
Uniprot=unip
Protein database.
String=strg
Protein-Protein interactions data base
MGI=mgim
Mouse Genome Informatics, mouse specific datasets (last M for marker, their identifier)
Reactome=reac
Pathway database

For each database, a relation token with the same name, maps the field is the unique identifier of that database.

Other relation tokens

symb
HGNC gene symbol (short, unique name for genes)
name
(HGNC) gene name (long, less standarised version of gene name)
prev
HGNC previous gene symbol
syno
HGNC gene symbol synonym
ensg
ensembl gene
enst
ensembl transcript
ensp
ensembl protein
gonm
GO name of a term
pros
Prosite protein family information
rnuc
RNA nucleic sequence ID to HGNC symbol.
unig
uniprotein gene id
sprt
Swiss-Prot part of Uniprot (high quality, curated)
trem
TrEMBL part of Uniprot (non curated)
mgim
MGI Marker (identifier for Mouse Genome Informatics Markers)
cgnc
Chicken gene nomenclature committee
taxo
taxonomy id (NCBI)
scnm
scientific names for species (NCBI)
gbnm
genbank common name (NCBI)

The name convention for map predicates is

   ?- hgnc_homs_hgnc_symb( Hgnc, Symb ).
   Hgnc = 1,
   Symb = 'A12M1~withdrawn' ;
   Hgnc = 2,
   Symb = 'A12M2~withdrawn' .

   ?- hgnc_homs_hgnc_symb( 19295, Symb ).
   Symb = 'LMTK3'.

   ?- hgnc_homs_symb_hgnc( 'LMTK3', Hgnc ).
  Hgnc = 19295.

Where the first hgnc corresponds to the source database, the second token, homs, identifies the organism, the third and fourth tokens are the fields of the map. Above, the second hgnc

The last part of the predicate name corresponds to the second (or all other) argument(s), which here is the unique Symbol assigned to a gene by HGNC. In the current version of bio_db, all tokens in map filenames are 4 characters long. Map data for predicate Pname from database DB are looked for in DB(Pname.Ext) (see bio_db_paths/0). Extension, Ext, depends on the current bio_db database interface (see bio_db_interface/1), and it is sqlite if the interface is prosqlite and pl otherwise.

The name convention for graphs is

  ?- strg_homs_edge_symb( Symb1, Symb2, W ).
  S1 = 'A1BG',
  S2 = 'ABAT',
  W = 360 ;
  S1 = 'A1BG',
  S2 = 'ABCC6',
  W = 158 .

The first part indicates the database and the second one the organism/species. Graph data for predicate Pname from database DB are looked for in bio_db_data(graphs/DB/Pname.Ext) (see bio_db_paths/1). Extension, Ext, depends on the current bio_db database interface (see bio_db_interface/1), and it is sqlite if the interface is prosqlite and pl otherwise.

Bio_db supports four db interfaces: prolog, prosqlite, berkeley and rocks. The first one is via Prolog fact bases, which is the default. The second is an interface to SQLite via pack(prosqlite) while the third and fourth work with the SWI-Prolog packs bdb and rocksdb. The underlying mechanisms are entirely transparent to the user. In order to use the sqlite data sources pack(prosqlite) needs to be installed via the pack manager

 ?- pack_install( prosqlite ).

The user can control which interface is in use with the bio_db_interface/1 predicate.

 ?- bio_db_interface( Curr ).
 Curr = prolog.

 ?- bio_db_interface( prosqlite ).

 ?- bio_db_interface( Curr ).
 Curr = prosqlite.

The type of the interface of a bio_db data predicate is determined by the interface at the time of first call.

Once the user has initiated the serving of a predicate via calling a goal to it, it is then possible to have access to information about the dataset such as download date and sourle url.

?- hgnc_homs_hgnc_symb( Hgnc, Symb ).
Hgnc = 1,
Symb = 'A12M1~withdrawn' .

?- bio_db_info( hgnc_homs_hgnc_symb/2, Key, Value ), write( Key-Value ), nl, fail.
interface-prolog
source_url-ftp://ftp.ebi.ac.uk/pub/databases/genenames/hgnc_complete_set.txt.gz
datetime-datetime(2018,11,27,12,32,11)
data_types-data_types(integer,atom)
unique_lengths-unique_lengths(46023,46023,46023)
relation_type-relation_type(1,1)
header-row(HGNC ID,Approved Symbol)
false

As of version 2.0 there are two flags that can automate some of the interactions.

:- set_prolog_flag(bio_db_pl_from_zip, user).
:- set_prolog_flag(bio_db_del_zip, user).

In both cases the recognised values for the flags are: [user,true,false]. User is for prompting the user and true is progressing with an implicit yes answer. The first flag automates conversion from .pl.zip to .pl (which will be the case for the first time you access any dataset if you have installed bio_db_repo), and the second controls the deletion of the zip file once the .pl file has been created.

As of version 4.0 there are 91 associated data predicates serving 55444729 records.

Thanks to Jan Wielemaker for a retractall fix and for code for fast loading of precompiled fact bases (and indeed for the changes in SWI that made this possible).

author
- nicos angelopoulos
version
- 0.5 2016/09/11
- 0.7 2016/10/21, experimenting with distros in github
- 0.9 2017/03/10, small changes for pack(requires) -> pack(lib) v1.1
- 1.0 2017/10/09, to coincide with ppdp paper presentation
- 2.1 2018/11/27, introduces cells and mouse data (and fixed dependency of 2.0)
- 2.4 2019/04/02, test: bio_db_stats, new mouse db predicates, iface: bio_db_data_predicate/4
- 2.5 2019/04/22, edge_strg_symb/4; bio_db_organism/1,2; go_id/2,3
- 2.6 2019/05/08, changed to organism alias interface; evidence in gont maps
- 2.7 2019/05/12, edge_strg_symb/4 -> org_edge_strg_symb/4
- 3.0 2019/05/15, paper submission
- 3.1 2020/03/09, fixed lib; no unigene
- 3.2 2020/09/18, include mouse ense + fixes/updates on building scripts
- 3:4 2021/05/10, removed edge_gont_includes/2 (reciprocal of is_a), and edge_gont_consists_of/2 (reciprocal of part_of/2)
- 3:6 2021/12/04, fixed pack_errors and map_ense_mouse_enst_chrl/5; bio_db_stats.pl version 0.2
- 4:1 2022/12/29, huge re-config of data predicate names + reac-tome (maps) + chicken
- 4:2 2023/06/06, support for pig
- 4:3 2023/10/05, mult for multi organisms; vgnc database; ncbi taxonomy db; build-reorganisation
- 4:4 2024/04/05, db(ncbi) preds were complete rehaul, better and more complete db(reactome) support, fixed pig cells
- 4:5 2024/04/05, fixed certificate issue when downloading individual files of bio_db_repo
- 4:6 2024/10/17, gg7w for loghorn chicken, hgnc change of base URL
- 4:7 2025/3/28, reactome predicate in sus scrofa; missing is_symbol/2 for chicken and pig
- 4:8 2026/6/18, updates to a number of download URLs :vgnc, cgnc & ense; factor out code for vgnc (multi+pig)
See also
- doc/Releases.txt for version details
- bio_db_data_predicate/4 for a way to enumerate all data predicates
- cell/ for the definitions of the data predicates

*/

 bio_db_paths
Initialisation call- setting up path aliases.

There are two main directory repositories the predicate deals with: (a) the bio_db installed databases root (alias bio_db_data), and (b) the root of downloaded databases (alias bio_db_downloads). Optionally a top directory of which both (a) and (b) are subdirs can be defined (alias bio_db). The default value for alias bio_db is a made-up pack directory pack(bio_db_repo). The default for bio_db_data is sub directory data of alias bio_db, while bio_db_downloads defaults to sub directory downloads of the alias bio_db. The canonical subdirectory name for (a) is data and for (b) is downloads.

pack(bio_db_repo) can also be installed as a complete package from SWI's manager.

?- pack_install( bio_db_repo ).

This will install all the Prolog database files. The single tar and gzipped file is 246 Mb in size and the fully expanded version of a Prolog installation can take up to 3.1Gb. The precise size depends on how many tables are accessed at least once (each producing an expanded .pl and a .qlf file).

Directory locations for (a) and (b) above can be given as either prolog flags with key bio_db_root and bio_dn_root respectively or via environment variables BioDbRoot and BioDnRoot.

Installed root alias(bio_db_data) contains sub-dirs

graphs
for graphs; string and reactome
maps
for all the supported maps

The above are mapped to aliases bio_graphs and bio_maps respectively. Within each of these sub-directories there is further structure based on the database the set was originated.

Downloaded root alias(bio_db_downloads) may contain sub-dirs

hgnc
data from HGNC database
ncbi
data from NCBI database
reactome
data from Reactome database
string
data from string database
uniprot
protein data from EBI
ense
ensembl database

Alias bio_db_downloads is only useful if you are downloading data files directly from the supported databases.

See

?- absolute_file_name( packs(bio_db(auxil)), Auxil ), ls( Auxil ).

for examples of how these can be used.

For most users these aliases are not needed as the library manages them automatically.

To be done
- transfer datasets and downloads to new pack location when running on newly installed SWI version upgrade.

*/

  662bio_db_paths :-
  663    bio_db_paths_root,
  664    bio_db_paths_installed,
  665    bio_db_paths_installed_sub,
  666    bio_db_paths_downloaded.
  667
  668bio_db_paths_root :-
  669    bio_db_setting( bio_db_root, Root ),
  670    !,
  671    bio_db_path_new( bio_db, Root ).
  672bio_db_paths_root.
  673
  674bio_db_paths_installed :-
  675    bio_db_setting( bio_db_data_root, DbRoot ),
  676    !,
  677    bio_db_path_new( bio_db_data, DbRoot ).
  678bio_db_paths_installed :-
  679    user:file_search_path( bio_db, BioDb ),
  680    os_path_1( BioDb, data, BioDbData ),
  681    % exists_directory( DbRoot ),
  682    !,
  683    bio_db_path_new( bio_db_data, BioDbData ).
  684bio_db_paths_installed :-
  685    throw( missing_setting(bio_db_data_root) ).
  686
  687bio_db_paths_downloaded :-
  688    bio_db_setting( bio_db_downloads_root, DnRoot ),
  689    !,
  690    bio_db_path_new( bio_db_downloads, DnRoot ).
  691bio_db_paths_downloaded :-
  692    user:file_search_path( bio_db_downloads_root, BioRoot ),
  693    os_path_1( BioRoot, downloads, DnRoot ),
  694    exists_directory( DnRoot ),
  695    !,
  696    bio_db_path_new( bio_db_downloads, DnRoot ).
  697
  698bio_db_paths_installed_sub :-
  699    user:file_search_path( bio_db_data, DbRoot ),
  700    findall( Sub, bio_db_sub(Sub), Subs ),
  701    maplist( bio_db_paths_installed_sub(DbRoot), Subs ),
  702    !.
  703
  704bio_db_paths_installed_sub( DbRoot, Sub ) :-
  705    os_path_1( DbRoot, Sub, AbsSub ),
  706    % exists_directory( Abs ),
  707    % directory_files( Abs, DbSubs ), % os_dirs
  708    ( atom_concat(SubSingular,'s',Sub) -> true; SubSingular = Sub ),
  709    atom_concat( bio_, SubSingular, BioDbSub ),
  710    bio_db_path_new( BioDbSub, AbsSub ),
  711    % os_path_1( AbsSub, Db, AbsDb )
  712    % bio_db_path_new( Db, AbsDb ),
  713    % bio_db_source( Sub, Db ),
  714    findall( DbSub, bio_db_source(Sub,DbSub), DbSubs ),
  715    maplist( bio_db_paths_installed_sub_dbs(AbsSub,Sub), DbSubs ),
  716    !.
  717bio_db_paths_installed_sub( _DbRoot, _Sub ).
  718
  719bio_db_paths_installed_sub_dbs( Abs, Sub, Db ) :-
  720    bio_db_source( Sub, Db ),
  721    os_path_1( Abs, Db, Full ),
  722    bio_db_path_new( Db, Full ).
  723% bio_db_paths_installed_sub_dbs( _Abs, _Sub ).
  724
  725bio_db_setting( PlSet, Value ) :-
  726    current_prolog_flag( PlSet, Value ),
  727    debug( bio_db, 'bio_db setting via flag: ~w, set to: ~w', [PlSet,Value] ),
  728    !.
  729bio_db_setting( PlSet, Value ) :-
  730    atomic_list_concat( Parts, '_', PlSet ),
  731    maplist( upcase_first, Parts, Arts ),
  732    atomic_list_concat( Arts, EnvVar ),
  733    getenv( EnvVar, Value ),
  734    debug( bio_db, 'bio_db setting via env: ~w, setting: ~w, set to: ~w', [EnvVar,PlSet,Value] ),
  735    !.
  736bio_db_setting( PlSet, Value ) :-
  737    bio_db_setting_default( PlSet, Value ).
  738
  739bio_db_path_new( Alias, New ) :-
  740    user:file_search_path( Alias, Old ),
  741    bio_db_path_new_exists( Alias, Old, New ),
  742    !.
  743bio_db_path_new( Alias, Path ) :-
  744    debug( bio_db, 'Asserting search alias: ~w, to ~p', [Alias,Path] ),
  745    assert( user:file_search_path(Alias,Path) ).
  746
  747bio_db_path_new_exists( _Alias, Old, Old ) :-
  748    !.
  749bio_db_path_new_exists( Alias, Old, New ) :-
  750    throw( fixme(alias_exists(Alias,Old,New)) ).
  751
  752bio_db_path_exists( Alias ) :- % fixme: is this called from anywhere ?
  753    throw( fixme(bio_db_paths_installed/0,search_path_exists(Alias)) ).
  754
  755upcase_first( Atom, Upped ) :-
  756    sub_atom( Atom, 0, 1, _, Flw ), 
  757    upcase_atom( Flw, Fup ),
  758    atom_length( Atom, Len ),
  759    Ken is Len - 1,
  760    sub_atom( atom, 1, Ken, 0, Tail ),
  761    atom_concat( Fup, Tail, Upped ).
 bio_db_version(-Vers, -Date)
Version Mj:Mn:Fx, and release date date(Y,M,D).
?- bio_db_version(V, D).
V = 4:8:0,
D = date(2026, 6, 18).
author
- Nicos Angelopoulos
version
- 4:8 2026/6/18, fixes, and building scripts
See also
- bio_db_data_predicate/4 (which should be generated for each new version)
- doc/Releases.txt for more detail on change log
- module documentation for brief comments on versioning history of this pack

*/

  780bio_db_version(4:8:0, date(2026,6,18)).
 bio_db_citation(-Atom, -Bibterm)
This predicate succeeds once for each publication related to this library. Atom is the atom representation suitable for printing while Bibterm is a bibtex(Type,Key,Pairs) term of the same publication. Produces all related publications on backtracking.
  790bio_db_citation( Atom, bibtex(Type,Key,Pairs) ) :-
  791  Atom = 'Accessing biological data as Prolog facts.\nNicos Angelopoulos and Jan Wielemaker. In Proceedings of 19th International Symposium on Principles and Practice of Declarative Programming, Namur, Belgium, October, 2017 (PPDP\'17), 10 pages.',
  792  Type = inproceedings,
  793  Key  = 'AngelopoulosN_GiamasG_2015',
  794  Pairs = [
  795               title  = 'Accessing biological data as Prolog facts',
  796               author = 'Nicos Angelopoulos and Jan Wielemaker',
  797               booktitle= '19th International Symposium on Principles and Practice of Declarative Programming',
  798               year = 2017,
  799               month = 'October',
  800               address= 'Namur, Belgium'
  801               % url     = 'http://ceur-ws.org/Vol-1433/tc_74.pdf'
  802     ].
  803
  804bio_db_citation( Atom, bibtex(Type,Key,Pairs) ) :-
  805  Atom = 'A logical approach to working with biological databases.\nNicos Angelopoulos and Georgios Giamas.\nProceedings of the 31st International Conference on Logic Programming (ICLP 2015) Accepted as a technical communication.\nCork, Ireland. September 2015.',
  806  Type = inproceedings,
  807  Key  = 'AngelopoulosN_GiamasG_2015',
  808  Pairs = [
  809               author = 'Nicos Angelopoulos and Georgios Giamas',
  810               title  = 'A logical approach to working with biological databases',
  811               booktitle= 'Technical Communication in Proceedings of the 31st International Conference on Logic Programming (ICLP 2015)',
  812               year = 2015,
  813               month = 'September',
  814            address= 'Cork, Ireland',
  815               url     = 'http://ceur-ws.org/Vol-1433/tc_74.pdf'
  816     ].
  817
  818bio_db_citation( Atom, bibtex(Type,Key,Pairs) ) :-
  819    Atom = 'Working with biological databases.\nNicos Angelopoulos and Georgios Giamas.\n1th Workshop on Constraint Based Methods for Bioinformatics (2015)\nCork, Ireland. September 2015',
  820    Type    = inproceedings,
  821    Key  = 'AngelopoulosN_GiamasG_2015a',
  822    Pairs = [
  823               author = 'Nicos Angelopoulos and Georgios Giamas',
  824            title  = 'Working with biological databases',
  825            booktitle = '11th Workshop on Constraint Based Methods for Bioinformatics (2015)',
  826            year = 2015,
  827            month = 'September',
  828            address = 'Cork, Ireland',
  829            url = 'http://clp.dimi.uniud.it/wp/wp-content/uploads/2015/08/WCB_2015_paper_1.pdf'
  830    ].
 bio_db_source(?Type, ?Db)
True if Db is a source database for bio_db serving predicate of type Type. Type is either maps or graphs.

The databases are

To be done
- fixme: this gets out of synch for new dbs, maybe have it in other location or throw a message if it fails ? */
  846bio_db_source(maps, hgnc).
  847bio_db_source(maps, gont).
  848bio_db_source(maps, ncbi).
  849bio_db_source(maps, unip).
  850bio_db_source(maps, vgnc).
  851bio_db_source(graphs, string ).
  852% bio_db_source( graphs, gont ). % these are used for aliases, so gont already exists
  853bio_db_source( graphs, reactome ).
  854
  855bio_db_sub(graphs).
  856bio_db_sub(maps).
  857
  858bio_db_setting_default( 'bio_db_root', BioDbRoot ) :-
  859    absolute_file_name( pack(bio_db), BioDb ),
  860    directory_file_path( Dir, bio_db, BioDb ),
  861    directory_file_path( Dir, bio_db_repo, BioDbRoot ).
  862bio_db_setting_default( 'bio_db_data_root', BioDbData ) :-
  863    absolute_file_name( bio_db(data), BioDbData ).
  864bio_db_setting_default( 'bio_db_downloads_root', BioDbDnloads ) :-
  865    absolute_file_name( bio_db(downloads), BioDbDnloads ).
 bio_db_interface(?Iface, -Status)
Interrogate the installation status (true or false) of bio_db's known interfaces. true if the interface dependencies are installed and the interface can be used, and =|false=| otherwise.

Can be used to enumerate all known or installed interfaces.

 ?- findall( Iface, bio_db_interface(Iface,_), Ifaces ).
 Ifaces = [prolog, berkeley, prosqlite, rocks].
  880bio_db_interface( prolog, true ).
  881bio_db_interface( berkeley, Bool ) :-
  882    ( catch( use_module( library(bdb) ), _, fail ) -> Bool = true; Bool = false ).
  883bio_db_interface( prosqlite, Bool ) :-
  884    ( catch( use_module( library(prosqlite) ), _, fail ) -> Bool = true; Bool = false ).
  885bio_db_interface( rocks, Bool ) :-
  886    ( catch( use_module( library(rocksdb) ), _, fail ) -> Bool = true; Bool = false ).
 bio_db_interface(?Iface)
Interrogate or set the current interface for bio_db database predicates. By default Iface = prolog. Also supported: prosqlite (needs pack proSQLite), berkley (needs SWI's own library(bdb) and rocks (needs pack(rocskdb).
?- bio_db_interface( Iface ).
Iface = prolog.

?- debug( bio_db ).
true.

?- bio_db_interface( wrong ).
% Could not set bio_db_interface prolog_flag, to: wrong, which in not one of: [prolog,prosqlite,berkeley,rocks]
false.

?- bio_db_interface( Iface ).
Iface = prolog.

?- hgnc_homs_symb_hgnc( 'LMTK3', Hgnc ).
% Loading prolog db: /usr/local/users/nicos/local/git/lib/swipl-7.1.32/pack/bio_db_repo/data/maps/hgnc/hgnc_homs_symb_hgnc.pl
Hgnc = 19295.

?- bio_db_interface( prosqlite ).
% Setting bio_db_interface prolog_flag, to: prosqlite
true.

?- hgnc_homs_prev_symb( Prev, Symb ).
% prosqlite DB:table hgnc:hgnc_homs_prev_symb/2 is not installed, do you want to download (Y/n) ?
% Execution Aborted
?- hgnc_homs_prev_symb( Prev, Symb ).
% Loading prosqlite db: /usr/local/users/nicos/local/git/lib/swipl-7.1.32/pack/bio_db_repo/data/maps/hgnc/hgnc_homs_prev_symb.sqlite
Prev = 'A1BG-AS',
Symb = 'A1BG-AS1' ;

In which case Iface is prosqlite.

  928bio_db_interface( Iface ) :-
  929    var( Iface ),
  930    !,
  931    current_prolog_flag( bio_db_interface, IfacePrv ),
  932    bio_db_interface_known( IfacePrv, Iface ).
  933bio_db_interface( Iface ) :-
  934    ground( Iface ),
  935    bio_db_interface_set( Iface ).
  936
  937bio_db_info( Iface, Pid, Key, Value ) :-
  938    var( Iface ),
  939    !,
  940    bio_db_info_gen( Iface, Pid, Key, Value ).
  941bio_db_info( Iface, Pid, Key, Value ) :-
  942    atom( Iface ),
  943    bio_db_info_source( Iface, Pid, Key, Value ).
  944
  945bio_db_info_gen( Iface, Pid, Key, Value ) :-
  946    bio_db_interface_extensions( Iface, _ ),
  947    bio_db_info( Iface, Pid, Key, Value ).
  948
  949bio_db_install_defaults( [org(hs),interactive(true)] ).
 bio_db_install(+PidOrPname, +Iface)
 bio_db_install(+PidOrPname, +Iface, +Opts)
Install the interface (Iface) for bio_db database that corresponds to predicate identifier (Pid) or a predicate name (Pname). Note that this is not necessary to do in advance as the library will auto load missing Iface and Pid combinations when first interrogated.

Opts

interactive(Ictive=true)
set false to accept default interactions
org(Org=hs)
organism

*/

  965bio_db_install( PorP, Iface ) :-
  966    bio_db_install( PorP, Iface, [] ).
  967bio_db_install( PorP, Iface, OptS ) :-
  968    options_append( bio_db_install, OptS, Opts ),
  969    options( interactive(Ictive), Opts ),
  970    options( org(Org), Opts ),
  971    bio_db_porp_call( PorP, bio_db_install/2, Call ),
  972    bio_db_map_call_db_pname( Call, Db, Pname, Arity ),
  973    ( bio_db_info(Iface,PorP,_,_) -> 
  974        Mess = '~a DB:table ~w is already installed. It will be overwritten. Continue',
  975        Args = [Iface,PorP],
  976        ui_yes_no( Ictive, Mess, Args, y, Reply ), 
  977        ( Reply == true ->
  978            bio_db_interface_extensions( Iface, [Ext|_] ),
  979            ( bio_db_pname_source(Org,Db,Pname,read,Ext,File) ->
  980                delete_installed( Ext, File )
  981                ;
  982                true
  983            ),
  984            bio_db_serve_pname( false, false, Org, Db, Pname, Arity, Iface, Call )
  985            ;
  986            % ensure qlf is also installed, before failing
  987            ( Iface == prolog ->
  988                ( bio_db_pname_source(Org,Db,Pname,read,qlf,_ExistFile) ->
  989                    Mess1 = 'Qlf is also istalled.',
  990                    phrase('$messages':translate_message(debug(Mess1,[])), Lines1),
  991                    print_message_lines(current_output, kind(informational), Lines1)
  992                    ;
  993                    bio_db_pname_source( Org, Db, Pname, read, pl, File ),
  994                    bio_db_load_call( false, Pname, Arity, Iface, File, true )
  995                )
  996                ;
  997                true
  998            )
  999        )
 1000        ;
 1001        bio_db_serve_pname( false, false, Db, Pname, Arity, Iface, Call )
 1002    ).
 1003
 1004delete_installed( rocks, Dir ) :-
 1005    delete_installed_db_dir_and_info( Dir ).
 1006delete_installed( db, File ) :-
 1007    delete_installed_db_file_and_info( File ).
 1008delete_installed( sqlite, File ) :-
 1009    delete_installed_db_file_and_info( File ).
 1010delete_installed( pl, File ) :-
 1011    delete_installed_db_file_and_info( File ),
 1012    file_name_extension( Stem, _Ext, File ),
 1013    file_name_extension( Stem,  qlf, Qile ),
 1014    ( exists_file(Qile) ->
 1015        debug( bio_db, 'Deleting file: ~p', Qile ),
 1016        delete_file(Qile)
 1017        ;
 1018        true
 1019    ).
 1020
 1021delete_installed_db_file_and_info( File ) :-
 1022    ( exists_file(File) ->
 1023        debug( bio_db, 'Deleting file: ~p', File ),
 1024        delete_file( File )
 1025        ;
 1026        true
 1027    ),
 1028    file_name_extension( Stem, Ext, File ),
 1029    atom_concat( Stem, '_info', InfoStem ),
 1030    file_name_extension( InfoStem, Ext, InfoFile ),
 1031    ( exists_file(InfoFile) ->
 1032        debug( bio_db, 'Deleting file: ~p', InfoFile ),
 1033        delete_file( InfoFile )
 1034        ;
 1035        true
 1036    ).
 1037
 1038delete_installed_db_dir_and_info( Dir ) :-
 1039    ( exists_directory(Dir) ->
 1040        debug( bio_db, 'Deleting directory: ~p', Dir ),
 1041        delete_directory_contents( Dir )
 1042        ;
 1043        true
 1044    ),
 1045    file_name_extension( Stem, Ext, Dir ),
 1046    atom_concat( Stem, '_info', InfoStem ),
 1047    file_name_extension( InfoStem, Ext, InfoDir ),
 1048    ( exists_directory(InfoDir) ->
 1049        debug( bio_db, 'Deleting directory: ~p', InfoDir ),
 1050        delete_directory_contents( InfoDir )
 1051        ;
 1052        true
 1053    ).
 bio_db_porp_call(PorP, CallerId, Call)
Constract a generic call from predicate id or predicate name (Porp).

*/

 1060bio_db_porp_call( Porp, Cid, Call ) :-
 1061    ground( Porp ),
 1062    bio_db_porp_call_ground( Porp, Cid, Call ).
 1063
 1064bio_db_porp_call_ground( Pname/Arity, _Cid, Call ) :- !,
 1065    functor( Call, Pname, Arity ).
 1066bio_db_porp_call_ground( Pname, Cid, Call ) :-
 1067    % find the name from the module def of bio_db. A bit hackish.
 1068    atom( Pname ),
 1069    absolute_file_name( pack('bio_db/prolog/bio_db.pl'), BioDbF, [access(exist)] ),
 1070    open( BioDbF, read, In ),
 1071    read( In, ModuleDef ), 
 1072    close( In ),
 1073    ModuleDef = (:- module( bio_db, Pids ) ),
 1074    ( memberchk(Pname/Arity,Pids) ->
 1075        true
 1076        ;
 1077        throw( not_a_db_pred(Pname), [pack(bio_db),pred(Cid)] )
 1078    ),
 1079    functor( Call, Pname, Arity ).
 bio_db_predicate_name(+PidOrPname, -Pname)
Auxiliary predicate that strips the Pname of Pid or assumes atomic PidOrPname to be a Pname.
To be done
- check it looks like a db name. this is only useful for db_preds.

*/

 1089bio_db_predicate_name( Pid, Pname ) :-
 1090    ground( Pid ),
 1091    bio_db_predicate_name_ground( Pid, Pname ).
 1092
 1093bio_db_predicate_name_ground( Pname/_, Pname ) :- !.
 1094bio_db_predicate_name_ground( Pname, Pname ) :-
 1095    atom( Pname ).
 1096
 1097bio_db_predicate_db( Pid, Db ) :-
 1098    bio_db_predicate_name( Pid, Pname ),
 1099    atomic_list_concat( [_,Db|_], '_', Pname ).
 1100
 1101bio_db_info_source( Iface, Pid, Key, Value ) :-
 1102    bio_db_predicate_name( Pid, Pname ),
 1103    bio_db_predicate_db( Pname, Db ),
 1104    bio_db_pname_source( Db, Pname, read, Iface, DbF ),
 1105    ( bio_db_interface_initialisation(Iface) -> true; true ),
 1106    bio_db_info_db_file( Iface, Pid, DbF, Key, Value ).
 1107
 1108bio_db_info_db_file( prolog, _Pid, DbF, Key, Value ) :-
 1109    bio_db_pl_info( DbF, Infos ),
 1110    member( Info, Infos ),
 1111    arg( 1, Info, Key ),
 1112    arg( 2, Info, Value ).
 1113bio_db_info_db_file( prosqlite, Pid, DbF, Key, Value ) :-
 1114    bio_db_predicate_info( Pid, Info ),
 1115    % bio_db_source_info( DbF, InfoF ),
 1116    sqlite_connect( DbF, Info ),
 1117    atom_concat( 'Select * from ', Info, Query ),
 1118    findall( Row, sqlite_query(Info,Query,Row), Rows ),
 1119    sqlite_disconnect( Info ),
 1120    member( row(Key,ValueAtom), Rows ),
 1121    ( catch(atom_to_term(ValueAtom,Value,_),_,fail) ->
 1122        true
 1123        ;
 1124        Value = ValueAtom
 1125    ).
 1126bio_db_info_db_file( berkeley, Pid, DbF, Key, Value ) :-
 1127    bio_db_info_interface_infos( berkeley, Pid, DbF, _,  KVs ),
 1128    member( Key-Value, KVs ).
 1129bio_db_info_db_file( rocks, Pid, DbF, Key, Value ) :-
 1130    bio_db_info_interface_infos( rocks, Pid, DbF, _,  KVs ),
 1131    member( Key-Value, KVs ).
 bio_db_info(+Pid, ?Iface)
 bio_db_info(+Pid, ?Key, -Value)
 bio_db_info(+Iface, +Pid, ?Key, -Value)
Retrieve information about bio_db database predicates.

When Iface is not given, Key and Value are those of the interface under which Pid is currently open for access. The predicate errors if Pid is not open for serving yet.

The bio_db_info/2 version succeeds for all interfaces Pid is installed- it is simply a shortcut to: bio_db_info( Iface, Pid, _, _ ).

The Key-Value information returned are about the particular data predicate as saved in the specific backend.

Key

source_url
an atomic value of the URL
datetime
datetime/6 term
data_types
data_types/n given the primary type for each argyument in the data table
header
row/n term, where n is the number of columns in the data table
unique_lengths
unique_lengths/3 term, lengths for the ordered sets of: Ks, Vs and KVs
relation_type(From, TO)
where From and To take values in 1 and m
?- bio_db_info( Iface, hgnc_homs_hgnc_symb/2, Key, Value), write( Iface:Key:Value ), nl, fail.
prolog:source_url:ftp://ftp.ebi.ac.uk/pub/databases/genenames/hgnc_complete_set.txt.gz
prolog:datetime:datetime(2016,9,10,0,2,14)
prolog:data_types:data_types(integer,atom)
prolog:unique_lengths:unique_lengths(44266,44266,44266)
prolog:relation_type:relation_type(1,1)
prolog:header:row(HGNC ID,Approved Symbol)
prosqlite:source_url:ftp://ftp.ebi.ac.uk/pub/databases/genenames/hgnc_complete_set.txt.gz
prosqlite:datetime:datetime(2016,9,10,0,2,14)
prosqlite:data_types:data_types(integer,atom)
prosqlite:unique_lengths:unique_lengths(44266,44266,44266)
prosqlite:relation_type:relation_type(1,1)
prosqlite:header:row(HGNC ID,Approved Symbol)

*/

 1185bio_db_info( PorP, Iface ) :-
 1186    bio_db_info( Iface, PorP, _, _ ),
 1187    !.
 1188
 1189bio_db_info( Pid, Key, Value ) :-
 1190    bio_db_db_predicate( Pid ),
 1191    !,
 1192    bio_db_info_pred( Pid, Key, Value ).
 1193bio_db_info( Pid, _Key, _Value ) :-
 1194    throw( not_a_db_pred(Pid), [pack(bio_db),pred(bio_db_info/3)] ).
 1195
 1196bio_db_info_pred( Pid, Key, Value ) :-
 1197    bio_db_handle( Pid, Iface, File, Handle, _Mod ),
 1198    !,
 1199    bio_db_info_interface( Iface, Pid, File, Handle, Key, Value ).
 1200
 1201bio_db_info_pred( Pid, _Key, _Value ) :-
 1202    throw( close_to_info(Pid), [pack(bio_db),pred(bio_db_info/3)] ).
 1203
 1204bio_db_info_interface_kvs( Iface, Pid, File, Handle, KVs ) :-
 1205    bio_db_info_interface_infos( Iface, Pid, File, Handle, Pairs ),
 1206    \+ var( KVs ),
 1207    bio_db_info_interface_kvs( KVs, Pairs ).
 1208    
 1209bio_db_info_interface_kvs( [], _ ).
 1210bio_db_info_interface_kvs( [K-V|T], Pairs ) :-
 1211    memberchk( K-V, Pairs ),
 1212    bio_db_info_interface_kvs( T, Pairs ).
 1213    
 1214bio_db_info_interface( Iface, Pid, File, Handle, Key, Value ) :-
 1215    bio_db_info_interface_infos( Iface, Pid, File, Handle, KVs ),
 1216    member( Key-Value, KVs ).
 1217    
 1218bio_db_info_interface_infos( Callable, Pid, _File, _Handle, Pairs ) :-
 1219    memberchk( Callable, [prolog,prosqlite] ),
 1220    !,
 1221    bio_db_predicate_info( Pid, InfoName ),
 1222    Goal =.. [InfoName,Key,Value],
 1223    findall( Key-Value, ( (Key = interface, Value = Callable) ;  bio_db:Goal ), Pairs ).
 1224bio_db_info_interface_infos( berkeley, _Pid, File, _Handle, KVs ) :-
 1225    % fixme add key = Berkley interface
 1226    % ( ((Key=interface, Value=berkeley); bdb_enum( Handle, info+Key , Value)) ).
 1227    bio_db_source_info( File, InfoF ),
 1228
 1229    bdb_open( InfoF, read, InfoHandle, [key(atom),value(term)] ),
 1230    findall( AKey-AValue, bdb_enum(InfoHandle,AKey,AValue), Pairs ),
 1231    bdb_close( InfoHandle ),
 1232    KVs = [interface-berkeley|Pairs].
 1233bio_db_info_interface_infos( rocks, _Pid, File, _Handle, KVs ) :-
 1234    % fixme add key = Berkley interface
 1235    file_name_extension( Stem, Ext, File ),
 1236    atom_concat( Stem, '_info', InfoStem ),
 1237    file_name_extension( InfoStem, Ext, InfoFile ),
 1238    rocks_open( InfoFile, InfoHandle, [key(atom),value(term)] ),
 1239    findall( AKey-AValue, rocks_enum(InfoHandle,AKey,AValue), Pairs ),
 1240    rocks_close( InfoHandle ),
 1241    KVs = [interface-rocks|Pairs].
 bio_db_close(+Pid)
Close the current serving of predicate Pid. Next time a Pid Goal is called the current interface (bio_db_interface/1) will be used to establish a new server and resolve the query.

Predicate throws an error if the Pid does not correspond to a db_predicate or if it is not currently servered by any of the backends.

?- bio_db_interface(prosqlite).
?- hgnc_homs_hgnc_symb( Hgnc, Symb ).
Hgnc = 506,
Symb = 'ANT3~withdrawn' .

?- bio_db_close( hgnc_homs_hgnc_symb/2 ).
?- bio_db_interface( prolog ).
?- hgnc_homs_hgnc_symb( Hgnc, Symb ).
Hgnc = 1,
Symb = 'A12M1~withdrawn' .
?- bio_db_close(hgnc_homs_hgnc_symb/2).

*/

 1267bio_db_close( Pid ) :-
 1268    bio_db_db_predicate( Pid ),
 1269    !,
 1270    bio_db_close_pred( Pid ).
 1271bio_db_close( Pid ) :-
 1272    throw( not_a_db_pred(Pid), [pack(bio_db),pred(bio_db_close/1)] ).
 1273
 1274bio_db_close_pred( Pid ) :-
 1275    bio_db_handle( Pid, Iface, File, Handle, Mod ),
 1276    !,
 1277    bio_db_close_connection( Iface, Handle ),
 1278    Pid = Pname/Arity,
 1279    functor( Head, Pname, Arity ),
 1280    retractall( Head ),
 1281    atom_concat( Pname, '_info', InfoPname ),
 1282    functor( InfoHead, InfoPname, 2 ),
 1283    retractall( InfoHead ),
 1284    retractall( bio_db_handle(Pid,Iface,File,Handle,Mod) ),
 1285    assert( (Head :- bio_db_serve(Head)) ).
 1286bio_db_close_pred( Pid ) :-
 1287    throw( not_served(Pid), [pack(bio_db),pred(db_close/1)] ),
 1288    fail.
 1289
 1290bio_db_close_connection( prosqlite, Handle ) :-
 1291    sqlite_disconnect( Handle ).
 1292bio_db_close_connection( prolog, _Handle ).
 1293bio_db_close_connection( berkeley, Handle ) :- 
 1294    bdb_close( Handle ).
 1295bio_db_close_connection( rocks, Handle ) :- 
 1296    rocks_close( Handle ).
 bio_db_close_connections
Close all currently open bio_db backend connections.

This is called by bio_db at halt.

*/

 1305bio_db_close_connections:-
 1306    findall( Pid, bio_db:bio_db_handle(Pid,_B,_C,_D,_Mod), Pids ),
 1307    member( Pid, Pids ),
 1308    bio_db_close( Pid ),
 1309    fail.
 1310bio_db_close_connections.
 bio_db_db_predicate(?Pid)
True if Pid is a predicate identifier which is defined in current bio_db session, and contains 4 _ sep tokens, each of length 4. When Pid is a free variable all such predicate identifiers are returned on backtracking.

For a statically produced list of all data predicates in bio_db see, bio_db_data_predicate/4.

  ?- bio_db_db_predicate( hgnc_homs_hgnc_symb/2 ).
  true.

  ?- bio_db_db_predicate( X ).
  X = hgnc_homs_symb_ncbi/2 ;
  X = ense_homs_enst_ensg/2 ;
  ...

*/

 1332bio_db_db_predicate( Pname/Arity) :-
 1333    ground(Pname/Arity), !,
 1334    functor(Head,Pname,Arity),
 1335    bio_db_data_predicate_name(Pname),
 1336    % predicate_property(bio_db:Head, exported), !.
 1337    predicate_property(bio_db:Head, defined), !.  
 1338    % fixme: when called from closing,  maybe do a bit of checking ? \+ (rule=:=1,clauses=:=1)
 1339bio_db_db_predicate( Pname/Arity) :-
 1340    % module_property(bio_db, exports(List)),
 1341    % member(Pname/Arity, List),
 1342    current_predicate( bio_db:Pname/Arity ),
 1343    bio_db_data_predicate_name(Pname).
 1344
 1345bio_db_data_predicate_name( Pname ) :-
 1346     atomic_list_concat( Parts, '_', Pname ),
 1347     maplist( atom_length, Parts, [4,4,4,4] ),
 1348     !.
 1349bio_db_data_predicate_name( _Db, _Parts, Pname, Arity ) :-
 1350    throw( not_a_db_pred(Pname/Arity), [pack(bio_db),pred(bio_db_close/1)] ).
 1351
 1352% map stubs, 
 1353% these are in memory iff the map is to be loaded as prolog 
 1354% and this is the first call to the pred, they get replaced
 1355% by the map data after that.
 1356% 
 1357bio_db_serve( Call ) :-
 1358    functor( Call, Pn, _ ),
 1359    ( atomic_list_concat([_,OrgPredTkn,_,_],'_',Pn) ->
 1360          ( bio_db_organism(OrgPredTkn,OrgTkn,_Org) ->
 1361               true
 1362               ; 
 1363               ( bio_db_organism(_,OrgPredTkn,_) ->
 1364                    OrgTkn = OrgPredTkn
 1365                    ;
 1366                    throw( cannot_get_org_token_for_bio_db_served(Call) )
 1367               )
 1368          )
 1369    ),
 1370    bio_db_serve( OrgTkn, Call, true ).
 1371
 1372bio_db_serve( Org, Call ) :-
 1373    bio_db_serve( Org, Call, true ).
 1374
 1375bio_db_serve( Org, Call, Load ) :-
 1376    bio_db_interface( Iface ),
 1377    bio_db_map_call_db_pname( Call, Db, Pname, Arity ),
 1378    bio_db_serve_pname( Load, true, Org, Db, Pname, Arity, Iface, Call ).
 1379
 1380bio_db_interface_set( Iface ) :-
 1381    bio_db_interface_atom( Iface ),
 1382    !,
 1383    M = 'Setting bio_db_interface prolog_flag, to: ~a',
 1384    debug( bio_db, M, Iface ),
 1385    ( bio_db_interface_initialisation(Iface) -> true; true ),
 1386    set_prolog_flag( bio_db_interface, Iface ).
 1387bio_db_interface_set( Iface ) :-
 1388    findall( Aface, bio_db_interface_atom(Aface), AllFaces ),
 1389    throw( arg_enumerate(1,AllFaces,Iface), [pack(bio_db),pred(bio_db_interface/2)] ).
 1390    
 1391bio_db_interface_extensions( prolog, [pl,''] ).
 1392bio_db_interface_extensions( prosqlite, [sqlite,''] ).
 1393bio_db_interface_extensions( berkeley, [db,''] ).
 1394bio_db_interface_extensions( rocks, [rocks,''] ).
 1395
 1396bio_db_interface_known( Prov, Iface ) :-
 1397    atomic( Prov ),
 1398    bio_db_interface_atom( Prov ),
 1399    !,
 1400    Iface = Prov.
 1401bio_db_interface_known( Prov, Def ) :-
 1402    bio_db_default_interface( Def ),
 1403    M = 'Resetting bogus bio_db_interface prolog_flag, from: ~w, to default: ~a',
 1404    debug( bio_db, M, [Prov,Def] ), % fixme: this is informational rather than debug
 1405    set_prolog_flag( bio_db_interface, Def ).
 1406
 1407% prosqlite here
 1408/*
 1409bio_db_serve_pname( load, Db, Pname, Arity, Call ) :-
 1410    current_prolog_flag( bio_db_interface, prosqlite ),
 1411    !,
 1412    Term =.. [Db,Pname],
 1413    absolute_file_name( Term, Src, [access(Mode),file_type(prolog),file_errors(fail)] ).
 1414    sqlite_connect( phones, phones_db, as_predicates(true) )
 1415    */
 bio_db_serve_pname(+LoadFlag, +Ictive, Org, Db, Pname, Arity, Iface, _Call)
LoadFlag can be one of check, true (for loading) and false for ensuring the db is installed but does not actually hot-swap it in. Ictive is a boolean with true for interactively questioning user whereas false accepts the defaults with no interupptions.

*/

 1425bio_db_serve_pname( check, _Ictive, Org, Db, Pname, _Arity, Iface, _Call ) :-
 1426    !,
 1427    % bio_db_interface_extensions( Iface, Exts ),
 1428    bio_db_interface_extensions( Iface, [Ext|_] ),
 1429    % new implementation, untested:
 1430    bio_db_pname_source( Org, Db, Pname, read, Ext, _Abs ).
 1431    % % bio_db_db_pname_source( Db, Pname, exist, Ext, Abs ),
 1432    % Rel =.. [Db|Pname],
 1433    % absolute_file_name( Rel, Abs, [extensions(Exts),access(exist)] ),
 1434    % exists_file( Abs ),
 1435
 1436bio_db_serve_pname( Load, _Ictive, Org, Db, Pname, Arity, Iface, Call ) :-
 1437    bio_db_interface_extensions( Iface, [Ext|_] ),
 1438    bio_db_pname_source( Org, Db, Pname, read, Ext, File ),
 1439    % bio_db_db_pname_source( Db, Pname, exist, Ext, Load ),
 1440    % user:file_search_path( Db, _DbPath ),
 1441    !,
 1442    bio_db_load_call( Load, Pname, Arity, Iface, File, Call ).
 1443bio_db_serve_pname( Load, Ictive, Org, Db, Pname, Arity, Iface, Call ) :-
 1444    Iface \== prolog,
 1445    bio_db_interface_extensions( prolog, [Ext|_] ),
 1446    bio_db_pname_source( Org, Db, Pname, read, Ext, File ),
 1447    Mess = '~a DB:table ~w:~w is not installed, but the Prolog db exists. Shall it be created from Prolog',
 1448    Args = [Iface,Db,Pname/Arity],
 1449    ui_yes_no( Ictive, Mess, Args, y, Reply ),
 1450    Reply == true,
 1451    % bio_db_serve_pname_from_local( Reply, Db, Pname, Arity, Iface, Load, Call ),
 1452    bio_db_pl_nonpl_interface( Iface, File, NonPlLoad ),
 1453    !,
 1454    % fixme: add logic for deleting prolog interface of downloaded db
 1455    bio_db_load_call( Load, Pname, Arity, Iface, NonPlLoad, Call ).
 1456bio_db_serve_pname( Load, Ictive, Org, Db, Pname, Arity, Iface, Call ) :-
 1457    % bio_db_pname_source( Db, Pname, read, prolog+zip, ZLoad ),
 1458    % bio_db_pname_source( Db, Pname, read, 'pl.zip', ZLoad ),
 1459    bio_db_pname_source( Org, Db, Pname, read, prolog+zip, ZLoad ),
 1460    !,
 1461    file_name_extension( PlLoad, zip, ZLoad ),
 1462    current_prolog_flag( bio_db_pl_from_zip, PlFromZipFlag ),
 1463    ( PlFromZipFlag == user ->
 1464        Mess = '~a DB:table ~w:~w is not installed, but the zipped prolog db exists. Shall it be created from this',
 1465        Args = [Iface,Db,Pname/Arity],
 1466        ui_yes_no( Ictive, Mess, Args, y, Reply )
 1467        ;
 1468        MessFg = '~a DB:table ~w:~w is not installed, but the zipped prolog db exists. Flag bio_db_pl_from_zip says: ~w',
 1469        message_report( MessFg, [Iface,Db,Pname/Arity,PlFromZipFlag], informational ),
 1470        Reply = PlFromZipFlag
 1471    ),
 1472    ( Reply == true ->
 1473        file_directory_name( ZLoad, Dir ),
 1474        archive_extract( ZLoad, Dir, [] ),
 1475        ( Iface \== prolog ->
 1476            bio_db_pl_nonpl_interface( Iface, PlLoad, NonPlLoad ),
 1477            bio_db_reply_delete_file( true, PlLoad )
 1478            ;
 1479            current_prolog_flag(bio_db_del_zip,DelZipFlag),
 1480            ( DelZipFlag == user ->
 1481                ZipDelMess = 'Delete the zip file: ~p',
 1482                ui_yes_no( Ictive, ZipDelMess, [ZLoad], n, ZipDelReply )
 1483                ;
 1484                MessDelFg = 'Zip file will be deleted depending on value of flag bio_db_del_zip, which is: ~w',
 1485                message_report( MessDelFg, [DelZipFlag], informational ),
 1486                ZipDelReply = DelZipFlag
 1487            ),
 1488            bio_db_reply_delete_file( ZipDelReply, ZLoad ),
 1489            NonPlLoad = PlLoad
 1490        ),
 1491        !,
 1492        bio_db_load_call( Load, Pname, Arity, Iface, NonPlLoad, Call )
 1493        ;
 1494        % fixme: do fresh download
 1495        debug( bio_db, 'Downloading fresh zip file for: ~w', Pname/Arity ),
 1496        delete_file( ZLoad ),
 1497        file_directory_name( ZLoad, DataDir ),
 1498        directory_files( DataDir, DataFiles ),
 1499        findall( Delable-FullDel, ( member(Delable,DataFiles), 
 1500                                file_name_extension(Pname,_DelExt,Delable), 
 1501                                directory_file_path(DataDir,Delable,FullDel)
 1502                            ),
 1503                                Delables ),
 1504        maplist( bio_db_conflict_file, Delables ),
 1505        bio_db_serve_pname_reply( true, Ictive, Load, Org, Db, Pname, Arity, Iface, Call )
 1506    ).
 1507% here  fixem: 
 1508% add logic that warns if other interfaces will be 
 1509bio_db_serve_pname( Load, Ictive, Org, Db, Pname, Arity, Iface, Call ) :-
 1510    ( Iface == prolog -> 
 1511        Mess = '~a DB:table ~w:~w is not installed, do you want to download it'
 1512        ;
 1513        Mess = '~a DB:table ~w:~w is not installed, do you want to download the prolog db and then generate this interface'
 1514    ),
 1515    Args = [Iface,Db,Pname/Arity],
 1516    ui_yes_no( Ictive, Mess, Args, y, Reply ),
 1517    bio_db_serve_pname_reply( Reply, Ictive, Load, Org, Db, Pname, Arity, Iface, Call ).
 1518
 1519bio_db_serve_pname_reply( false, _Ictive, _Load, _Org, _Db, _Pname, _Arity, _Iface, _Call ) :-
 1520    abort.
 1521bio_db_serve_pname_reply( true, Ictive, Load, Org, Db, Pname, Arity, Iface, Call ) :-
 1522    stoics( Stoics ),
 1523    Mess = 'Downloading dataset from server: ~w',
 1524    phrase('$messages':translate_message(debug(Mess,[Stoics])), Lines),
 1525    print_message_lines(current_output, kind(informational), Lines),
 1526    atomic_list_concat( [_,_,Comp3|_], '_', Pname ), 
 1527    bio_db_predicate_type_sub_dir( Comp3, Sub ),
 1528    atomic_list_concat( [Stoics,Org,Sub,Db,Pname], '/', StoicsStem ),
 1529    atomic_list_concat( [StoicsStem,pl,zip], '.', StoicsFile ),
 1530    bio_db_pname_source( Org, Db, Pname, none, 'pl.zip', Local ),
 1531    debug( bio_db, 'Trying to get: ~w', url_file(StoicsFile,Local,insecure(true)) ),
 1532    % directory_file_path( LocDir, _, Local ),
 1533    file_directory_name( Local, LocalDir ),
 1534    % here
 1535    bio_db_repo_skeleton_pack,
 1536    make_directory_path( LocalDir ),
 1537    url_file( StoicsFile, Local, insecure(true) ),  % 2024.04.05 you needed latest stoics_lib; fixme: temp
 1538    % fixme: delete the .pl file here if it exists before unpacking ?  % although this is inconsistent with calling logic
 1539    archive_extract( Local, LocalDir, [] ),
 1540    % here( 'Unzip the pl, create the Iface and if not Iface==Prolog, suggest deleting the .pl db' ),
 1541    file_name_extension( LocalPlF, zip, Local ),
 1542    directory_files( LocalDir, LocalFiles ),
 1543    bio_db_interface_extensions( Iface, [Ext|_] ),
 1544    findall( Delable-FullDel, ( member(Delable,LocalFiles), 
 1545                            file_name_extension(Pname,DelExt,Delable), 
 1546                            \+ memberchk(DelExt,['pl.zip',pl,Ext]),
 1547                            directory_file_path(LocalDir,Delable,FullDel)
 1548                            ),
 1549                                Delables ),
 1550    debug( bio_db, 'Candidates for deletion: ~w', [Delables] ),
 1551
 1552    ( \+ exists_file(LocalPlF) -> 
 1553        throw( decompression_didnot_produce(LocalPlF) )
 1554        ; 
 1555        % here: ask to delete .zip file
 1556        ZipDelMess = 'Delete the zip file: ~p',
 1557        ui_yes_no( Ictive, ZipDelMess, [Local], n, ZipDelReply ),
 1558        bio_db_reply_delete_file( ZipDelReply, Local )
 1559    ),
 1560    ( Iface == prolog ->
 1561        NonPlLoad = LocalPlF
 1562        ;
 1563        bio_db_pl_nonpl_interface( Iface, LocalPlF, NonPlLoad ),
 1564        PlDelMess = 'Delete the Prolog file: ~p',
 1565        ui_yes_no( Ictive, PlDelMess, [LocalPlF], y, PlDelReply ),
 1566        bio_db_reply_delete_file( PlDelReply, LocalPlF )
 1567    ),
 1568    maplist( bio_db_conflict_file, Delables ),
 1569    % then( 'go back and make sure you deal with existing other interfaces (delete them)' ),
 1570    !,
 1571    bio_db_load_call( Load, Pname, Arity, Iface, NonPlLoad, Call ).
 1572    % we probably (now need something lighter than:
 1573    % bio_db_serve_pname( load, Db, Pname, Arity, Iface, Call ).
 1574
 1575bio_db_repo_skeleton_pack :-
 1576    absolute_file_name( pack(bio_db), BioDbD, [file_type(directory)] ),
 1577    directory_file_path( PackD, _, BioDbD ),
 1578    directory_file_path( PackD, bio_db_repo, RepoD ),
 1579    directory_file_path( RepoD, 'pack.pl', RepoPackPl ),
 1580    ( exists_file(RepoPackPl) ->
 1581        true
 1582        ;
 1583        make_directory_path( RepoD ),
 1584        ensure_loaded( pack('bio_db/auxil/lib/bio_db_repo_info') ),
 1585        findall( InfTerm, bio_db_repo_info(InfTerm), [InfNm,InfTi|Infs] ),
 1586        date_two_digit_dotted( Dotted ),
 1587        atomic_list_concat( [YrA,MnA,DyA], '.', Dotted ),
 1588        % atomic_list_concat( [Dotted,skeleton], '-', PlPackVers ),
 1589        Clauses = [InfNm,InfTi,version(Dotted)|Infs],
 1590        portray_clauses( Clauses, file(RepoPackPl) ),
 1591        atomic_list_concat( [20,YrA], FullYA ),
 1592        maplist( atom_number, [YrA,FullYA,MnA,DyA], [Yr,FullY,Mn,Dy] ), % the day gets a -skeleton suffix
 1593        atomic_list_concat( [DyA,skeleton], '-', DyPsfx ),
 1594        directory_file_path( RepoD, prolog, RepoPlD ),
 1595        make_directory_path( RepoPlD ),
 1596        directory_file_path( RepoPlD, 'bio_db_repo_version.pl', ModVersF ),
 1597        portray_clauses( [bio_db_repo_version(Yr:Mn:DyPsfx,date(FullY,Mn,Dy))], file(ModVersF) ),
 1598        directory_file_path( BioDbD, 'auxil/lib/bio_db_repo.pl', BioDbRepoPlF ),
 1599        directory_file_path( RepoPlD, 'bio_db_repo.pl', DstRepoF ),
 1600        copy_file( BioDbRepoPlF, DstRepoF )
 1601    ).
 1602
 1603bio_db_conflict_file( Delable-Full ) :-
 1604    Mess = 'Current db file might be inconsistent to new zip file. Delete db file: ~p',
 1605    Ictive = false,
 1606    % fixme: should we be passing Ictive from above ?
 1607    ui_yes_no( Ictive, Mess, [Delable], y, Reply ),
 1608    bio_db_reply_delete_file( Reply, Full ).
 1609
 1610/*
 1611bio_db_serve_pname_from_local( false, _Db, _Pname, Arity,Iface, Load, Call ) :-
 1612    ( bio_db_db_pname_source( Db, Pname, read, prolog+zip, ZLoad ) ->
 1613        fail  % .zip will be tried by caller on failure
 1614        ; 
 1615    ).
 1616    fail.
 1617    */
 1618% fixme: this is not called from anywhere? 
 1619bio_db_serve_pname_from_local( true, _Db, Pname, Arity, Iface, Load, Call ) :-
 1620    % fixme: add predicates for interogating and deleting db/interface pairs
 1621    bio_db_pl_nonpl_interface( Iface, Load, NonPlLoad ),
 1622    % fixme: add logic for deleting prolog interface of downloaded db
 1623    !,
 1624    bio_db_load_call( Pname, Arity, Iface, NonPlLoad, Call ).
 1625
 1626bio_db_pl_nonpl_interface( Iface, Load, NonPlLoad ) :-
 1627    debug( bio_db, 'Converting to interface: ~a, from file: ~p', [Iface,Load] ),
 1628    atom_concat( pl_, Iface, Stem ),
 1629    atom_concat( 'bio_db/auxil/backends/', Stem, Backend ),
 1630    ensure_loaded( pack(Backend) ),
 1631    Conv =.. [Stem,Load],
 1632    call( Conv ),
 1633    file_name_extension( LoadStem, _Pl, Load ),
 1634    bio_db_interface_extensions( Iface, [Ext|_] ),
 1635    file_name_extension( LoadStem, Ext, NonPlLoad ).
 1636
 1637bio_db_ensure_loaded( Iface, Pid, Load, Handle, From ) :-
 1638    atom( Iface ),
 1639    bio_db_ensure_loaded_1( Iface, Pid, Load, Handle, From ),
 1640    !.
 1641bio_db_ensure_loaded( Iface, Pid, Load, _Handle, _From ) :-
 1642    % fixme: Goal in error can be supplied ?
 1643    throw( failed_to_load(Iface,Pid,Load), [pack(bio_db),pred(bio_db_ensure_loaded/4)] ).
 1644
 1645bio_db_ensure_loaded_1( prolog, Pid, Load, [], From ) :-
 1646    Pid = Pname/_Arity,
 1647    atomic_list_concat( [Ppfx|_], '_', Pname ),
 1648    bio_db_pl_load( Ppfx, Pid, Load, From ).
 1649bio_db_ensure_loaded_1( prosqlite, Pname/_Arity, Load, Pname, _From ) :-
 1650    sqlite_connect( Load, Pname, [as_predicates(true),at_module(bio_db)] ).
 1651bio_db_ensure_loaded_1( berkeley, Pname/Arity, Load, Berkeley, _From ) :-
 1652    \+ '$bio_db_handle'(Pname,_),
 1653    % fixme: is the option needed ? we are just reading- check
 1654    % bio_db_info_interface( berkeley, _Pid, Load, _Handle, data_types, data_types(Ktype,Vtype) ),
 1655
 1656    Pairs = [data_types-DtTypes,relation_type-RelType],
 1657    bio_db_info_interface_kvs( berkeley, _Pid, Load, _Handle, Pairs ),
 1658    bio_db_info_interface_types( RelType, DtTypes, berkeley, Dup, _DbTypes, KeyType, ValType ),
 1659    % Open = bdb_open( Load, read, Berkeley, [duplicates(Dupl),key(KeyType),value(ValType)] ),
 1660    Open = bdb_open( Load, read, Berkeley, [dup(Dup),key(KeyType),value(ValType)] ),
 1661    debug( bio_db, 'Bdb opening for reading with: ~w' , Open ),
 1662    call( Open ),
 1663    % bdb_open( Load, read, Berkeley, [duplicates(true),key(KeyType),value(ValType)] ),  % 0.5
 1664    % retractall( '$bio_db_handle'(Pname,_) ),  % fixme: we can do some error reporting if something does exist
 1665    % assert( '$bio_db_handle'(Pname,Berkeley) ),
 1666    % atomic_list_concat( [Ppfx|_], '_', Pname ),
 1667    arg( 1, RelType, Krt ),
 1668    arg( 1, RelType, Vrt ),
 1669    ground( Arity ),
 1670    bio_db_berkeley_predicate_assert_arity( Arity, Krt, Vrt, Pname, bdb_get, bdb_enum, Berkeley ).
 1671bio_db_ensure_loaded_1( rocks, Pname/Arity, Load, Handle, _From ) :-
 1672    /*
 1673    bio_db_info_interface( rocks, _Pid, Load, _Handle, data_types, data_types(Ktype,Vtype) ),
 1674    */
 1675    Pairs = [data_types-DtTypes,relation_type-RelType],
 1676    bio_db_info_interface_kvs( rocks, _Pid, Load, _Handle, Pairs ),
 1677    bio_db_info_interface_types( RelType, DtTypes, rocks, Dup, _DbTypes, KeyType, ValType ),
 1678    % maplist( bio_db_info_rocks_singleton_type, [Ktype,Vtype], [Kbype,Vbype] ),
 1679    % ( Dup == false -> KeyType = NoDupKeyType; NoDupKeyType = term ),
 1680    % 2nd take, duplicates are now stored as lists of values
 1681    ( Dup == false -> ValType = DupValType; DupValType = term ),
 1682    Open = rocks_open( Load, Handle, [key(KeyType),value(DupValType)] ),
 1683    debug( bio_db, 'Rocks opening for reading with: ~w' , Open ),
 1684    call( Open ),
 1685
 1686    % atomic_list_concat( [Ppfx|_], '_', Pname ),
 1687    bio_db_rocks_predicate_assert_arity( Arity, Dup, Pname, rocks_get, rocks_enum, Handle ).
 1688    % bio_db_rocks_predicate_assert_arity( Kbype/Vbype, Arity, Pname, rocks_get, rocks_enum, Handle ).
 1689
 1690% bio_db_pl_load( map, Pid, Load, From ).
 1691bio_db_pl_load( _Type, Pid, Load, Mod ) :-
 1692    dynamic( Mod:Pid ),  % fixme: we should be able to remove this? 
 1693    % ensure_loaded( Load ).  % following is an elaboration of code by JW: 16.11.13:
 1694    (   (file_name_extension(Base,pl,Load), \+ current_prolog_flag(bio_db_qcompile,false))
 1695    ->  Mod:load_files( Base, [qcompile(auto),if(not_loaded)] )
 1696    ;   ensure_loaded( Mod:Load )  % fixme: use load_files/2 ?
 1697    ).
 1698
 1699% bio_db_pl_load( edge, Pname/_Arity, Load ) :-
 1700/*
 1701bio_db_pl_load( edge, Pid, Load ) :-
 1702    % os_postfix ... :(
 1703    % % file_name_extension( Base, Ext, Load ),
 1704    % % atomic_list_concat( [Base,ord], '_', OrdBase ),
 1705    % % file_name_extension( OrdBase, Ext, OrdLoad ),
 1706    % % ensure_loaded( OrdLoad ),
 1707    ensure_loaded( Load ),
 1708    % % atomic_list_concat( [Pname,ord], '_', Pord ),
 1709    % % Head =.. [Pname,X,Y,W],
 1710    % % GoalF =.. [Pord,X,Y,W],
 1711    % % GoalB =.. [Pord,Y,X,W],
 1712    % % consult_clause( (Head:-(GoalF;GoalB)) ).
 1713    true.
 1714    */
 1715
 1716    /*
 1717bio_db_kv_db_predicate_assert( _, Pname, Krt, Vrt, Arity, Get, Enum, Handle ) :-
 1718    ground( Arity ),
 1719    bio_db_kv_db_predicate_assert_arity( Arity, Krt, Vrt, Pname, Get, Enum, Handle ).
 1720bio_db_kv_db_predicate_assert( edge, Pname, Arity, Get, Enum, Handle ) :-
 1721    bio_db_kv_db_predicate_assert_edge( Arity, Pname, Get, Enum, Handle ).
 1722    */
 1723
 1724bio_db_berkeley_predicate_assert_arity( 2, 1, 1,  Pname, Get, Enum, Handle ) :-
 1725    !, % maybe this relevat to other modes too  (here mode is 2,1,1
 1726    Head =.. [Pname,Key,Value],
 1727    GetG  =.. [  Get, Handle, Key, Value ],
 1728    EnumG =.. [ Enum, Handle, Key, Value ],
 1729    Conditional =  ( ( ground(Key) -> 
 1730                    GetG
 1731                    ;
 1732                    EnumG
 1733                  )
 1734            ),
 1735    consult_clause( (Head:-(Conditional)) ).
 1736
 1737bio_db_berkeley_predicate_assert_arity( N, _, _,  Pname, Get, Enum, Handle ) :-
 1738    functor( Head, Pname, N ),
 1739    Head =.. [Pname,Key|Args],
 1740    GetG  =.. [  Get, Handle, Key, Value ],
 1741    EnumG =.. [ Enum, Handle, Key, Value ],
 1742    Conditional =  ( ( ground(Key) -> 
 1743                    GetG
 1744                    ;
 1745                    EnumG
 1746                  )
 1747            ),
 1748    Unravel = bio_db_kv_db_value( Args, Value ),
 1749    consult_clause( (Head:-(Conditional,Unravel)) ).
 1750
 1751bio_db_rocks_predicate_assert_arity( 2, false, Pname, Get, Enum, Handle ) :-
 1752    !, % maybe this relevat to other modes too  (here mode is 2, false (=no duplicates)
 1753    Head =.. [Pname,Key,Value],
 1754    GetG  =.. [  Get, Handle, Key, Value ],
 1755    EnumG =.. [ Enum, Handle, Key, Value ],
 1756    Conditional =  ( ( ground(Key) -> 
 1757                    GetG
 1758                    ;
 1759                    EnumG
 1760                  )
 1761            ),
 1762    consult_clause( (Head:-(Conditional)) ).
 1763bio_db_rocks_predicate_assert_arity( N, false, Pname, Get, Enum, Handle ) :-
 1764    N > 2,
 1765    functor( Head, Pname, N ),
 1766    Head =.. [Pname,Key|Args],
 1767    GetG  =.. [  Get, Handle, Key, Value ],
 1768    EnumG =.. [ Enum, Handle, Key, Value ],
 1769    Conditional =  ( ( ground(Key) -> 
 1770                    GetG
 1771                    ;
 1772                    EnumG
 1773                  )
 1774            ),
 1775    Unravel = bio_db_kv_db_value( Args, Value ),
 1776    consult_clause( (Head:-(Conditional,Unravel)) ).
 1777bio_db_rocks_predicate_assert_arity( 2, true, Pname, Get, Enum, Handle ) :-
 1778    !, % maybe this relevat to other modes too  (here mode is 2, false (=no duplicates)
 1779    Head =.. [Pname,Key,Value],
 1780    GetG  =.. [  Get, Handle, Key, Values ],
 1781    EnumG =.. [ Enum, Handle, Key, Values ],
 1782    Conditional =  ( ( ground(Key) -> 
 1783                    (GetG, bio_db_rocks_multi_key_value(Values,Value) )
 1784                    ;
 1785                    (EnumG, bio_db_rocks_multi_key_value(Values,Value) )
 1786                  )
 1787            ),
 1788    consult_clause( (Head:-(Conditional)) ).
 1789bio_db_rocks_predicate_assert_arity( Arity, true, Pname, Get, Enum, Handle ) :-
 1790    Arity > 2,
 1791    functor( Head, Pname, Arity ),
 1792    Head =.. [Pname,Key|Args],
 1793    GetG  =.. [  Get, Handle, Key, ValueTerm ],
 1794    EnumG =.. [ Enum, Handle, Key, ValueTerm ],
 1795    % EnuTG =.. [ Enum, Handle, Key:_X, Value ],
 1796    Conditional =  ( ( ground(Key) -> 
 1797                    ( GetG, bio_db_rocks_multi_key_value(ValueTerm,Value) )
 1798                    ;
 1799                    ( EnumG, bio_db_rocks_multi_key_value(ValueTerm,Value) )
 1800                    % ( EnumG , ( (atomic(ProvKey),ProvKey=Key);ProvKey=Key:_) )
 1801                  )
 1802                ),
 1803    Unravel = bio_db_kv_db_value( Args, Value ),
 1804    consult_clause( (Head:-(Conditional,Unravel)) ).
 1805    
 1806
 1807bio_db_rocks_multi_key_value( [H|T], Value ) :-
 1808    !,
 1809    ( Value = H; member( Value, T ) ).
 1810bio_db_rocks_multi_key_value( Value, Value ).
 1811
 1812bio_db_kv_db_value( [H], Value ) :- !, Value = H.
 1813bio_db_kv_db_value( [H|T], H+Value ) :-
 1814    bio_db_kv_db_value( T, Value ).
 1815consult_clause( Clause ) :-
 1816    assert( Clause ).
 1817
 1818/*
 1819consult_clause( Clause ) :-
 1820    tmp_file_stream(text, File, Stream),
 1821    portray_clause( Stream, Clause ),
 1822    close( Stream ),
 1823    debug( bio_db, 'Consulting from: ~p', File ),
 1824    consult( File ),
 1825    true.
 1826*/
 1827
 1828bio_db_interfaces_ext( A+B, Ext ) :-
 1829    !,
 1830    bio_db_interfaces_ext( A, AExt ),
 1831    bio_db_interfaces_ext( B, BExt ),
 1832    atomic_list_concat( [AExt,BExt], '.', Ext ).
 1833bio_db_interfaces_ext( Iface, Ext ) :-
 1834    bio_db_interface_extensions( Iface, [Ext|_] ),
 1835    !.
 1836bio_db_interfaces_ext( Ext, Ext ).
 1837
 1838bio_db_pname_source( _Org, Db, Pname, Mode, DbFaces, Src ) :-
 1839    % fixme: make it play with Org ?
 1840    bio_db_interfaces_ext( DbFaces, Ext ),
 1841    Term =.. [Db,Pname],
 1842    debug( bio_db, 'Trying DB location: ~p, mode: ~w', [Term,Mode] ),
 1843    ( absolute_file_name( Term, Src, [access(Mode),extensions([Ext]),file_errors(fail)] )
 1844      ;
 1845      (  DbFaces==rocks,
 1846         file_name_extension(Pname,rocks,Rname),
 1847        Rerm =.. [Db,Rname],
 1848        absolute_file_name(Rerm,Src,[access(Mode),file_errors(fail),file_type(directory)])
 1849      )
 1850    ),
 1851    !.
 1852% The above is a short-cut this is the long way.
 1853% Works when single db provides both maps and graphs
 1854%
 1855bio_db_pname_source( Org, Db, Pname, Mode, DbFaces, Src ) :-
 1856    bio_db_interfaces_ext( DbFaces, Ext ),
 1857    % Term =.. [Db,Pname],
 1858    bio_db_pred_name_type( Pname, Type ),
 1859    directory_file_path( Org, Type, Rel ),
 1860    % Term =.. [bio_db_data,Type], % pre Org times
 1861    Term =.. [bio_db_data,Rel],
 1862    absolute_file_name( Term, Dir ),
 1863    file_name_extension( Pname, Ext, Bname ),
 1864    directory_file_path( Dir, Db, DbDir ),
 1865    directory_file_path( DbDir, Bname, Src ),
 1866    debug( bio_db, 'Trying DB location: ~p, mode: ~w', [Src,Mode] ), % fixme: debug_call, with success/failure
 1867    ( absolute_file_name( Src, _, [access(Mode),file_errors(fail)])
 1868       ;
 1869      (  DbFaces==rocks,
 1870        absolute_file_name( Src, _, [access(Mode),file_errors(fail),file_type(directory)] )
 1871      )
 1872    ),
 1873    !.
 1874    % absolute_file_name( Pname, Src, [access(Mode),extensions([Ext]),file_errors(fail)] ).
 bio_db_source_info(+File, -InfoF)
Generate Info filename corresponding to the database filename at File.

*/

 1881bio_db_source_info( File, InfoF ) :-
 1882    file_name_extension( Stem, Ext, File ),
 1883    atom_concat( Stem, '_info', InfoStem ),
 1884    file_name_extension( InfoStem, Ext, InfoF ).
 bio_db_predicate_info(+PidOrPname, -InfoName)
Generate the information predicate name of a Pid or of Db predicate name.

*/

 1891bio_db_predicate_info( Pname/_Arity, InfoName ) :-
 1892    !,
 1893    atom_concat( Pname, '_info', InfoName ).
 1894bio_db_predicate_info( Pname, InfoName ) :-
 1895    atom( Pname ),
 1896    atom_concat( Pname, '_info', InfoName ).
 1897
 1898bio_db_pred_name_type( Pname, Type ) :-
 1899    atomic_list_concat( [_,_,Trd|_], '_', Pname ),
 1900    bio_db_pred_name_prefix_type( Trd, Type ).
 1901
 1902bio_db_pred_name_prefix_type( edge, graphs ) :- !.
 1903bio_db_pred_name_prefix_type( _, maps ).
 1904
 1905bio_db_load_call( false, Pname, Arity, Iface, File, _Call ) :-
 1906    ( Iface == prolog -> 
 1907        % ensure .qlf is created
 1908        file_name_extension( Stem, pl, File ),
 1909        Mess = 'Ensuring .qlf is also installed: ~w',
 1910        phrase('$messages':translate_message(debug(Mess,[Pname/Arity])), Lines),
 1911        print_message_lines(current_output, kind(informational), Lines),
 1912        load_files( scratch:Stem, [qcompile(auto),if(true)] ),
 1913        abolish( scratch:Pname/Arity )
 1914        ;
 1915        true
 1916    ).
 1917bio_db_load_call( true, Pname, Arity, Iface, File, Call ) :-
 1918    debug( bio_db, 'Loading pred: ~w, interface: ~a, file: ~w', [Pname/Arity,Iface,File] ),
 1919    ground( Iface ),
 1920    functor( Phead, Pname, Arity ),
 1921    ( predicate_property(Phead,imported_from(From) ) -> true; From = bio_db ),
 1922    abolish( From:Pname/Arity ),    % fixme: retractall/1 if we have problem with regenerations ?
 1923    % retractall(Phead),
 1924    atom_concat( Pname, '_info', InfoPname ),
 1925    dynamic( From:InfoPname/2 ),
 1926    % functor( Ihead, InfoPname, 2 ),
 1927    ( (From \== bio_db,\+ current_predicate(bio_db:InfoPname/2)) -> 
 1928            % fixme: test again:
 1929            From:export(InfoPname/2),
 1930            bio_db:import(From:InfoPname/2)
 1931            ;
 1932            true
 1933    ),
 1934    functor( InfoHead, InfoPname, 2),
 1935    retractall( From:InfoHead ),
 1936    bio_db_ensure_loaded( Iface, Pname/Arity, File, Handle, From ),
 1937    assert( bio_db_handle(Pname/Arity,Iface,File,Handle,From) ),
 1938    call( Call ).
 1939
 1940bio_db_predicate_type_sub_dir( edge, graphs ) :- !.
 1941bio_db_predicate_type_sub_dir( _, maps ).
 1942
 1943bio_db_map_call_db_pname( Call, Db, Pname, Arity ) :-
 1944    functor( Call, Pname, Arity ),
 1945    at_con( [Db|Parts], '_', Pname ),
 1946    bio_db_map_call_db_pname_check( Db, Parts, Pname, Arity ).
 1947    % bio_db_type_arity_check( Type, Arity ).
 1948
 1949bio_db_map_call_db_pname_check( Db, Parts, _Pname, _Arity ) :-
 1950     maplist( atom_length, [Db|Parts], [4,4,4,4] ),
 1951     !.
 1952bio_db_map_call_db_pname_check( _Db, _Parts, Pname, Arity ) :-
 1953    throw( not_a_db_pred(Pname/Arity), [pack(bio_db),pred(bio_db_serve/3)] ).
 1954
 1955% fixme: delete these 2 preds
 1956bio_db_type_arity_check( Type, Arity ) :-
 1957    bio_db_type_arity_known( Type, Arity ),
 1958    !.
 1959bio_db_type_arity_check( Type, Arity ) :-
 1960    throw( unknown_combination_of_type_arity(Type,Arity) ).
 1961
 1962% fixme: this now a bit outdated... maybe add name for special cases ?
 1963bio_db_type_arity_known( map, 2 ).
 1964bio_db_type_arity_known( map, 3 ).
 1965bio_db_type_arity_known( map, 4 ).
 1966bio_db_type_arity_known( map, 5 ).
 1967bio_db_type_arity_known( map, 7 ).
 1968bio_db_type_arity_known( edge, 3 ).
 1969bio_db_type_arity_known( edge, 2 ).
 1970
 1971bio_db_reply_delete_file( true, Local ) :-
 1972    debug( bio_db, 'Deleting file: ~p', Local ),
 1973    delete_file( Local ).
 1974bio_db_reply_delete_file( false, Local ) :-
 1975    debug( bio_db, 'NOT deleting file: ~p', Local ).
 1976
 1977/*
 1978bio_db_info_db_types( berkeley, RelType, DataTypes, Dup, DbTypes, KeyType, ValType ) :-
 1979    bio_db_info_berkeley_types( RelType, DataTypes, Dup, DbTypes, KeyType, ValType ).
 1980bio_db_info_db_types( rocks, RelType, DataTypes, Dup, DbTypes, KeyType, ValType ) :-
 1981    % bio_db_info_rocks_types( RelType, DataTypes, Dup, DbTypes, KeyType, ValType ).
 1982    bio_db_info_rocks_types( RelType, DataTypes, Dup, DbTypes, KeyType, ValType ).
 1983
 1984bio_db_info_rocks_types( relation_type(1,1), DataTypes, Dup, DbTypes, KeyType, ValType ) :- 
 1985    DataTypes =.. [data_types,PlKeyType,PlValsTypes],
 1986    bio_db_info_rocks_type( PlKeyType, KeyType ),
 1987    bio_db_info_rocks_type( PlValsTypes, ValType ),
 1988    DbTypes = [key(KeyType),value(ValType)].
 1989    */
 1990% fixme: change all the calls and remove this
 1991bio_db_info_db_types( Iface, RelType, DataTypes, Dup, DbTypes, KeyType, ValType ) :-
 1992    bio_db_info_interface_types( RelType, DataTypes, Iface, Dup, DbTypes, KeyType, ValType ).
 1993
 1994% bio_db_info_berkeley_types( relation_type(1,MR), data_types(Kt,Vt), Dup, DbTypes, KeyType, ValType ) :-   
 1995bio_db_info_interface_types( relation_type(1,MR), data_types(Kt,Vt), Iface, Dup, DbTypes, KeyType, ValType ) :- 
 1996    ( MR =:= 1 -> Dup = false; Dup = true ),
 1997    !,  % Arity = 2 (from the form of data_types...
 1998    bio_db_info_interface_type( Kt, Iface, KeyType ),
 1999    bio_db_info_interface_type( Vt, Iface, ValType ),
 2000    DbTypes = [key(KeyType),value(ValType)].
 2001bio_db_info_interface_types( relation_type(1,MR), DtTypes, Iface, Dup, DbTypes, KeyType, ValType ) :-   
 2002    ( MR =:= 1 -> Dup = false; Dup = true ),
 2003    !,  % Arity = 2 (from the form of data_types...
 2004    functor( DtTypes, _, Arity ),
 2005    Arity > 2,
 2006    !,
 2007    arg( 1, DtTypes, Kt ),
 2008    bio_db_info_interface_type( Kt, Iface, KeyType ),
 2009    ValType = term,
 2010    DbTypes = [key(KeyType),value(term)].
 2011bio_db_info_interface_types( RelType, DtTypes, Iface, Dup, DbTypes, KeyType, ValType ) :-
 2012    ( RelType = relation_type(1,1) -> Dup = false; Dup = true ),
 2013    arg( 1, DtTypes, Kt ),
 2014    functor( DtTypes, _, Arity ),
 2015    ( Arity > 2 -> ValType = term
 2016                ; 
 2017
 2018                arg( 2, DtTypes, Vt ),
 2019                    bio_db_info_interface_type( Vt, Iface, ValType )
 2020    ),
 2021    bio_db_info_interface_type( Kt, Iface, KeyType ),
 2022    DbTypes = [key(KeyType),value(term)].
 2023
 2024bio_db_info_interface_type( [Singleton], Iface, Type ) :-  !,
 2025    bio_db_info_interface_unit_type( Iface, Singleton, Type ).
 2026bio_db_info_interface_type( [_,_|_], _Iface, term ) :- !.  % a bit of a shortcut
 2027bio_db_info_interface_type( Singleton, Iface, Type ) :-
 2028    bio_db_info_interface_unit_type( Iface, Singleton, Type ).
 2029
 2030bio_db_info_interface_unit_type( berkeley, Unit, Type ) :-
 2031    bio_db_berkeley_type( Unit, Type ).
 2032bio_db_info_interface_unit_type( rocks, Unit, Type ) :-
 2033    bio_db_rocks_type( Unit, Type ).
 2034
 2035bio_db_rocks_type( term, term ).
 2036bio_db_rocks_type( atom, atom ).
 2037bio_db_rocks_type( integer, int64 ). % rocks also has int32
 2038bio_db_rocks_type( number, atom ).  % rocks has doubles and floats
 2039
 2040bio_db_berkeley_type( term, term ).
 2041bio_db_berkeley_type( atom, atom ).
 2042bio_db_berkeley_type( integer, c_long ).
 2043bio_db_berkeley_type( number, atom ).
 2044
 2045% this is a mock implementation see library(os) or library(os_) 
 2046% for the real one
 2047os_path_( Dir, File, Path ) :-
 2048    ground( Dir ),
 2049    ground( File ),
 2050    !,
 2051    directory_file_path( Dir, File, Path ).
 2052os_path_1( Dir, File, Path ) :-
 2053    ground( Path ),
 2054    directory_file_path( DirSl, File, Path ),
 2055    atom_concat( Dir, '/', DirSl ).
 2056    
 2057pack_errors:message( close_to_info(Pid) ) -->
 2058    ['Predicate: ~w, is not currently served, info depend on the opening interface.'-[Pid]].
 2059pack_errors:message( not_a_db_pred(Pid) ) -->
 2060    ['Predicate identifier: ~w, not of a db predicate.'-[Pid]].
 2061pack_errors:message( not_served(Pid) ) -->
 2062    ['Predicate: ~w, is not currently served.'-[Pid]].
 2063pack_errors:message( failed_to_load(Iface,Pid,File) ) -->
 2064    ['Failed to load predicate: ~w, for backend: ~w, from file: ~p.'-[Pid,Iface,File]].
 2065
 2066% add at_halt, close databases particularly berkeley ones
 2067:- at_halt( bio_db_close_connections ). 2068:- initialization( bio_db_paths, after_load ). 2069
 2070:- multifile sandbox:safe_primitive/1. 2071
 2072bio_sandbox_clause(sandbox:safe_primitive(bio_db:Head)) :-
 2073    module_property(bio_db, exports(PIList)),
 2074    member(Name/Arity, PIList),
 2075    (   sub_atom(Name, 0, _, _, edge_)
 2076    ;   sub_atom(Name, 0, _, _, map_)
 2077    ),
 2078    functor(Head, Name, Arity).
 2079
 2080term_expansion(bio_db_interface, Clauses) :-
 2081    findall(Clause, bio_sandbox_clause(Clause), Clauses).
 2082
 2083bio_db_interface.
 2084sandbox:safe_primitive(bio_db:bio_db_info(_,_,_)).
 2085sandbox:safe_primitive(bio_db:bio_db_info(_,_,_,_))