Proposed syntax.
Internally, this prepares the predicate for an array.filter()
operation.
.where( propertyName ) : Start query. Returns query object.
.and( propertyName ) : Continues query with logical AND. Returns query object.
.or ( propertyName ) : Continues query with logical OR. Returns query object.
.startsWith(), .endsWith() : Adds string start/end match comparison to the query. Returns query object.
.includes() : Adds substring match to the query. Returns query object.
.is()|.isGreaterThan()|.isLessThan() : Adds value comparison to the query. Returns query object.
Internally, this executes and returns the result of an array.filter()
operation. If a specific set of properties is requested, an array.map()
is also performed.
.get ([property1, property2, …]) : Executes query. If properties are specified, returns only those properties.
Internally, these result in an array.sort()
operation.
.sortBy() : Sorts by given property in ascending order.
.sortAscendingBy() : Alias for sortBy()
.sortDescendingBy() : Sorts by given property in descending order.
Internally, these result in an array.reduce()
operation.
.groupBy() : Groups the result by the passed property. Returns array.
.sum() : Reduces to the sum of the given property. Returns a numerical value.
.average() : Reduces to the average of the given property. Returns a numerical value.
.expectOne() : Returns the only item in the array. If array has more than one item, throws.
.expectMany() : Returns array. If array has no items or one item, throws.
.expectNone() : Returns null. If array is not empty, throws.
.expect(n) : Returns the array with N items. If array.length !== n, throws.
require('@small-tech/whatdb')
const people = [
{ name: 'Aral', pet: {type: 'dog', name: 'Oskar'}, likesToPlay: 'RimWorld' },
{ name: 'Laura', pet: {type: 'dog', name: 'Oskar'}, likesToPlay: 'Dishonored 2'}
]
let person
person = people
.where('name')
.is('Laura')
.and('pet.name')
.is('Oskar')
.get()
// Returns [ { name: 'Laura', pet: {type: 'dog', name: 'Oskar'}, likesToPlay: 'Dishonored 2'} ]
try {
person = people.where('pet.type').is('dog').and('likesToPlay').includes('World').get('name').expectOne()
} catch (error) {
// e.g., if there is more than one.
console.log(`Query error: ${error}`)
}
// Returns: {name: 'Aral'}
// With get('name.value') instead, would return the string value: 'Aral'
Hey, @der-On, appreciate the thoughts :)
One thing I want to avoid is having functions within the syntax. Mostly because, given that queries return plain old JavaScript arrays, if you need to do anything more complicated, you can go directly to custom logic. I think that’s a good place to draw the boundary: the interface exists to support basic, everyday “80%” work and anything more complicated, just chain your own custom function and use lower-level primitives for finer grained control/expressiveness.
Will check it out; thanks :)