Skip to content

Commit

Permalink
Replace nedb with fork @seald-io/nedb
Browse files Browse the repository at this point in the history
  • Loading branch information
gonzalojaubert committed Nov 27, 2023
1 parent 10dee0a commit 49898d2
Show file tree
Hide file tree
Showing 12 changed files with 82 additions and 170 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,19 @@ import { ApolloClient, NormalizedCacheObject } from '@apollo/client'
import { changeCartItem, graphQLClient } from './utils'
import { random } from 'faker'
import { expect } from 'chai'
import * as DataStore from 'nedb'
import Datastore from '@seald-io/nedb'
import { sandboxPath } from './constants'
import * as util from 'util'
import * as path from 'path'
import { waitForIt } from '../../helper/sleep'

describe('commands', () => {
let events: DataStore<unknown>
let events: Datastore<unknown>

let client: ApolloClient<NormalizedCacheObject>

before(async () => {
events = new DataStore(path.join(sandboxPath, '.booster', 'events.json'))
events = new Datastore(path.join(sandboxPath, '.booster', 'events.json'))
client = await graphQLClient()
})

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,18 @@ import { ApolloClient, NormalizedCacheObject } from '@apollo/client'
import { changeCartItem, graphQLClient } from './utils'
import { random } from 'faker'
import { expect } from 'chai'
import * as DataStore from 'nedb'
import Datastore from '@seald-io/nedb'
import { sandboxPath } from './constants'
import * as path from 'path'
import { waitForIt } from '../../helper/sleep'

describe('read-models', () => {
let readModels: DataStore<unknown>
let readModels: Datastore<unknown>

let client: ApolloClient<NormalizedCacheObject>

before(async () => {
readModels = new DataStore(path.join(sandboxPath, '.booster', 'read_models.json'))
readModels = new Datastore(path.join(sandboxPath, '.booster', 'read_models.json'))
client = await graphQLClient()
})

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { ApolloClient, NormalizedCacheObject, gql } from '@apollo/client'
import { commerce, finance, random } from 'faker'
import { expect } from 'chai'
import { expect } from '../../helper/expect'
import { applicationUnderTest } from './setup'

describe('Commands end-to-end tests', () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/* eslint-disable @typescript-eslint/ban-ts-comment */
import { ApolloClient, NormalizedCacheObject, gql } from '@apollo/client'
import { commerce, finance, internet, lorem, random } from 'faker'
import { expect } from 'chai'
import { expect } from '../../helper/expect'
import { waitForIt } from '../../helper/sleep'
import { CartItem } from '../../../src/common/cart-item'
import { applicationUnderTest } from './setup'
Expand Down Expand Up @@ -179,12 +179,7 @@ describe('Read models end-to-end tests', () => {
await Promise.all(changeCartPromises)
})

// TODO this test is failing in local because of local provider doesn't provides optimistic concurrency control
// TODO Remove condition when it will be fixed
it('should retrieve expected cart', async () => {
if (process.env.TESTED_PROVIDER === 'LOCAL') {
return
}
const queryResult = await waitForIt(
() => {
return client.query({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ describe('subscriptions', () => {
})
})
})

context('with a user without the required role', () => {
let loggedClient: DisconnectableApolloClient

Expand Down
6 changes: 3 additions & 3 deletions packages/framework-integration-tests/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@
"jwks-rsa": "3.0.1",
"mocha": "10.2.0",
"mocha-skip-if": "0.0.3",
"nedb": "^1.8.0",
"@seald-io/nedb": "4.0.2",
"nyc": "^15.1.0",
"prettier": "2.3.0",
"rimraf": "^5.0.0",
Expand Down Expand Up @@ -100,9 +100,9 @@
"integration/aws-end-to-end": "TS_NODE_PROJECT=\"./tsconfig.integration.json\" TESTED_PROVIDER=AWS AWS_SDK_LOAD_CONFIG=true BOOSTER_ENV=production mocha --forbid-only --exit --config \"integration/provider-unaware/end-to-end/.mocharc.yml\" \"integration/provider-unaware/end-to-end/**/*.integration.ts\"",
"integration/aws-load": "echo 'Skipping integration tests.' # TS_NODE_PROJECT=\"./tsconfig.integration.json\" TESTED_PROVIDER=AWS AWS_SDK_LOAD_CONFIG=true BOOSTER_ENV=production mocha --forbid-only --exit --config \"integration/provider-unaware/load/.mocharc.yml\" \"integration/provider-unaware/load/**/*.load.ts\"",
"integration/aws-nuke": "TS_NODE_PROJECT=\"./tsconfig.integration.json\" AWS_SDK_LOAD_CONFIG=true BOOSTER_ENV=production mocha --forbid-only --exit --config \"integration/provider-specific/aws/nuke/.mocharc.yml\" \"integration/provider-specific/aws/nuke/**/*.integration.ts\"",
"integration/local": "TS_NODE_PROJECT=\"./tsconfig.integration.json\" BOOSTER_ENV=local mocha --forbid-only --exit --config \"integration/provider-specific/local/.mocharc.yml\" \"integration/provider-specific/local/**/*.integration.ts\"",
"integration/local": "TS_NODE_PROJECT=\"./tsconfig.integration.json\" npm run integration/local-start && npm run integration/local-end-to-end && npm run integration/local-stop",
"integration/local-ongoing": "TS_NODE_PROJECT=\"./tsconfig.integration.json\" npm run integration/local-start && npm run integration/local-stop",
"integration/local-start": "TS_NODE_PROJECT=\"./tsconfig.integration.json\" BOOSTER_ENV=local mocha --forbid-only --exit --config \"integration/provider-specific/local/start/.mocharc.yml\" \"integration/provider-specific/local/start/*.integration.ts\"",
"integration/local-start": "TS_NODE_PROJECT=\"./tsconfig.integration.json\" BOOSTER_ENV=local mocha --forbid-only --config \"integration/provider-specific/local/start/.mocharc.yml\" \"integration/provider-specific/local/start/*.integration.ts\"",
"integration/local-func": "TS_NODE_PROJECT=\"./tsconfig.integration.json\" TESTED_PROVIDER=LOCAL BOOSTER_ENV=local mocha --forbid-only --exit --config \"integration/provider-unaware/functionality/.mocharc.yml\" \"integration/provider-unaware/functionality/**/*.integration.ts\"",
"integration/local-end-to-end": "TS_NODE_PROJECT=\"./tsconfig.integration.json\" TESTED_PROVIDER=LOCAL BOOSTER_ENV=local mocha --forbid-only --exit --config \"integration/provider-unaware/end-to-end/.mocharc.yml\" \"integration/provider-unaware/end-to-end/**/*.integration.ts\"",
"integration/local-stop": "TS_NODE_PROJECT=\"./tsconfig.integration.json\" BOOSTER_ENV=local mocha --forbid-only --exit --config \"integration/provider-specific/local/stop/.mocharc.yml\" \"integration/provider-specific/local/stop/*.integration.ts\"",
Expand Down
3 changes: 1 addition & 2 deletions packages/framework-provider-local/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,7 @@
"dependencies": {
"@boostercloud/framework-common-helpers": "workspace:^2.2.0",
"@boostercloud/framework-types": "workspace:^2.2.0",
"@types/nedb": "^1.8.12",
"nedb": "^1.8.0",
"@seald-io/nedb": "4.0.2",
"tslib": "^2.4.0",
"@effect-ts/core": "^0.60.4",
"ws": "8.12.0"
Expand Down
52 changes: 16 additions & 36 deletions packages/framework-provider-local/src/services/event-registry.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
/* eslint-disable @typescript-eslint/ban-types */
import { EntitySnapshotEnvelope, EventEnvelope, EventStoreEntryEnvelope } from '@boostercloud/framework-types'
import * as DataStore from 'nedb'
import { eventsDatabase } from '../paths'
const DataStore = require('@seald-io/nedb')

export class EventRegistry {
public readonly events: DataStore<EventStoreEntryEnvelope> = new DataStore(eventsDatabase)
private readonly events

constructor() {
this.events.loadDatabase()
this.events = new DataStore({ filename: eventsDatabase, autoload: true })
}

getCursor(query: object, createdAt = 1, projections?: unknown) {
return this.events.find(query, projections).sort({ createdAt: createdAt })
const cursor = this.events.findAsync(query, projections)
return cursor.sort({ createdAt: createdAt })
}

public async query(
Expand All @@ -19,53 +21,31 @@ export class EventRegistry {
limit?: number,
projections?: unknown
): Promise<EventStoreEntryEnvelope[]> {
const cursor = this.getCursor(query, createdAt, projections)
let cursor = this.getCursor(query, createdAt, projections)
if (limit) {
cursor.limit(Number(limit))
cursor = cursor.limit(Number(limit))
}
const queryPromise = await new Promise<EventStoreEntryEnvelope[]>((resolve, reject) => {
cursor.exec((err, docs) => {
if (err) reject(err)
else resolve(docs)
})
})

return queryPromise
return await cursor.execAsync()
}

public async queryLatestSnapshot(query: object): Promise<EntitySnapshotEnvelope | undefined> {
const results = await new Promise<EventStoreEntryEnvelope[]>((resolve, reject) =>
this.events
.find({ ...query, kind: 'snapshot' })
.sort({ snapshottedEventCreatedAt: -1 }) // Sort in descending order (newer timestamps first)
.exec((err, docs) => {
if (err) reject(err)
else resolve(docs)
})
)

const cursor = this.events.findAsync({ ...query, kind: 'snapshot' }).sort({ snapshottedEventCreatedAt: -1 }) // Sort in descending order (newer timestamps first)
const results = await cursor.execAsync()
if (results.length <= 0) {
return undefined
}
return results[0] as EntitySnapshotEnvelope
}

public async store(storableObject: EventEnvelope | EntitySnapshotEnvelope): Promise<void> {
return new Promise((resolve, reject) => {
this.events.insert(storableObject, (err) => {
err ? reject(err) : resolve()
})
})
await this.events.insertAsync(storableObject)
}

public async deleteAll(): Promise<number> {
const deletePromise = new Promise((resolve, reject) =>
this.events.remove({}, { multi: true }, (err, numRemoved: number) => {
if (err) reject(err)
else resolve(numRemoved)
})
)
return await this.events.removeAsync({}, { multi: true })
}

return (await deletePromise) as number
public async count(query?: object): Promise<number> {
return await this.events.countAsync(query)
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { ReadModelEnvelope, SortFor, UUID } from '@boostercloud/framework-types'
import * as DataStore from 'nedb'
import { readModelsDatabase } from '../paths'
const DataStore = require('@seald-io/nedb')

interface LocalSortedFor {
[key: string]: number
Expand All @@ -11,9 +11,9 @@ export type NedbError = Error & { [key: string | number | symbol]: unknown }
export const UNIQUE_VIOLATED_ERROR_TYPE = 'uniqueViolated'

export class ReadModelRegistry {
public readonly readModels: DataStore<ReadModelEnvelope> = new DataStore(readModelsDatabase)
public readonly readModels
constructor() {
this.readModels.loadDatabase()
this.readModels = new DataStore({ filename: readModelsDatabase, autoload: true })
this.readModels.ensureIndex({ fieldName: 'uniqueKey', unique: true, sparse: true })
}

Expand All @@ -23,7 +23,7 @@ export class ReadModelRegistry {
skip?: number,
limit?: number
): Promise<Array<ReadModelEnvelope>> {
let cursor = this.readModels.find(query)
let cursor = this.readModels.findAsync(query)
const sortByList = this.toLocalSortFor(sortBy)
if (sortByList) {
cursor = cursor.sort(sortByList)
Expand All @@ -34,13 +34,7 @@ export class ReadModelRegistry {
if (limit) {
cursor = cursor.limit(limit)
}
const queryPromise = new Promise((resolve, reject) =>
cursor.exec((err, docs) => {
if (err) reject(err)
else resolve(docs)
})
)
return queryPromise as Promise<Array<ReadModelEnvelope>>
return await cursor.execAsync()
}

public async store(readModel: ReadModelEnvelope, expectedCurrentVersion: number): Promise<void> {
Expand All @@ -52,49 +46,33 @@ export class ReadModelRegistry {
return this.update(uniqueReadModel, expectedCurrentVersion)
}

private insert(readModel: ReadModelEnvelope): Promise<void> {
return new Promise((resolve, reject) => {
this.readModels.insert(readModel, (err: unknown) => {
err ? reject(err) : resolve()
})
})
private async insert(readModel: ReadModelEnvelope): Promise<void> {
await this.readModels.insertAsync(readModel)
}

private update(readModel: ReadModelEnvelope, expectedCurrentVersion: number): Promise<void> {
return new Promise((resolve, reject) => {
this.readModels.update(
{
typeName: readModel.typeName,
'value.id': readModel.value.id,
'value.boosterMetadata.version': expectedCurrentVersion,
},
readModel,
{ upsert: false, returnUpdatedDocs: true },
(err: unknown, numAffected: number) => {
if (numAffected === 0) {
const error: NedbError = new Error(
`Can't update readModel ${JSON.stringify(
readModel
)} with expectedCurrentVersion = ${expectedCurrentVersion} . Optimistic concurrency error`
) as NedbError
error.errorType = UNIQUE_VIOLATED_ERROR_TYPE
reject(error)
}
err ? reject(err) : resolve()
}
)
})
private async update(readModel: ReadModelEnvelope, expectedCurrentVersion: number): Promise<void> {
const { numAffected } = await this.readModels.updateAsync(
{
typeName: readModel.typeName,
'value.id': readModel.value.id,
'value.boosterMetadata.version': expectedCurrentVersion,
},
readModel,
{ upsert: false, returnUpdatedDocs: true }
)
if (numAffected === 0) {
const error: NedbError = new Error(
`Can't update readModel ${JSON.stringify(
readModel
)} with expectedCurrentVersion = ${expectedCurrentVersion} . Optimistic concurrency error`
) as NedbError
error.errorType = UNIQUE_VIOLATED_ERROR_TYPE
throw error
}
}

public async deleteById(id: UUID, typeName: string): Promise<number> {
const deletePromise = new Promise((resolve, reject) =>
this.readModels.remove({ typeName: typeName, 'value.id': id }, { multi: false }, (err, numRemoved: number) => {
if (err) reject(err)
else resolve(numRemoved)
})
)

return deletePromise as Promise<number>
return await this.readModels.removeAsync({ typeName: typeName, 'value.id': id }, { multi: false })
}

toLocalSortFor(
Expand Down
Loading

0 comments on commit 49898d2

Please sign in to comment.