<commit_before>/* Copyright (c) 2010-2020 <NAME> and other contributors, MIT License */
'use strict'

import { intern } from './lib/intern'

let internals = {
  name: 'mem-store'
}

module.exports = mem_store
Object.defineProperty(module.exports, 'name', { value: 'mem-store' })

module.exports.defaults = {
  'entity-id-exists':
    'Entity of type <%=type%> with id = <%=id%> already exists.',
}

/* NOTE: `intern` serves as a namespace for utility functions used by
 * the mem store.
 */
module.exports.intern = intern

function mem_store(this: any, options: any) {
  let seneca: any = this

  let init = seneca.export('entity/init')

  // merge default options with any provided by the caller
  options = seneca.util.deepextend(
    {
      prefix: '/mem-store',
      web: {
        dump: false,
      },

      // TODO: use seneca.export once it allows for null values
      generate_id: seneca.root.private$.exports['entity/generate_id'],
    },
    options
  )

  // The calling Seneca instance will provide
  // a description for us on init(), it will
  // be used in the logs
  let desc: any

  // Our super awesome in mem database. Please bear in mind
  // that this store is meant for fast prototyping, using
  // it for production is not advised!
  let entmap: any = {}

  // Define the store using a description object.
  // This is a convenience provided by seneca.store.init function.
  let store = {
    // The name of the plugin, this is what is the name you would
    // use in seneca.use(), eg seneca.use('mem-store').
    name: internals.name,

    save: function(this: any, msg: any, reply: any) {
      // Take a reference to Seneca
      // and the entity to save
      let seneca = this
      let ent = msg.ent

      // create our cannon and take a copy of
      // the zone, base and name, we will use
      // this info further down.
      let canon = ent.canon$({ object: true })
      let zone = canon.zone
      let base = canon.base
      let name = canon.name

      // check if we are in create mode,
      // if we are do a create, otherwise
      // we will do a save instead
      //
      const is_new = intern.is_new(ent)

      return is_new ? do_create() : do_save()

      // The actual save logic for saving or
      // creating and then saving the entity.
      function do_save(id?: any, isnew?: boolean) {
        entmap[base] = entmap[base] || {}
        entmap[base][name] = entmap[base][name] || {}


        // NOTE: It looks like `ent` is stripped of any private fields
        // at this point, hence the `ent.data$(true)` does not actually
        // leak private fields into saved entities. The line of code in
        // the snippet below, for example, does not save the user.psst$
        // field along with the entity:
        //
        // app.make('user').data$({ psst$: 'private' }).save$()
        //
        // This can be verified by logging the mement object below.
        //
        const mement = ent.data$(true, 'string')


        let mement_ptr: any = null
        let operation: string | null = null

        if (intern.is_upsert(msg)) {
          operation = 'upsert'
          mement_ptr = try_upsert(mement, msg)
        }

        if (null == mement_ptr) {
          operation = intern.is_new(msg.ent) ? 'insert' : 'update'
          mement_ptr = complete_save(mement, msg, id, isnew)
        }

        seneca.log.debug(() => [
          'save/' + operation,
          ent.canon$({ string: 1 }),
          mement_ptr,
          desc
        ])

        const result_mement = seneca.util.deep(mement_ptr)

        return reply(null, ent.make$(result_mement))


        function try_upsert(mement: any, msg: any) {
          const { q, ent } = msg
          const upsert_on = intern.clean_array(q.upsert$)

          if (0 < upsert_on.length) {
            const has_upsert_fields = upsert_on.every((p: string) => p in mement)

            if (has_upsert_fields) {
              const match_by = upsert_on.reduce((h: any, p: string) => {
                h[p] = mement[p]
                return h
              }, {})

              const updated_ent = intern.update_mement(entmap, ent, match_by, mement)

              return updated_ent
            }
          }

          return null
        }


        function complete_save(mement: any, msg: any, id?: any, isnew?: boolean) {<commit_msg>Move the logging statement<commit_after>/* Copyright (c) 2010-2020 <NAME> and other contributors, MIT License */
'use strict'

import { intern } from './lib/intern'

let internals = {
  name: 'mem-store'
}

module.exports = mem_store
Object.defineProperty(module.exports, 'name', { value: 'mem-store' })

module.exports.defaults = {
  'entity-id-exists':
    'Entity of type <%=type%> with id = <%=id%> already exists.',
}

/* NOTE: `intern` serves as a namespace for utility functions used by
 * the mem store.
 */
module.exports.intern = intern

function mem_store(this: any, options: any) {
  let seneca: any = this

  let init = seneca.export('entity/init')

  // merge default options with any provided by the caller
  options = seneca.util.deepextend(
    {
      prefix: '/mem-store',
      web: {
        dump: false,
      },

      // TODO: use seneca.export once it allows for null values
      generate_id: seneca.root.private$.exports['entity/generate_id'],
    },
    options
  )

  // The calling Seneca instance will provide
  // a description for us on init(), it will
  // be used in the logs
  let desc: any

  // Our super awesome in mem database. Please bear in mind
  // that this store is meant for fast prototyping, using
  // it for production is not advised!
  let entmap: any = {}

  // Define the store using a description object.
  // This is a convenience provided by seneca.store.init function.
  let store = {
    // The name of the plugin, this is what is the name you would
    // use in seneca.use(), eg seneca.use('mem-store').
    name: internals.name,

    save: function(this: any, msg: any, reply: any) {
      // Take a reference to Seneca
      // and the entity to save
      let seneca = this
      let ent = msg.ent

      // create our cannon and take a copy of
      // the zone, base and name, we will use
      // this info further down.
      let canon = ent.canon$({ object: true })
      let zone = canon.zone
      let base = canon.base
      let name = canon.name

      // check if we are in create mode,
      // if we are do a create, otherwise
      // we will do a save instead
      //
      const is_new = intern.is_new(ent)

      return is_new ? do_create() : do_save()

      // The actual save logic for saving or
      // creating and then saving the entity.
      function do_save(id?: any, isnew?: boolean) {
        entmap[base] = entmap[base] || {}
        entmap[base][name] = entmap[base][name] || {}


        // NOTE: It looks like `ent` is stripped of any private fields
        // at this point, hence the `ent.data$(true)` does not actually
        // leak private fields into saved entities. The line of code in
        // the snippet below, for example, does not save the user.psst$
        // field along with the entity:
        //
        // app.make('user').data$({ psst$: 'private' }).save$()
        //
        // This can be verified by logging the mement object below.
        //
        const mement = ent.data$(true, 'string')


        let mement_ptr: any = null
        let operation: string | null = null

        if (intern.is_upsert(msg)) {
          operation = 'upsert'
          mement_ptr = try_upsert(mement, msg)
        }

        if (null == mement_ptr) {
          operation = intern.is_new(msg.ent) ? 'insert' : 'update'
          mement_ptr = complete_save(mement, msg, id, isnew)
        }


        const result_mement = seneca.util.deep(mement_ptr)
        const result_ent = ent.make$(result_mement)

        seneca.log.debug(() => [
          'save/' + operation,
          ent.canon$({ string: 1 }),
          mement_ptr,
          desc
        ])

        return reply(null, result_ent)


        function try_upsert(mement: any, msg: any) {
          const { q, ent } = msg
          const upsert_on = intern.clean_array(q.upsert$)

          if (0 < upsert_on.length) {
            const has_upsert_fields = upsert_on.every((p: string) => p in mement)

            if (has_upsert_fields) {
              const match_by = upsert_on.reduce((h: any, p: string) => {
                h[p] = mement[p]
                return h
              }, {})

              const updated_ent = intern.update_mement(entmap, ent, match_by, mement)

              return updated_ent
            }
          }

          return null
        }


        function complete_save(mement: any, msg: any, id?: any, isnew?: boolean) {
{'fraction_non_alphanumeric': 0.11345015930814747, 'fraction_numerical': 0.002275830678197542, 'mean_word_length': 2.0506768483165567, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 15, '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': '1488279', 'n_tokens_mistral': 2672, 'n_tokens_neox': 2578, 'n_words': 896}