dbay
Version:
In-Process, In-Memory & File-Based Relational Data Processing with SQLite, BetterSQLite3
226 lines (209 loc) • 9.82 kB
text/coffeescript
'use strict'
############################################################################################################
GUY = require 'guy'
{ alert
debug
help
info
plain
praise
urge
warn
whisper } = GUY.trm.get_loggers 'DBAY'
{ rpr
inspect
echo
log } = GUY.trm
#...........................................................................................................
PATH = require 'path'
FS = require 'fs'
types = require './types'
guy = require 'guy'
new_bsqlt3_connection = require 'better-sqlite3'
#...........................................................................................................
E = require './errors'
H = require './helpers'
{ SQL } = H
{ sql } = require './sql'
{ DBay_query } = require './query-mixin'
{ DBay_ctx } = require './ctx-mixin'
{ DBay_openclose } = require './open-close-mixin'
{ DBay_stdlib } = require './stdlib-mixin'
{ DBay_sqlgen } = require './sqlgen-mixin'
{ Random } = require './random'
{ DBay_udf } = require './udf-mixin'
{ DBay_sqlx } = require 'dbay-sql-macros'
GUY_LEGACY = require 'guy-legacy'
#===========================================================================================================
class DBay extends \
DBay_query \
DBay_ctx \
DBay_openclose \
DBay_stdlib \
DBay_sqlgen \
DBay_udf \
Function
#---------------------------------------------------------------------------------------------------------
@C: guy.lft.freeze
autolocation: H.autolocation
symbols:
execute: Symbol 'execute'
defaults:
#.....................................................................................................
constructor_cfg:
# _temp_prefix: '_dba_temp_'
readonly: false
create: true
timeout: 5000
#...................................................................................................
overwrite: false
path: null
random_seed: null
random_delta: null
#...................................................................................................
macros: false
journal_mode: 'wal'
# journal_mode: 'delete'
# create_stdlib: true
#.....................................................................................................
dbay_with_transaction_cfg:
mode: 'deferred'
#.....................................................................................................
dba_open_cfg:
schema: null
path: null
# overwrite: false
# create: true
#.....................................................................................................
dbay_create_function_cfg:
deterministic: true
varargs: false
directOnly: false
#.....................................................................................................
dbay_create_aggregate_function_cfg:
deterministic: true
varargs: false
directOnly: false
start: null
#.....................................................................................................
dbay_create_window_function_cfg:
deterministic: true
varargs: false
directOnly: false
start: null
#.....................................................................................................
dbay_create_table_function_cfg:
deterministic: true
varargs: false
directOnly: false
#.....................................................................................................
dbay_create_virtual_table_cfg: {}
#.....................................................................................................
dbay_create_insert_cfg:
schema: 'main'
into: null
fields: null
exclude: null
returning: null
#.....................................................................................................
dbay_execute_file_cfg:
path: null
encoding: 'utf-8'
#.....................................................................................................
dba_dt_now_cfg:
subtract: null
add: null
#---------------------------------------------------------------------------------------------------------
@cast_sqlt_cfg: ( me ) ->
### Produce a configuration object for `better-sqlite3` from `me.cfg`. ###
R = guy.props.pluck_with_fallback me.cfg, null, 'readonly', 'timeout'
R.fileMustExist = not me.cfg.create; delete me.cfg.create
return R
#---------------------------------------------------------------------------------------------------------
@cast_constructor_cfg: ( me, cfg = null ) ->
clasz = me.constructor
R = cfg ? me.cfg
#.......................................................................................................
if R.path?
R.temporary ?= false
R.path = PATH.resolve R.path
else
R.temporary ?= true
filename = me.rnd.get_random_filename()
R.path = PATH.resolve PATH.join clasz.C.autolocation, filename
R = guy.props.omit_nullish R ### TAINT should not be needed ###
R = { @C.defaults.constructor_cfg..., R..., }
return R
#---------------------------------------------------------------------------------------------------------
@declare_types: ( me ) ->
### called from constructor via `guy.cfg.configure_with_types()` ###
me.cfg = @cast_constructor_cfg me
me.sqlt_cfg = @cast_sqlt_cfg me
me.cfg = guy.lft.freeze guy.props.omit_nullish me.cfg
me.sqlt_cfg = guy.lft.freeze guy.props.omit_nullish me.sqlt_cfg
me.types.validate.constructor_cfg me.cfg
return null
#---------------------------------------------------------------------------------------------------------
constructor: ( cfg ) ->
super '...P', 'return this._me.do(...P)'
@_me = @bind @
@_me.state = guy.lft.freeze {}
guy.props.hide @_me, 'SQL', SQL
guy.props.hide @_me, 'sql', sql
guy.props.hide @_me, 'rnd', new Random { seed: cfg?.random_seed ? null, delta: cfg?.random_delta ? null, }
@_$query_initialize?()
@_$ctx_initialize?()
@_$openclose_initialize?()
@_$stdlib_initialize?()
@_$sqlgen_initialize?()
@_$udf_initialize?()
@_$trash_initialize?()
GUY_LEGACY.cfg.configure_with_types @_me, cfg, types
#.......................................................................................................
guy.props.hide @_me, '_dbs', {}
guy.props.hide @_me, 'E', E
@_me._register_schema 'main', @_me.cfg.path, @_me.cfg.temporary
unless @constructor._skip_sqlt
guy.props.hide @_me, 'sqlt1', @_me._new_bsqlt3_connection()
@set_journal_mode.call @_me, @_me.cfg.journal_mode
guy.props.hide @_me, 'macros', new DBay_sqlx()
@_compile_sql?()
### make `alt` an on-demand clone of present instance: ###
guy.props.def_oneoff @_me, 'alt', { enumerable: false, }, => new @constructor @_me.cfg
# @create_stdlib() if @_me.cfg.create_stdlib
# @_create_sql_functions()
# @_create_db_structure()
guy.process.on_exit => @_me.destroy()
return @_me
#---------------------------------------------------------------------------------------------------------
_new_bsqlt3_connection: ->
return new_bsqlt3_connection @cfg.path, @sqlt_cfg
#---------------------------------------------------------------------------------------------------------
_register_schema: ( schema, path, temporary ) ->
### Register a schema and descriptional properties, especially whether DB file is to be removed on
process exit. ###
@_dbs[ schema ] = { path, temporary, }
return null
#=========================================================================================================
# CLEANUP ON DEMAND, ON PROCESS EXIT
#---------------------------------------------------------------------------------------------------------
destroy: ->
### To be called on progress exit or explicitly by client code. Removes all DB files marked 'temporary'
in `@_dbs`. ###
try @sqlt1?.close() catch error then warn '^dbay/main@1^', error.message
for schema, d of @_dbs
continue unless d.temporary
H.unlink_file d.path
### NOTE for purpose of these temporary files, see https://www.sqlite.org/tempfiles.html ###
H.unlink_file "#{d.path}-shm"
H.unlink_file "#{d.path}-wal"
H.unlink_file "#{d.path}-journal"
return null
############################################################################################################
### This function is meant to be used to explicitly mark up SQL literals as in
constructs like `for row from db SQL"select * from ..."`. The markup can help text editors to provided
syntax hiliting and other language-specific features for embedded SQL strings. ###
guy.props.hide DBay, 'SQL', SQL
guy.props.hide DBay, 'sql', sql
guy.props.hide DBay, 'new_bsqlt3_connection', new_bsqlt3_connection
module.exports = { DBay, SQL, sql, }