npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

duck-storage

v0.0.34

Published

event-based data-modeling ORM

Downloads

18

Readme

Installation

$ npm i duck-storage --save
# or
$ yarn add duck-storage

Features

stores schematized ducks

const createEvent = forEvent(Rack, 'create')
const entry = await Rack.create({
  firstName: 'Martin',
  lastName: 'Rafael'
})

t.truthy(entry)
t.true(Object.prototype.hasOwnProperty.call(entry, '_id'))
t.true(Object.prototype.hasOwnProperty.call(entry, '_v'))
t.is(entry.fullName, 'Martin Rafael')

const createEventPayload = (await createEvent)[0]

t.truthy(createEvent)
t.deepEqual(createEventPayload, entry)

entry.fullName = 'Pedro Perez'

t.is(entry.firstName, 'Pedro')
t.is(entry.lastName, 'Perez')

finds a duck

const entry = await Rack.create({
  firstName: 'Martin'
})

const found = await Rack.read(entry._id)
t.deepEqual(entry.toObject(), found.toObject())
t.not(entry, found)

updates information of a duck

const updateEvent = forEvent(Rack, 'update')
const created = (await Rack.create({
  firstName: 'Martin',
  lastName: 'Gonzalez'
})).consolidate()

const toUpdate = {
  firstName: 'Olivia'
}
const updated = await Rack.update({ lastName: { $eq: 'Gonzalez' } }, toUpdate)

const updatePayload = (await updateEvent)[0]

t.truthy(updatePayload)
t.deepEqual(updatePayload.oldEntry, created)
t.deepEqual(updatePayload.newEntry, toUpdate)
t.deepEqual(updatePayload.entry, updated[0])

t.true(Array.isArray(updated))
t.is(updated.length, 1)
t.is(updated[0].firstName, 'Olivia')
t.is(updated[0].lastName, 'Gonzalez')
t.is(updated[0]._v, 2)

const updatedEntry = await Rack.read(created._id)
t.is(updatedEntry.firstName, 'Olivia')

updates information of multiple ducks at a time

const updateEvent = forEvent(Rack, 'update', { trap: 2 })

const martin = (await Rack.create({
  firstName: 'Martin',
  lastName: 'Gonzalez'
})).toObject()

const ana = (await Rack.create({
  firstName: 'Ana',
  lastName: 'Sosa'
})).toObject()

const toUpdate = {
  firstName: 'Olivia'
}

const updated = await Rack.update({}, toUpdate)

t.true(Array.isArray(updated))

t.is(updated.length, 2)
t.is(updated[0]._id, martin._id)
t.is(updated[0].firstName, 'Olivia')
t.is(updated[0].lastName, 'Gonzalez')
t.is(updated[0]._v, 2)

t.is(updated[1]._id, ana._id)
t.is(updated[0].firstName, 'Olivia')
t.is(updated[0].lastName, 'Gonzalez')
t.is(updated[0]._v, 2)

const updatePayload = await updateEvent

t.truthy(updatePayload)

t.deepEqual(updatePayload[0].oldEntry, martin)
t.deepEqual(updatePayload[0].newEntry, toUpdate)
t.deepEqual(updatePayload[0].entry, updated[0])

t.deepEqual(updatePayload[1].oldEntry, ana)
t.deepEqual(updatePayload[1].newEntry, toUpdate)
t.deepEqual(updatePayload[1].entry, updated[1])

removes ducks from the rack

const deleteEvent = forEvent(Rack, 'delete')
const entry = await Rack.create({
  firstName: 'Martin',
  lastName: 'Gonzalez'
})
const deleted = await Rack.delete({
  _id: {
    $eq: entry._id
  }
})
const deletedPayload = (await deleteEvent)[0]

t.deepEqual(deletedPayload, deleted[0])

t.true(Array.isArray(deleted))
t.is(deleted.length, 1)
t.is(deleted[0]._id, entry._id)
t.is(deleted[0].firstName, 'Martin')
t.is(deleted[0].lastName, 'Gonzalez')

const notFound = await Rack.read({ _id: { $eq: entry._id } })
t.is(notFound, undefined)
t.is(Object.keys(Rack.storeKey).length, 0)

lists ducks in the rack

const entry1 = (await Rack.create({
  firstName: 'Martin',
  lastName: 'Gonzalez'
})).toObject()

const entry2 = (await Rack.create({
  firstName: 'Olivia',
  lastName: 'Gonzalez'
})).toObject()

const res = await Rack.list()
t.true(Array.isArray(res))
t.is(res.length, 2)
t.deepEqual(res.map(entry => entry.consolidate()), [entry1, entry2])

loads references of ducks in other racks

const orderSchema = new Schema({
  customer: {
    type: 'ObjectId',
    duckRack: 'customer'
  },
  amount: {
    type: Number,
    integer: true
  },
  createdAt: {
    type: Date,
    default: Date.now
  }
})
const customerSchema = new Schema({
  firstName: String,
  lastName: String,
  email: String
})

const OrderModel = new Duck({ schema: orderSchema })
const CustomerModel = new Duck({ schema: customerSchema })

const OrderBucket = new DuckRack('order', {
  duckModel: OrderModel
})

OrderBucket.hook('before', 'create', function (entry) {
  return entry
})

async function loadReferences (entry) {
  const entriesToLoad = this.duckModel
    .schema
    .paths
    .filter((path) => {
      return this.duckModel.schema.schemaAtPath(path).settings.duckRack && Utils.find(entry, path)
    })
    .map(path => {
      const Rack = DuckStorage.getRackByName(this.duckModel.schema.schemaAtPath(path).settings.duckRack)
      const _idPayload = Utils.find(entry, path)
      const _id = Rack.duckModel.schema.isValid(_idPayload) ? _idPayload._id : _idPayload
      return { duckRack: this.duckModel.schema.schemaAtPath(path).settings.duckRack, _id, path }
    })

  for (const entryToLoad of entriesToLoad) {
    set(entry, entryToLoad.path, await DuckStorage.getRackByName(entryToLoad.duckRack).findOneById(entryToLoad._id))
  }

  return entry
}

OrderBucket.hook('after', 'read', loadReferences)
OrderBucket.hook('after', 'create', loadReferences)

const CustomerBucket = new DuckRack('customer', {
  duckModel: CustomerModel
})

const customer = await CustomerBucket.create({
  firstName: 'Martin',
  lastName: 'Rafael',
  email: '[email protected]'
})

t.truthy(customer._id)

// console.log({ customer })
// console.log(CustomerModel.schema.parse(customer))

try {
  await OrderModel.schema.parse({
    customer,
    amount: 100
  })
} catch (err) {
  console.log('\n\nERROR\n\n', err)
  throw err
}

const order = await OrderBucket.create({
  customer,
  amount: 100
})

t.deepEqual(order.customer, customer.consolidate())

const readOrder = await OrderBucket.read(order._id)
t.deepEqual(readOrder.customer, customer.consolidate())

defines duck rack methods

const userSchema = new Schema({
  name: String,
  level: String
})
const userDuckModel = new Duck({ schema: userSchema })
const UserRack = new DuckRack('some-user', {
  duckModel: userDuckModel,
  methods: {
    changeLevel: {
      input: {
        userId: 'ObjectId',
        newLevel: String
      },
      async handler ({ userId, newLevel }) {
        const user = await this.findOneById(userId)
        user.level = newLevel
        return this.update(userId, user)
      }
    },
    getAdmins () {
      return this.list({
        level: {
          $eq: 'admin'
        }
      })
    },
    getUsers () {
      return this.list({
        level: {
          $eq: 'user'
        }
      })
    }
  }
})

await UserRack.create({
  name: 'Martin',
  level: 'admin'
})

await UserRack.create({
  name: 'Rafael',
  level: 'admin'
})

await UserRack.create({
  name: 'Pedro',
  level: 'user'
})

const admins = await UserRack.getAdmins()
t.truthy(admins)
t.is(admins.length, 2)

const users = await UserRack.getUsers()
t.truthy(users)
t.is(users.length, 1)

UserRack.changeLevel({
  userId: admins[0]._id,
  newLevel: 'user'
})

validates properties in realtime

const duckModel = Duck.create({ schema: AdvancedSchema })
let err

err = t.throws(() => { return duckModel.dont.do.this.to.me })
t.is(err.message, 'Unknown property dont')

err = t.throws(() => { duckModel.firstName = 123 })
t.is(err.message, 'Invalid string')

err = t.throws(() => { duckModel.address.zip = '33q29' })
t.is(err.message, 'Invalid number')

err = t.throws(() => { duckModel.email = 'martin' })
t.is(err.message, 'Invalid e-mail address')

t.notThrows(() => { duckModel.firstName = 'Martin' })
t.notThrows(() => { duckModel.lastName = 'Rafael' })
t.notThrows(() => { duckModel.email = '[email protected]' })
t.notThrows(() => { duckModel.address.line1 = 'Brickell' })
t.notThrows(() => { duckModel.address.zip = 305 })

t.is(duckModel.firstName, 'Martin')
t.is(duckModel.lastName, 'Rafael')
t.is(duckModel.email, '[email protected]')
t.is(duckModel.address.line1, 'Brickell')
t.is(duckModel.address.zip, 305)

err = t.throws(() => duckModel.getEmailDomain())
t.is(err.message, 'consolidate the model prior invoking method getEmailDomain')

duckModel.consolidate()

t.truthy(duckModel._id)
t.is(duckModel.getEmailDomain(), 'devtin.io')

t.deepEqual(duckModel.toObject(), {
  _id: duckModel._id,
  _v: 1,
  firstName: 'Martin',
  lastName: 'Rafael',
  email: '[email protected]',
  address: {
    line1: 'Brickell',
    zip: 305
  }
})

registers duck racks from given dir

checks all events emitted by a duck

const User = new Schema({
  name: String,
  emails: {
    type: Array,
    default () {
      return []
    }
  }
}, {
  methods: {
    addEmail: {
      events: {
        emailAdded: String
      },
      input: String,
      handler (email) {
        this.$field.emails.push(email)
        this.$emit('emailAdded', email)
      }
    }
  }
})

const userPayload = User.parse({
  name: 'Martin'
})

const eventsFired = schemaDuckMonitor(User, userPayload)

t.is(eventsFired.length, 0)
userPayload.addEmail('martin')
t.is(eventsFired.length, 1)

DuckRack

Description:

Stores only ducks specified by the duckModel

duckRack.read(_id) ⇒ Promise.<*>

| Param | | --- | | _id |

Description:

Sugar for find(entityName, { _id: { $eq: _id } })

Duck

Description:

A duck model

duck.getModel([defaultValues], [state]) ⇒ Object

| Param | Type | | --- | --- | | [defaultValues] | Object | | [state] | Object |

Returns: Object - the duck proxy model
Description:

Prepares a duck proxy model to be used with the defined schema

Duck.create(duckPayload, [...modelPayload]) ⇒ Object

| Param | Type | Description | | --- | --- | --- | | duckPayload | Object | the duck constructor payload | | [...modelPayload] | | the model payload |

Returns: Object - the duck proxy model
Description:

Sugar for calling new Duck({...}).getModel()

schemaDuckMonitor ⇒ Array

| Param | Type | | --- | --- | | schema | Object | | payload | Object |

Returns: Array - an array with all of the events fired
Description:

Logs all events emitted by a duck


License

MIT

© 2020-present Martin Rafael Gonzalez [email protected]