The Memory adapter provides an in-memory service implementation for testing and rapid prototyping. Data is stored in memory and will be lost when the process exits.
Installation
npm install @feathersjs/memory
MemoryService
The main service class for in-memory operations.
Constructor
import { MemoryService, memory } from '@feathersjs/memory'
// Using the class
const service = new MemoryService<Result, Data, ServiceParams, PatchData>(options)
// Using the factory function
const service = memory<Result, Data, ServiceParams>(options)
Configuration options for the Memory adapterName of the id field property
Initial data store object with id as keys. Default is {}
Starting value for auto-generated ids
Pagination settings with default and max page size
Allow multiple updates. Can be true, false, or an array of method names
Custom query matcher function. Default uses sift
Custom sorting function. Default uses built-in sorter
Service Methods
find
Retrieve multiple records from memory.
await service.find(params?)
Query filters including $limit, $skip, $sort, $select, and comparison operators
paginate
PaginationOptions | false
Override pagination settings
result
Paginated<Result> | Result[]
Paginated results or array depending on settings
get
Retrieve a single record by id.
await service.get(id, params?)
The record id to retrieve
Additional query filters to match
create
Create one or more new records.
await service.create(data, params?)
Record data to create. If id is not provided, it will be auto-generated
update
Completely replace a record.
await service.update(id, data, params?)
Complete record data to replace with
patch
Partially update one or multiple records.
await service.patch(id, data, params?)
The record id to patch, or null to patch multiple records matching the query
Partial data to merge with existing record(s)
Query to filter which records to patch (when id is null)
remove
Remove one or multiple records.
await service.remove(id, params?)
The record id to remove, or null to remove multiple records
Query to filter which records to remove (when id is null)
MemoryAdapter
The base adapter class that MemoryService extends.
Properties
store
Direct access to the in-memory data store.
const allData = service.store
// { '0': { id: 0, name: 'Item 1' }, '1': { id: 1, name: 'Item 2' } }
Methods
getEntries
Retrieve all entries matching a query.
const entries = await service.getEntries(params?)
Array of all matching entries
Query Syntax
The Memory adapter supports MongoDB-style query syntax via the sift library.
Comparison Operators
// Equals
await service.find({
query: { status: 'active' }
})
// Greater than / less than
await service.find({
query: {
age: { $gt: 18 },
score: { $lte: 100 }
}
})
// In / not in array
await service.find({
query: {
role: { $in: ['admin', 'moderator'] },
status: { $nin: ['deleted', 'banned'] }
}
})
// Not equal
await service.find({
query: {
status: { $ne: 'deleted' }
}
})
Array Operators
// Element in array field
await service.find({
query: {
tags: { $elemMatch: { $eq: 'javascript' } }
}
})
// Array size
await service.find({
query: {
tags: { $size: 3 }
}
})
// All elements match
await service.find({
query: {
tags: { $all: ['javascript', 'nodejs'] }
}
})
Logical Operators
// $or queries
await service.find({
query: {
$or: [
{ status: 'active' },
{ role: 'admin' }
]
}
})
// $and queries
await service.find({
query: {
$and: [
{ age: { $gte: 18 } },
{ verified: true }
]
}
})
// $nor queries
await service.find({
query: {
$nor: [
{ status: 'deleted' },
{ banned: true }
]
}
})
Element Operators
// Field exists
await service.find({
query: {
email: { $exists: true }
}
})
// Type checking
await service.find({
query: {
age: { $type: 'number' }
}
})
Special Query Parameters
await service.find({
query: {
status: 'active',
$select: ['id', 'name', 'email'], // Select specific fields
$sort: { createdAt: -1, name: 1 }, // Sort descending, then ascending
$limit: 10, // Limit results
$skip: 20 // Skip first 20 results
}
})
Regular Expressions
// Pattern matching
await service.find({
query: {
email: { $regex: /.*@example\.com$/ }
}
})
Custom Matcher and Sorter
Provide custom query matching and sorting logic:
import { memory } from '@feathersjs/memory'
const service = memory({
matcher: (query) => {
// Custom matching logic
return (item) => {
if (query.customField) {
return item.customField === query.customField.toUpperCase()
}
return true
}
},
sorter: (sort) => {
// Custom sorting logic
return (a, b) => {
const field = Object.keys(sort)[0]
const direction = sort[field]
if (a[field] < b[field]) return -1 * direction
if (a[field] > b[field]) return 1 * direction
return 0
}
}
})
Example
import { memory, MemoryService } from '@feathersjs/memory'
interface Todo {
id?: number
text: string
completed: boolean
userId: number
}
// Using factory function
const todos = memory<Todo>({
id: 'id',
startId: 1,
paginate: {
default: 10,
max: 50
}
})
// Create todos
const todo1 = await todos.create({
text: 'Learn Feathers',
completed: false,
userId: 1
})
const todo2 = await todos.create({
text: 'Build an app',
completed: false,
userId: 1
})
// Find incomplete todos
const incomplete = await todos.find({
query: {
completed: false,
userId: 1
}
})
// Update a todo
await todos.patch(todo1.id, {
completed: true
})
// Complex query
const results = await todos.find({
query: {
$or: [
{ completed: true },
{ userId: 2 }
],
$sort: { id: -1 },
$limit: 5
}
})
// Bulk operations
await todos.patch(null,
{ completed: true },
{
query: { userId: 1 }
}
)
// Pre-populate with data
const preloadedService = new MemoryService<Todo>({
store: {
1: { id: 1, text: 'Existing todo', completed: false, userId: 1 },
2: { id: 2, text: 'Another todo', completed: true, userId: 1 }
},
startId: 3
})
Testing
The Memory adapter is ideal for testing:
import { memory } from '@feathersjs/memory'
import { strict as assert } from 'assert'
describe('User Service', () => {
let service: ReturnType<typeof memory>
beforeEach(() => {
service = memory()
})
it('creates a user', async () => {
const user = await service.create({
email: '[email protected]',
name: 'Test User'
})
assert.ok(user.id)
assert.equal(user.email, '[email protected]')
})
it('finds users by email', async () => {
await service.create({
email: '[email protected]',
name: 'Test User'
})
const results = await service.find({
query: { email: '[email protected]' }
})
assert.equal(results.length, 1)
})
})