<commit_before>class PLX
  (@conn) ->
    @eval = @plv8x-eval
    @ap = @plv8x-apply

  bootstrap: (...args) ->
    require \./bootstrap .apply @, args

  end: -> @conn.end!

  query: (...args) ->
    cb = args.pop!
    err, {rows}? <- @conn.query ...args
    throw err if err
    cb? rows

  plv8x-eval: (code, cb) ->
    code = "(#code)()" if typeof code is \function
    @query "select plv8x.eval($1) as ret", [code], -> cb JSON.parse it?0?ret

  plv8x-apply: (code, args, cb) ->
    code = "(#code)()" if typeof code is \function
    args = JSON.stringify args if typeof args isnt \string
    @query "select plv8x.apply($1, $2) as ret", [code, args], -> cb JSON.parse it?0?ret

  list: (cb) ->
    @query "select name, length(code) as length from plv8x.code", cb

  purge: (cb) ->
    @query "delete from plv8x.code", cb

  delete-bundle: (name, cb) ->
    @query "delete from plv8x.code where name = $1" [name], -> cb it.rows

  _bundle: (name, manifest, cb) ->
    require! <[one tmp path fs]>
    exclude = <[one pg plv8x]>
    err, tmpfile <~ tmp.tmpName

    # XXX one 2.0.8 bug: absolute manifest doesn't work
    o = one path.relative process.cwd!, manifest
      .exclude ...exclude
      .name name
      .quiet!

    # XXX some way of injecting node core modules later
    if name is \sequelize
      o.dependency \util \* .dependency \events \*
    err <- o.save tmpfile

    throw err if err
    bundle = fs.readFileSync tmpfile, \utf-8

    cb bundle

  import-bundle: (name, manifest, cb) ->
    bundle_from = (name, m, cb) ~>
      if m is /\.js$/
        cb (require \fs .readFileSync m, \utf8)
      else
        @_bundle name, m, cb
    code <~ bundle_from name, manifest
    rows <~ @query "select name from plv8x.code where name = $1" [name]
    [q, bind] = if rows.length # udpate
      ["update plv8x.code set code = $2 where name = $1" [name, code]]
    else
      ["insert into plv8x.code (name, code) values($1, $2)" [name, code]]
    @query q, bind, cb

  mk-user-func: (spec, source, cb) ->
    [_, rettype, name, args] = spec.match /^([\.\w]+)?\s*(\w+)\((.*)\)$/ or throw "failed to parse #spec"

    param-obj = {}
    for arg, idx in args.split /\s*,\s*/
      [_, type, param-name] = arg.match /^([\.\w]+)\s*(\w+)?$/ or throw "failed to parse param #arg"
      param-name ?= "__#{idx}"
      param-obj[param-name] = type

    [_, pkg, expression] = source.match /^(\w*):(.*)$/ or throw "failed to parse source #source"

    body = if pkg
      plv8x-lift pkg, expression
      boot = true
    else
      xpression-to-body expression
    <~ @query _mk_func name, param-obj, rettype, body, {boot}

    cb { rettype, name, param-obj, body }


<[ bootstrap plv8xEval importBundle list purge deleteBundle mkUserFunc ]>.for-each !(key) ~>
    exports[key] = (conn, ...rest) ->
      console.error 'deprecated api, use PLX instead'
      plx = new PLX conn
      plx[key] ...rest

exports.new = (db, cb) ->
  db = "tcp://localhost/#db" if db.indexOf '/' < 0
  conn = connect db
  plx = new PLX conn
  <- plx.bootstrap
  <- plx.query 'select plv8x.boot()'
  <- plx.import-bundle \plv8x require.resolve \../package.json
  cb? plx

export function connect(db)
  require! pg
  new pg.Client db
    ..connect!

export function xpression-to-body(code)
  cls = if plv8? then plv8x.compile-livescript else compile-livescript
  ccoffee = if plv8? then plv8x.compile-coffeescript else compile-coffeescript
  match code
  | /^\s*->/     => cls code
  | /^\s*~>/     => cls code.replace /~>/ \->
  | /^\s*\=\>/   => ccoffee code.replace /\=\>/ \->
  | /^function/  => "(#code)"
  | /^\s*@/      => cls "-> #code"
  | /\breturn[(\s]/ => "(function(){#code})"
  | otherwise       => "(function(){return #code})"

export function compile-livescript(expression)
  require \LiveScript .compile expression, {+bare} .replace /;$/, ''

export function compile-coffeescript(expression)
  cs = require \CoffeeScript<commit_msg>fix bizzare precedence<commit_after>class PLX
  (@conn) ->
    @eval = @plv8x-eval
    @ap = @plv8x-apply

  bootstrap: (...args) ->
    require \./bootstrap .apply @, args

  end: -> @conn.end!

  query: (...args) ->
    cb = args.pop!
    err, {rows}? <- @conn.query ...args
    throw err if err
    cb? rows

  plv8x-eval: (code, cb) ->
    code = "(#code)()" if typeof code is \function
    @query "select plv8x.eval($1) as ret", [code], -> cb JSON.parse it?0?ret

  plv8x-apply: (code, args, cb) ->
    code = "(#code)()" if typeof code is \function
    args = JSON.stringify args if typeof args isnt \string
    @query "select plv8x.apply($1, $2) as ret", [code, args], -> cb JSON.parse it?0?ret

  list: (cb) ->
    @query "select name, length(code) as length from plv8x.code", cb

  purge: (cb) ->
    @query "delete from plv8x.code", cb

  delete-bundle: (name, cb) ->
    @query "delete from plv8x.code where name = $1" [name], -> cb it.rows

  _bundle: (name, manifest, cb) ->
    require! <[one tmp path fs]>
    exclude = <[one pg plv8x]>
    err, tmpfile <~ tmp.tmpName

    # XXX one 2.0.8 bug: absolute manifest doesn't work
    o = one path.relative process.cwd!, manifest
      .exclude ...exclude
      .name name
      .quiet!

    # XXX some way of injecting node core modules later
    if name is \sequelize
      o.dependency \util \* .dependency \events \*
    err <- o.save tmpfile

    throw err if err
    bundle = fs.readFileSync tmpfile, \utf-8

    cb bundle

  import-bundle: (name, manifest, cb) ->
    bundle_from = (name, m, cb) ~>
      if m is /\.js$/
        cb (require \fs .readFileSync m, \utf8)
      else
        @_bundle name, m, cb
    code <~ bundle_from name, manifest
    rows <~ @query "select name from plv8x.code where name = $1" [name]
    [q, bind] = if rows.length # udpate
      ["update plv8x.code set code = $2 where name = $1" [name, code]]
    else
      ["insert into plv8x.code (name, code) values($1, $2)" [name, code]]
    @query q, bind, cb

  mk-user-func: (spec, source, cb) ->
    [_, rettype, name, args] = spec.match /^([\.\w]+)?\s*(\w+)\((.*)\)$/ or throw "failed to parse #spec"

    param-obj = {}
    for arg, idx in args.split /\s*,\s*/
      [_, type, param-name] = arg.match /^([\.\w]+)\s*(\w+)?$/ or throw "failed to parse param #arg"
      param-name ?= "__#{idx}"
      param-obj[param-name] = type

    [_, pkg, expression] = source.match /^(\w*):(.*)$/ or throw "failed to parse source #source"

    body = if pkg
      plv8x-lift pkg, expression
      boot = true
    else
      xpression-to-body expression
    <~ @query _mk_func name, param-obj, rettype, body, {boot}

    cb { rettype, name, param-obj, body }


<[ bootstrap plv8xEval importBundle list purge deleteBundle mkUserFunc ]>.for-each !(key) ~>
    exports[key] = (conn, ...rest) ->
      console.error 'deprecated api, use PLX instead'
      plx = new PLX conn
      plx[key] ...rest

exports.new = (db, cb) ->
  db = "tcp://localhost/#db" if db.indexOf('/') < 0
  conn = connect db
  plx = new PLX conn
  <- plx.bootstrap
  <- plx.query 'select plv8x.boot()'
  <- plx.import-bundle \plv8x require.resolve \../package.json
  cb? plx

export function connect(db)
  require! pg
  new pg.Client db
    ..connect!

export function xpression-to-body(code)
  cls = if plv8? then plv8x.compile-livescript else compile-livescript
  ccoffee = if plv8? then plv8x.compile-coffeescript else compile-coffeescript
  match code
  | /^\s*->/     => cls code
  | /^\s*~>/     => cls code.replace /~>/ \->
  | /^\s*\=\>/   => ccoffee code.replace /\=\>/ \->
  | /^function/  => "(#code)"
  | /^\s*@/      => cls "-> #code"
  | /\breturn[(\s]/ => "(function(){#code})"
  | otherwise       => "(function(){return #code})"

export function compile-livescript(expression)
  require \LiveScript .compile expression, {+bare} .replace /;$/, ''

export function compile-coffeescript(expression)
  cs = require \CoffeeScript
{'fraction_non_alphanumeric': 0.1724225495175216, 'fraction_numerical': 0.009649568308786187, 'mean_word_length': 2.494676131322094, 'pattern_counts': {'":': 0, '<': 29, '<?xml version=': 0, '>': 77, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1489836', 'n_tokens_mistral': 2924, 'n_tokens_neox': 2800, 'n_words': 843}