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 Jul 26, 2023
1 parent 63745a4 commit 53d5270
Show file tree
Hide file tree
Showing 13 changed files with 165 additions and 263 deletions.
175 changes: 83 additions & 92 deletions common/config/rush/pnpm-lock.yaml

Large diffs are not rendered by default.

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
7 changes: 3 additions & 4 deletions packages/framework-integration-tests/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@
"@types/faker": "5.1.5",
"@types/jsonwebtoken": "^8.5.8",
"@types/mocha": "8.2.2",
"@types/nedb": "^1.8.12",
"@types/node": "16.11.7",
"@types/sinon": "10.0.0",
"@types/sinon-chai": "3.2.5",
Expand All @@ -64,7 +63,7 @@
"jwks-rsa": "2.0.3",
"mocha": "8.4.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 +99,9 @@
"integration/aws-end-to-end": "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.' # 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": "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": "BOOSTER_ENV=local mocha --forbid-only --exit --config \"integration/provider-specific/local/.mocharc.yml\" \"integration/provider-specific/local/**/*.integration.ts\"",
"integration/local": "npm run integration/local-start && npm run integration/local-end-to-end && npm run integration/local-stop",
"integration/local-ongoing": "npm run integration/local-start && npm run integration/local-stop",
"integration/local-start": "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": "BOOSTER_ENV=local mocha --forbid-only --config \"integration/provider-specific/local/start/.mocharc.yml\" \"integration/provider-specific/local/start/*.integration.ts\"",
"integration/local-func": "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": "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": "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 @@ -22,8 +22,7 @@
"dependencies": {
"@boostercloud/framework-common-helpers": "workspace:^1.18.1",
"@boostercloud/framework-types": "workspace:^1.18.1",
"@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 })
}

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 53d5270

Please sign in to comment.