<commit_before>/* Copyright (c) 2014 <NAME>, MIT License */
'use strict'

var assert = require('chai').assert
var async = require('async')
var _ = require('lodash')
var lab = require('lab')

var bartemplate = {
  name$: 'bar',
  base$: 'moon',
  zone$: 'zen',

  str: 'aaa',
  int: 11,
  dec: 33.33,
  bol: false,
  wen: new Date(2020, 1, 1),
  arr: [ 2, 3 ],
  obj: {
    a: 1,
    b: [2],
    c: { d: 3 }
  }
}

var barverify = function (bar) {
  assert.equal(bar.str, 'aaa')
  assert.equal(bar.int, 11)
  assert.equal(bar.dec, 33.33)
  assert.equal(bar.bol, false)
  assert.equal(_.isDate(bar.wen) ? bar.wen.toISOString() : bar.wen, new Date(2020, 1, 1).toISOString())
  assert.equal('' + bar.arr, '' + [ 2, 3 ])
  assert.deepEqual(bar.obj, {
    a: 1,
    b: [2],
    c: { d: 3 }
  })
}

function verify (cb, tests) {
  return function (error, out) {
    if (error) {
      return cb(error)
    }

    try {
      tests(out)
    }
    catch (ex) {
      return cb(ex)
    }

    cb()
  }
}

function clearDb (si) {
  return function clear (done) {
    async.series([
      function clearFoo (next) {
        si.make('foo').remove$({ all$: true }, next)
      },
      function clearBar (next) {
        si.make('zen', 'moon', 'bar').remove$({ all$: true }, next)
      }
    ], done)
  }
}

function createEntities (si, name, data) {
  return function create (done) {
    async.each(data, function (el, next) {
      si.make$(name, el).save$(next)
    }, done)
  }
}

function basictest (settings) {
  var si = settings.seneca
  var merge = settings.senecaMerge
  var script = settings.script || lab.script()

  var describe = script.describe
  var it = script.it
  var before = script.before
  var beforeEach = script.beforeEach

  describe('Basic Tests', function () {
    describe('Load', function () {
      before(clearDb(si))
      before(createEntities(si, 'foo', [{
        id$: 'foo1',
        p1: 'v1'
      }, {
        id$: 'foo2',
        p1: 'v2',
        p2: 'z2'
      }]))
      before(createEntities(si, 'bar', [ bartemplate ]))

      it('should load an entity', function (done) {
        var foo = si.make('foo')
        foo.load$('foo1', verify(done, function (foo1) {
          assert.isNotNull(foo1)
          assert.equal(foo1.id, 'foo1')
          assert.equal(foo1.p1, 'v1')
        }))
      })

      it('should return null for non existing entity', function (done) {
        var foo = si.make('foo')
        foo.load$('does-not-exist-at-all-at-all', verify(done, function (out) {
          assert.isNull(out)
        }))
      })

      it('should support filtering', function (done) {
        var foo = si.make('foo')
        foo.load$({ p1: 'v2' }, verify(done, function (foo1) {
          assert.isNotNull(foo1)
          assert.equal(foo1.id, 'foo2')
          assert.equal(foo1.p1, 'v2')
          assert.equal(foo1.p2, 'z2')
        }))
      })

      it('should filter with AND', function (done) {
        var foo = si.make('foo')
        foo.load$({ p1: 'v2', p2: 'z2' }, verify(done, function (foo1) {
          assert.isNotNull(foo1)
          assert.equal(foo1.id, 'foo2')
          assert.equal(foo1.p1, 'v2')
          assert.equal(foo1.p2, 'z2')
        }))
      })

      it('should filter with AND 2', function (done) {
        var foo = si.make('foo')
        foo.load$({ p1: 'v2', p2: 'a' }, verify(done, function (foo1) {
          assert.isNull(foo1)
        }))
      })

      it('should support different attribute types', function (done) {
        var bar = si.make('zen', 'moon', 'bar')

        bar.load$({ str: 'aaa' }, verify(done, function (bar1) {
          assert.isNotNull(bar1)
          assert.isNotNull(bar1.id)
          barverify(bar1)
        }))
      })
    })

    describe('Save', function () {
      beforeEach(clearDb(si))
      beforeEach(createEntities(si, 'foo', [{
        id$: 'to-be-updated',
        p1: 'v1',
        p2: 'v2',
        p3: 'v3'
      }]))

      it('should save an entity to store (and generate an id)', function (done) {
        var foo = si.make('foo')
        foo.p1 = 'v1'
        foo.p2 = 'v2'

        foo.save$(function (err, foo1) {
          assert.isNull(err)
          assert.isNotNull(foo1.id)

          foo1.load$(foo1.id, verify(done, function (foo2) {
            assert.isNotNull(foo2)
            assert.equal(foo2.id, foo1.id)
            assert.equal(foo2.p1, 'v1')
            assert.equal(foo2.p2, 'v2')
          }))
        })
      })

      it('should save an entity to store (with provided id)', function (done) {
        var foo = si.make('foo')
        foo.id$ = 'existing'
        foo.p1 = 'v1'
        foo.p2 = 'v2'

        foo.save$(function (err, foo1) {
          assert.isNull(err)
          assert.isNotNull(foo1.id)
          assert.equal(foo1.id, 'existing')

          foo1.load$('existing', verify(done, function (foo2) {
            assert.isNotNull(foo2)
            assert.equal(foo2.id, 'existing')
            assert.equal(foo2.p1, 'v1')
            assert.equal(foo2.p2, 'v2')
          }))
        })
      })

      it('should update an entity if id provided', function (done) {
        var foo = si.make('foo')
        foo.id = 'to-be-updated'
        foo.p1 = 'z1'
        foo.p2 = 'z2'

        foo.save$(function (err, foo1) {
          assert.isNull(err)
          assert.isNotNull(foo1.id)
          assert.equal(foo1.id, 'to-be-updated')
          assert.equal(foo1.p1, 'z1')
          assert.equal(foo1.p2, 'z2')
          assert.equal(foo1.p3, 'v3')

          foo1.load$('to-be-updated', verify(done, function (foo2) {
            assert.isNotNull(foo2)
            assert.equal(foo2.id, 'to-be-updated')
            assert.equal(foo2.p1, 'z1')
            assert.equal(foo2.p2, 'z2')
            assert.equal(foo2.p3, 'v3')
          }))
        })
      })

      it('should save an entity if id provided but original doesn\'t exist', function (done) {
        var foo = si.make('foo')
        foo.id = 'will-be-inserted'
        foo.p1 = 'z1'
        foo.p2 = 'z2'
        foo.p3 = 'z3'

        foo.save$(function (err, foo1) {
          assert.isNull(err)
          assert.isNotNull(foo1.id)
          assert.equal(foo1.id, 'will-be-inserted')
          assert.equal(foo1.p1, 'z1')
          assert.equal(foo1.p2, 'z2')
          assert.equal(foo1.p3, 'z3')

          foo1.load$('to-be-updated', verify(done, function (foo2) {
            assert.isNotNull(foo2)
            assert.equal(foo2.id, 'will-be-inserted')
            assert.equal(foo2.p1, 'z1')
            assert.equal(foo2.p2, 'z2')
            assert.equal(foo2.p3, 'z3')
          }))
        })
      })

      it('should allow to not merge during update with merge$: false', function (done) {
        var foo = si.make('foo')
        foo.id = 'to-be-updated'
        foo.p1 = 'z1'
        foo.p2 = 'z2'

        foo.save$({ merge$: false }, function (err, foo1) {
          assert.isNull(err)
          assert.isNotNull(foo1.id)
          assert.equal(foo1.id, 'to-be-updated')
          assert.equal(foo1.p1, 'z1')
          assert.equal(foo1.p2, 'z2')
          assert.notOk(foo1.p3)

          foo1.load$('to-be-updated', verify(done, function (foo2) {
            assert.isNotNull(foo2)
            assert.equal(foo2.id, 'to-be-updated')
            assert.equal(foo2.p1, 'z1')
            assert.equal(foo2.p2, 'z2')
            assert.notOk(foo1.p3)
          }))
        })
      })

      it('should support different attribute types', function (done) {
        var bar = si.make(bartemplate)
        var mark = bar.mark = Math.random()

        bar.save$(function (err, bar) {
          assert.isNull(err)
          assert.isNotNull(bar)
          assert.isNotNull(bar.id)
          barverify(bar)
          assert.equal(bar.mark, mark)

          bar.load$(bar.id, verify(done, function (bar1) {
            assert.isNotNull(bar1)
            assert.equal(bar1.id, bar.id)
            barverify(bar1)
            assert.equal(bar1.mark, mark)
          }))
        })
      })

      it('should allow dublicate attributes', function (done) {
        var foo = si.make('foo')
        foo.p2 = 'v2'

        foo.save$(function (err, foo1) {
          assert.isNull(err)
          assert.isNotNull(foo1.id)
          assert.equal(foo1.p2, 'v2')

          foo.load$(foo1.id, verify(done, function (foo2) {
            assert.isNotNull(foo2)
            assert.equal(foo2.id, foo1.id)
            assert.equal(foo2.p2, 'v2')
            assert.notOk(foo2.p1)
            assert.notOk(foo2.p3)
          }))
        })
      })
    })

    describe('With Option marge:false', function () {
      beforeEach(clearDb(si))
      beforeEach(createEntities(si, 'foo', [{
        id$: 'to-be-updated',
        p1: 'v1',
        p2: 'v2',
        p3: 'v3'
      }]))

      it('should provide senecaMerge', function (done) {
        assert(merge, 'Implementor should provide a seneca instance with the store configured to default to merge:false')
        done()
      })

      it('should update an entity if id provided', function (done) {
        var foo = merge.make('foo')
        foo.id = 'to-be-updated'
        foo.p1 = 'z1'
        foo.p2 = 'z2'

        foo.save$(function (err, foo1) {
          assert.isNull(err)
          assert.isNotNull(foo1.id)
          assert.equal(foo1.id, 'to-be-updated')
          assert.equal(foo1.p1, 'z1')
          assert.equal(foo1.p2, 'z2')
          assert.notOk(foo1.p3)

          foo1.load$('to-be-updated', verify(done, function (foo2) {
            assert.isNotNull(foo2)
            assert.equal(foo2.id, 'to-be-updated')
            assert.equal(foo2.p1, 'z1')
            assert.equal(foo2.p2, 'z2')
            assert.notOk(foo2.p3)
          }))
        })
      })

      it('should allow to merge during update with merge$: true', function (done) {
        var foo = merge.make('foo')
        foo.id = 'to-be-updated'
        foo.p1 = 'z1'
        foo.p2 = 'z2'

        foo.save$({ merge$: true }, function (err, foo1) {
          assert.isNull(err)
          assert.isNotNull(foo1.id)
          assert.equal(foo1.id, 'to-be-updated')
          assert.equal(foo1.p1, 'z1')
          assert.equal(foo1.p2, 'z2')
          assert.equal(foo1.p3, 'v3')

          foo1.load$('to-be-updated', verify(done, function (foo2) {
            assert.isNotNull(foo2)
            assert.equal(foo2.id, 'to-be-updated')
            assert.equal(foo2.p1, 'z1')
            assert.equal(foo2.p2, 'z2')
            assert.equal(foo1.p3, 'v3')
          }))
        })
      })
    })

    describe('List', function () {
      before(clearDb(si))
      before(createEntities(si, 'foo', [{
        id$: 'foo1',
        p1: 'v1'
      }, {
        id$: 'foo2',
        p1: 'v2',
        p2: 'z2'
      }]))
      before(createEntities(si, 'bar', [ bartemplate ]))

      it('should load all elements if no params', function (done) {
        var bar = si.make('zen', 'moon', 'bar')
        bar.list$({}, verify(done, function (res) {
          assert.lengthOf(res, 1)
          barverify(res[0])
        }))
      })

      it('should load all elements if no params 2', function (done) {
        var foo = si.make('foo')
        foo.list$({}, verify(done, function (res) {
          assert.lengthOf(res, 2)
        }))
      })

      it('should list entities by id', function (done) {
        var foo = si.make('foo')
        foo.list$({ id: 'foo1' }, verify(done, function (res) {
          assert.lengthOf(res, 1)
          assert.equal(res[0].p1, 'v1')
          assert.notOk(res[0].p2)
          assert.notOk(res[0].p3)
        }))
      })

      it('should list entities by integer property', function (done) {
        var bar = si.make('zen', 'moon', 'bar')
        bar.list$({ int: bartemplate.int }, verify(done, function (res) {
          assert.lengthOf(res, 1)
          barverify(res[0])
        }))
      })

      it('should list entities by string property', function (done) {
        var foo = si.make('foo')
        foo.list$({ p2: 'z2' }, verify(done, function (res) {
          assert.lengthOf(res, 1)
          assert.equal(res[0].p1, 'v2')
          assert.equal(res[0].p2, 'z2')
        }))
      })

      it('should list entities by two properties', function (done) {
        var foo = si.make('foo')
        foo.list$({ p2: 'z2', p1: 'v2' }, verify(done, function (res) {
          assert.lengthOf(res, 1)
          assert.equal(res[0].p1, 'v2')
          assert.equal(res[0].p2, 'z2')
        }))
      })

      it('should filter with AND', function (done) {
        var foo = si.make('foo')
        foo.list$({ p2: 'z2', p1: 'v1' }, verify(done, function (res) {
          assert.lengthOf(res, 0)
        }))
      })
    })

    describe('Remove', function () {
      beforeEach(clearDb(si))
      beforeEach(createEntities(si, 'foo', [{
        id$: 'foo1',
        p1: 'v1'
      }, {
        id$: 'foo2',
        p1: 'v2',
        p2: 'z2'
      }]))
      beforeEach(createEntities(si, 'bar', [ bartemplate ]))

      it('should delete only an entity', function (done) {
        var foo = si.make('foo')
        foo.remove$({}, function (err, res) {
          assert.isNull(err)
          assert.notOk(res)

          foo.list$({}, verify(done, function (res) {
            assert.lengthOf(res, 1)<commit_msg>support opaque ids on list<commit_after>/* Copyright (c) 2014 <NAME>, MIT License */
'use strict'

var assert = require('chai').assert
var async = require('async')
var _ = require('lodash')
var lab = require('lab')

var bartemplate = {
  name$: 'bar',
  base$: 'moon',
  zone$: 'zen',

  str: 'aaa',
  int: 11,
  dec: 33.33,
  bol: false,
  wen: new Date(2020, 1, 1),
  arr: [ 2, 3 ],
  obj: {
    a: 1,
    b: [2],
    c: { d: 3 }
  }
}

var barverify = function (bar) {
  assert.equal(bar.str, 'aaa')
  assert.equal(bar.int, 11)
  assert.equal(bar.dec, 33.33)
  assert.equal(bar.bol, false)
  assert.equal(_.isDate(bar.wen) ? bar.wen.toISOString() : bar.wen, new Date(2020, 1, 1).toISOString())
  assert.equal('' + bar.arr, '' + [ 2, 3 ])
  assert.deepEqual(bar.obj, {
    a: 1,
    b: [2],
    c: { d: 3 }
  })
}

function verify (cb, tests) {
  return function (error, out) {
    if (error) {
      return cb(error)
    }

    try {
      tests(out)
    }
    catch (ex) {
      return cb(ex)
    }

    cb()
  }
}

function clearDb (si) {
  return function clear (done) {
    async.series([
      function clearFoo (next) {
        si.make('foo').remove$({ all$: true }, next)
      },
      function clearBar (next) {
        si.make('zen', 'moon', 'bar').remove$({ all$: true }, next)
      }
    ], done)
  }
}

function createEntities (si, name, data) {
  return function create (done) {
    async.each(data, function (el, next) {
      si.make$(name, el).save$(next)
    }, done)
  }
}

function basictest (settings) {
  var si = settings.seneca
  var merge = settings.senecaMerge
  var script = settings.script || lab.script()

  var describe = script.describe
  var it = script.it
  var before = script.before
  var beforeEach = script.beforeEach

  describe('Basic Tests', function () {
    describe('Load', function () {
      before(clearDb(si))
      before(createEntities(si, 'foo', [{
        id$: 'foo1',
        p1: 'v1'
      }, {
        id$: 'foo2',
        p1: 'v2',
        p2: 'z2'
      }]))
      before(createEntities(si, 'bar', [ bartemplate ]))

      it('should load an entity', function (done) {
        var foo = si.make('foo')
        foo.load$('foo1', verify(done, function (foo1) {
          assert.isNotNull(foo1)
          assert.equal(foo1.id, 'foo1')
          assert.equal(foo1.p1, 'v1')
        }))
      })

      it('should return null for non existing entity', function (done) {
        var foo = si.make('foo')
        foo.load$('does-not-exist-at-all-at-all', verify(done, function (out) {
          assert.isNull(out)
        }))
      })

      it('should support filtering', function (done) {
        var foo = si.make('foo')
        foo.load$({ p1: 'v2' }, verify(done, function (foo1) {
          assert.isNotNull(foo1)
          assert.equal(foo1.id, 'foo2')
          assert.equal(foo1.p1, 'v2')
          assert.equal(foo1.p2, 'z2')
        }))
      })

      it('should filter with AND', function (done) {
        var foo = si.make('foo')
        foo.load$({ p1: 'v2', p2: 'z2' }, verify(done, function (foo1) {
          assert.isNotNull(foo1)
          assert.equal(foo1.id, 'foo2')
          assert.equal(foo1.p1, 'v2')
          assert.equal(foo1.p2, 'z2')
        }))
      })

      it('should filter with AND 2', function (done) {
        var foo = si.make('foo')
        foo.load$({ p1: 'v2', p2: 'a' }, verify(done, function (foo1) {
          assert.isNull(foo1)
        }))
      })

      it('should support different attribute types', function (done) {
        var bar = si.make('zen', 'moon', 'bar')

        bar.load$({ str: 'aaa' }, verify(done, function (bar1) {
          assert.isNotNull(bar1)
          assert.isNotNull(bar1.id)
          barverify(bar1)
        }))
      })
    })

    describe('Save', function () {
      beforeEach(clearDb(si))
      beforeEach(createEntities(si, 'foo', [{
        id$: 'to-be-updated',
        p1: 'v1',
        p2: 'v2',
        p3: 'v3'
      }]))

      it('should save an entity to store (and generate an id)', function (done) {
        var foo = si.make('foo')
        foo.p1 = 'v1'
        foo.p2 = 'v2'

        foo.save$(function (err, foo1) {
          assert.isNull(err)
          assert.isNotNull(foo1.id)

          foo1.load$(foo1.id, verify(done, function (foo2) {
            assert.isNotNull(foo2)
            assert.equal(foo2.id, foo1.id)
            assert.equal(foo2.p1, 'v1')
            assert.equal(foo2.p2, 'v2')
          }))
        })
      })

      it('should save an entity to store (with provided id)', function (done) {
        var foo = si.make('foo')
        foo.id$ = 'existing'
        foo.p1 = 'v1'
        foo.p2 = 'v2'

        foo.save$(function (err, foo1) {
          assert.isNull(err)
          assert.isNotNull(foo1.id)
          assert.equal(foo1.id, 'existing')

          foo1.load$('existing', verify(done, function (foo2) {
            assert.isNotNull(foo2)
            assert.equal(foo2.id, 'existing')
            assert.equal(foo2.p1, 'v1')
            assert.equal(foo2.p2, 'v2')
          }))
        })
      })

      it('should update an entity if id provided', function (done) {
        var foo = si.make('foo')
        foo.id = 'to-be-updated'
        foo.p1 = 'z1'
        foo.p2 = 'z2'

        foo.save$(function (err, foo1) {
          assert.isNull(err)
          assert.isNotNull(foo1.id)
          assert.equal(foo1.id, 'to-be-updated')
          assert.equal(foo1.p1, 'z1')
          assert.equal(foo1.p2, 'z2')
          assert.equal(foo1.p3, 'v3')

          foo1.load$('to-be-updated', verify(done, function (foo2) {
            assert.isNotNull(foo2)
            assert.equal(foo2.id, 'to-be-updated')
            assert.equal(foo2.p1, 'z1')
            assert.equal(foo2.p2, 'z2')
            assert.equal(foo2.p3, 'v3')
          }))
        })
      })

      it('should save an entity if id provided but original doesn\'t exist', function (done) {
        var foo = si.make('foo')
        foo.id = 'will-be-inserted'
        foo.p1 = 'z1'
        foo.p2 = 'z2'
        foo.p3 = 'z3'

        foo.save$(function (err, foo1) {
          assert.isNull(err)
          assert.isNotNull(foo1.id)
          assert.equal(foo1.id, 'will-be-inserted')
          assert.equal(foo1.p1, 'z1')
          assert.equal(foo1.p2, 'z2')
          assert.equal(foo1.p3, 'z3')

          foo1.load$('to-be-updated', verify(done, function (foo2) {
            assert.isNotNull(foo2)
            assert.equal(foo2.id, 'will-be-inserted')
            assert.equal(foo2.p1, 'z1')
            assert.equal(foo2.p2, 'z2')
            assert.equal(foo2.p3, 'z3')
          }))
        })
      })

      it('should allow to not merge during update with merge$: false', function (done) {
        var foo = si.make('foo')
        foo.id = 'to-be-updated'
        foo.p1 = 'z1'
        foo.p2 = 'z2'

        foo.save$({ merge$: false }, function (err, foo1) {
          assert.isNull(err)
          assert.isNotNull(foo1.id)
          assert.equal(foo1.id, 'to-be-updated')
          assert.equal(foo1.p1, 'z1')
          assert.equal(foo1.p2, 'z2')
          assert.notOk(foo1.p3)

          foo1.load$('to-be-updated', verify(done, function (foo2) {
            assert.isNotNull(foo2)
            assert.equal(foo2.id, 'to-be-updated')
            assert.equal(foo2.p1, 'z1')
            assert.equal(foo2.p2, 'z2')
            assert.notOk(foo1.p3)
          }))
        })
      })

      it('should support different attribute types', function (done) {
        var bar = si.make(bartemplate)
        var mark = bar.mark = Math.random()

        bar.save$(function (err, bar) {
          assert.isNull(err)
          assert.isNotNull(bar)
          assert.isNotNull(bar.id)
          barverify(bar)
          assert.equal(bar.mark, mark)

          bar.load$(bar.id, verify(done, function (bar1) {
            assert.isNotNull(bar1)
            assert.equal(bar1.id, bar.id)
            barverify(bar1)
            assert.equal(bar1.mark, mark)
          }))
        })
      })

      it('should allow dublicate attributes', function (done) {
        var foo = si.make('foo')
        foo.p2 = 'v2'

        foo.save$(function (err, foo1) {
          assert.isNull(err)
          assert.isNotNull(foo1.id)
          assert.equal(foo1.p2, 'v2')

          foo.load$(foo1.id, verify(done, function (foo2) {
            assert.isNotNull(foo2)
            assert.equal(foo2.id, foo1.id)
            assert.equal(foo2.p2, 'v2')
            assert.notOk(foo2.p1)
            assert.notOk(foo2.p3)
          }))
        })
      })
    })

    describe('With Option marge:false', function () {
      beforeEach(clearDb(si))
      beforeEach(createEntities(si, 'foo', [{
        id$: 'to-be-updated',
        p1: 'v1',
        p2: 'v2',
        p3: 'v3'
      }]))

      it('should provide senecaMerge', function (done) {
        assert(merge, 'Implementor should provide a seneca instance with the store configured to default to merge:false')
        done()
      })

      it('should update an entity if id provided', function (done) {
        var foo = merge.make('foo')
        foo.id = 'to-be-updated'
        foo.p1 = 'z1'
        foo.p2 = 'z2'

        foo.save$(function (err, foo1) {
          assert.isNull(err)
          assert.isNotNull(foo1.id)
          assert.equal(foo1.id, 'to-be-updated')
          assert.equal(foo1.p1, 'z1')
          assert.equal(foo1.p2, 'z2')
          assert.notOk(foo1.p3)

          foo1.load$('to-be-updated', verify(done, function (foo2) {
            assert.isNotNull(foo2)
            assert.equal(foo2.id, 'to-be-updated')
            assert.equal(foo2.p1, 'z1')
            assert.equal(foo2.p2, 'z2')
            assert.notOk(foo2.p3)
          }))
        })
      })

      it('should allow to merge during update with merge$: true', function (done) {
        var foo = merge.make('foo')
        foo.id = 'to-be-updated'
        foo.p1 = 'z1'
        foo.p2 = 'z2'

        foo.save$({ merge$: true }, function (err, foo1) {
          assert.isNull(err)
          assert.isNotNull(foo1.id)
          assert.equal(foo1.id, 'to-be-updated')
          assert.equal(foo1.p1, 'z1')
          assert.equal(foo1.p2, 'z2')
          assert.equal(foo1.p3, 'v3')

          foo1.load$('to-be-updated', verify(done, function (foo2) {
            assert.isNotNull(foo2)
            assert.equal(foo2.id, 'to-be-updated')
            assert.equal(foo2.p1, 'z1')
            assert.equal(foo2.p2, 'z2')
            assert.equal(foo1.p3, 'v3')
          }))
        })
      })
    })

    describe('List', function () {
      before(clearDb(si))
      before(createEntities(si, 'foo', [{
        id$: 'foo1',
        p1: 'v1'
      }, {
        id$: 'foo2',
        p1: 'v2',
        p2: 'z2'
      }]))
      before(createEntities(si, 'bar', [ bartemplate ]))

      it('should load all elements if no params', function (done) {
        var bar = si.make('zen', 'moon', 'bar')
        bar.list$({}, verify(done, function (res) {
          assert.lengthOf(res, 1)
          barverify(res[0])
        }))
      })

      it('should load all elements if no params 2', function (done) {
        var foo = si.make('foo')
        foo.list$({}, verify(done, function (res) {
          assert.lengthOf(res, 2)
        }))
      })

      it('should list entities by id', function (done) {
        var foo = si.make('foo')
        foo.list$({ id: 'foo1' }, verify(done, function (res) {
          assert.lengthOf(res, 1)
          assert.equal(res[0].p1, 'v1')
          assert.notOk(res[0].p2)
          assert.notOk(res[0].p3)
        }))
      })

      it('should list entities by integer property', function (done) {
        var bar = si.make('zen', 'moon', 'bar')
        bar.list$({ int: bartemplate.int }, verify(done, function (res) {
          assert.lengthOf(res, 1)
          barverify(res[0])
        }))
      })

      it('should list entities by string property', function (done) {
        var foo = si.make('foo')
        foo.list$({ p2: 'z2' }, verify(done, function (res) {
          assert.lengthOf(res, 1)
          assert.equal(res[0].p1, 'v2')
          assert.equal(res[0].p2, 'z2')
        }))
      })

      it('should list entities by two properties', function (done) {
        var foo = si.make('foo')
        foo.list$({ p2: 'z2', p1: 'v2' }, verify(done, function (res) {
          assert.lengthOf(res, 1)
          assert.equal(res[0].p1, 'v2')
          assert.equal(res[0].p2, 'z2')
        }))
      })

      it('should support opaque ids (array)', function (done) {
        var foo = si.make('foo')
        foo.list$([ 'foo1', 'foo2' ], verify(done, function (res) {
          assert.lengthOf(res, 2)
          assert.equal(res[0].p1, 'v1')
          assert.notOk(res[0].p2)
          assert.notOk(res[0].p3)
          assert.equal(res[1].p1, 'v2')
          assert.equal(res[1].p2, 'z2')
          assert.equal(res[1].p3)
        }))
      })

      it('should support opaque ids (single id)', function (done) {
        var foo = si.make('foo')
        foo.list$([ 'foo2' ], verify(done, function (res) {
          assert.lengthOf(res, 1)
          assert.equal(res[0].p1, 'v2')
          assert.equal(res[0].p2, 'z2')
          assert.equal(res[0].p3)
        }))
      })

      it('should support opaque ids (string)', function (done) {
        var foo = si.make('foo')
        foo.list$('foo2', verify(done, function (res) {
          assert.lengthOf(res, 1)
          assert.equal(res[0].p1, 'v2')
          assert.equal(res[0].p2, 'z2')
          assert.equal(res[0].p3)
        }))
      })

      it('should filter with AND', function (done) {
        var foo = si.make('foo')
        foo.list$({ p2: 'z2', p1: 'v1' }, verify(done, function (res) {
          assert.lengthOf(res, 0)
        }))
      })
    })

    describe('Remove', function () {
      beforeEach(clearDb(si))
      beforeEach(createEntities(si, 'foo', [{
        id$: 'foo1',
        p1: 'v1'
      }, {
        id$: 'foo2',
        p1: 'v2',
        p2: 'z2'
      }]))
      beforeEach(createEntities(si, 'bar', [ bartemplate ]))

      it('should delete only an entity', function (done) {
        var foo = si.make('foo')
        foo.remove$({}, function (err, res) {
          assert.isNull(err)
          assert.notOk(res)

          foo.list$({}, verify(done, function (res) {
            assert.lengthOf(res, 1)
{'fraction_non_alphanumeric': 0.16579545044882657, 'fraction_numerical': 0.027398247954143987, 'mean_word_length': 1.8430870144511633, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 5, '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': '7506081', 'n_tokens_mistral': 9794, 'n_tokens_neox': 9543, 'n_words': 1944}