Skip to content

Commit

Permalink
feat: Add mock db driver & collect:drivers scripts
Browse files Browse the repository at this point in the history
  • Loading branch information
codinsonn committed Jun 28, 2024
1 parent e97ee50 commit 1a8784d
Show file tree
Hide file tree
Showing 21 changed files with 494 additions and 12 deletions.
5 changes: 5 additions & 0 deletions features/@app-core/appConfig.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import Constants from 'expo-constants'
import { Platform } from 'react-native'
import { DRIVER_OPTIONS, createDriverConfig } from '@app/registries/drivers.config'

/* --- Notes ----------------------------------------------------------------------------------- */

Expand Down Expand Up @@ -33,6 +34,10 @@ export const appConfig = {
graphURL: process.env.NEXT_PUBLIC_GRAPH_URL || process.env.EXPO_PUBLIC_GRAPH_URL || `${fallbackBaseURL}/api/graphql`, // prettier-ignore
// - Secrets -
appSecret: process.env.APP_SECRET || process.env.APP_SECRET,
// - Drivers -
drivers: createDriverConfig({
db: DRIVER_OPTIONS.db.mockDB,
}),
} as const

/* --- Debug ----------------------------------------------------------------------------------- */
Expand Down
21 changes: 21 additions & 0 deletions features/@app-core/models/Settings.model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { z, schema } from '@green-stack/schemas'
import { createSchemaModel } from '@db/driver'

/* --- Schema ---------------------------------------------------------------------------------- */

export const Setting = schema('Setting', {
key: z.string().addMeta({ isID: true }),
value: z.any()
})

/* --- Types ----------------------------------------------------------------------------------- */

export type Setting = z.infer<typeof Setting>

/* --- Model ----------------------------------------------------------------------------------- */

export const SettingsModel = createSchemaModel(Setting)

/* --- Drivers --------------------------------------------------------------------------------- */

export const driverModel = SettingsModel.driver
43 changes: 42 additions & 1 deletion features/@app-core/resolvers/healthCheck.resolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import type { NextRequest } from 'next/server'
import { createResolver } from '@green-stack/schemas/createResolver'
import { appConfig } from '../appConfig'
import { healthCheckBridge } from './healthCheck.bridge'
import { Settings } from '@db/models'
import { DRIVER_KEYS } from '@app/registries/drivers.config'

/* --- Constants ------------------------------------------------------------------------------- */

Expand All @@ -29,6 +31,45 @@ export const healthCheck = createResolver(async ({ args, req, context }) => {
const requestURL = r?.url || `${requestProtocol}://${requestHost}/api/health`
const { baseURL, backendURL, apiURL, graphURL } = appConfig

// -- Context --

const extraContext = { requestContext: headerContext, drivers: {} } as ObjectType<any$Unknown>

const addDriverStatus = (
driverName: DRIVER_KEYS,
driverType = 'UNKNOWN',
status: 'OK' | 'NOK' | 'NONE',
) => {
extraContext.drivers[driverName] = {
type: driverType,
status,
}
}

// -- Test DB Driver --

try {

const hasDbDriverSetting = !!(await Settings.findMany({ key: 'dbDriver' })).length

if (!hasDbDriverSetting) {
await Settings.createOne({
key: 'dbDriver',
value: appConfig.drivers.db,
})
}

const dbDriverSetting = await Settings.findOne({ key: 'dbDriver' })
const dbDriverValue = dbDriverSetting?.value || 'NONE'
addDriverStatus('db', dbDriverValue, dbDriverValue ? 'OK' : 'NOK')

} catch (error) {

console.error('Error testing DB driver:', error)
addDriverStatus('db', appConfig.drivers.db, 'NOK')

}

// -- Respond --

return {
Expand Down Expand Up @@ -64,6 +105,6 @@ export const healthCheck = createResolver(async ({ args, req, context }) => {
systemTotalMemory: OS.totalmem(),
systemLoadAverage: OS.loadavg(),
// CONTEXT
context: showContext ? headerContext : undefined,
context: showContext ? extraContext : undefined,
}
}, healthCheckBridge)
3 changes: 3 additions & 0 deletions features/@app-core/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@
"@green-stack/styles/*": ["../../packages/@green-stack-core/styles/*"],
"@green-stack/navigation/*": ["../../packages/@green-stack-core/navigation/*"],
"@green-stack/context/*": ["../../packages/@green-stack-core/context/*"],
"@green-stack/scripts/*": ["../../packages/@green-stack-core/scripts/*"],
"@db/models": ["../../packages/@db-driver/models.ts"],
"@db/mock": ["../../packages/@db-driver/drivers/mock.db.ts"]
}
},
"include": [
Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
"check:workspaces": "npx turbo run @green-stack/core#check:workspaces",
"collect:generators": "npx turbo run @green-stack/core#collect:generators",
"collect:resolvers": "npx turbo run @green-stack/core#collect:resolvers",
"collect:drivers": "npx turbo run @green-stack/core#collect:drivers",
"collect:models": "npx turbo run @db/driver#collect:models",
"link:routes": "npx turbo run @green-stack/core#link:routes",
"add:dependencies": "npx turbo run @app-expo#add-dependencies",
"env:local": "npx turbo run env:local",
Expand Down
11 changes: 11 additions & 0 deletions packages/@db-driver/drivers/mock.db.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { validateDriver } from '../utils/validateDriver.db'

/* --- Import Driver Methods ------------------------------------------------------------------- */

import { createSchemaModel } from '../utils/createSchemaModel.mock'

/* --- Driver Validation ----------------------------------------------------------------------- */

export const driver = validateDriver({
createSchemaModel,
})
14 changes: 14 additions & 0 deletions packages/@db-driver/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { dbDrivers } from '@app/registries/drivers.generated'
import { appConfig } from '@app/config'

/* --- Determine Main DB driver ---------------------------------------------------------------- */

const dbDriver = dbDrivers[appConfig.drivers.db]

/* --- Re-export Driver Methods ---------------------------------------------------------------- */

export const createSchemaModel = dbDriver['createSchemaModel']

/* --- Export Driver Helpers ------------------------------------------------------------------- */

export { validateDriver } from './utils/validateDriver.db'
3 changes: 3 additions & 0 deletions packages/@db-driver/models.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
/* --- Re-export Driver Models ----------------------------------------------------------------- */

export * from '@app/registries/models.generated'
7 changes: 5 additions & 2 deletions packages/@db-driver/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
"name": "@db/driver",
"version": "0.0.1",
"description": "Database Driver & types to create DB drivers with ease. Falls back to mock memory DB if no driver is provided.",
"scripts": {},
"dependencies": {}
"dependencies": {},
"scripts": {
"collect:models": "npm -w @green-stack/core run run:script ../../packages/@db-driver/scripts/collect-models.ts",
"collect:drivers": "npm -w @green-stack/core run run:script ../../packages/@green-stack-core/scripts/collect-drivers.ts"
}
}
96 changes: 96 additions & 0 deletions packages/@db-driver/scripts/collect-models.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import glob from 'glob'
import fs from 'fs'
import { addSetItem } from '@green-stack/utils/arrayUtils'
import { parseWorkspaces, replaceMany } from '@green-stack/scripts/helpers/scriptUtils'

/* --- models.generated.ts --------------------------------------------------------------------- */

const modelsFileTemplate = `// -i- Auto generated with "npx turbo run @db/driver#collect-models"
{{modelImportLines}}
/* --- Reexports ------------------------------------------------------------------------------- */
export {
{{modelModuleAliasLines}}
}
/* --- Models ---------------------------------------------------------------------------------- */
const dbModels = {
{{modelModuleAliasLines}}
}
/* --- Exports --------------------------------------------------------------------------------- */
export type DB_MODEL = keyof typeof dbModels
export default dbModels
`

/* --- Types ----------------------------------------------------------------------------------- */

type ModelRegistry = {
modelImportLines: string[],
modelAliasEntryLines: string[],
}

/* --- collect-models -------------------------------------------------------------------------- */

const collectModels = () => {
try {
// Get all model file paths in /features/ & /packages/ workspaces
const featureModelPaths = glob.sync('../../features/**/models/*.model.ts')
const packageModelPaths = glob.sync('../../packages/**/models/*.model.ts')
const allModelPaths = [...featureModelPaths, ...packageModelPaths]

// Figure out import paths from each workspace
const { workspaceImports } = parseWorkspaces()

// Build overview of lines to build model registry files with
const modelRegistry = allModelPaths.reduce((acc, modelFilePath) => {

// Skip if not a valid model
const modelFileContents = fs.readFileSync(modelFilePath, 'utf-8')
const isValidModel = modelFileContents.includes('export const driverModel = ')
if (!isValidModel) return acc

// Figure out model workspace from filename
const workspaceEntry = Object.entries(workspaceImports).find(([pathKey]) => {
return modelFilePath.includes(pathKey)
})

// Figure out model name from filename
const [workspacePath, modelWorkspace] = workspaceEntry!
const innerModelFilePath = modelFilePath.split(workspacePath)[1]
const modelFilename = innerModelFilePath.replace('/models/', '')
const modelFileModuleName = modelFilename.replace('.tsx', '').replace('.ts', '')
const [modelName] = modelFileModuleName.split('.')
const modelImportPath = `${modelWorkspace}/models/${modelFileModuleName}`
const modelImportLine = `import { driverModel as ${modelName} } from '${modelImportPath}'` // prettier-ignore
const modelModuleAliasLine = ` ${modelName}`

// Add to the accumulator
return {
modelImportLines: addSetItem(acc.modelImportLines, modelImportLine),
modelAliasEntryLines: addSetItem(acc.modelAliasEntryLines, modelModuleAliasLine),
}

}, {} as ModelRegistry)

// Build models.generated.ts file
const modelModuleAliasLines = modelRegistry.modelAliasEntryLines.join('\n,')
const modelImportLines = modelRegistry.modelImportLines.join('\n')
let modelsFileContent = modelsFileTemplate.replace('{{modelImportLines}}', modelImportLines) // prettier-ignore
modelsFileContent = replaceMany(modelsFileContent, [' {{modelModuleAliasLines}}'], modelModuleAliasLines) // prettier-ignore
fs.writeFileSync('../../packages/@registries/models.generated.ts', modelsFileContent)

} catch (err) {
console.log(err)
console.error(err)
process.exit(1)
}
}

/* --- init ------------------------------------------------------------------------------------ */

collectModels()
3 changes: 3 additions & 0 deletions packages/@db-driver/utils/createSchemaModel.mock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { z } from '@green-stack/schemas'
import { warnOnce } from '@green-stack/utils/commonUtils'
import { getProperty } from '@green-stack/utils/objectUtils'
import { memoryDB } from '../constants/memoryDB.mock'
import http from 'http'

/* --- Constants ------------------------------------------------------------------------------- */

Expand Down Expand Up @@ -58,6 +59,8 @@ export const createSchemaModel = <
warnOnce(`-!- Model "${modelKey}" already exists in memory DB. Skipping recreation from createSchemaModel()`) // prettier-ignore
}

http.createServer()

/** --- matchesCondition() ----------------------------------------------------------------- */
/** -i- Checks whether mongo-like condition matching keys `$eq`, `$ne`, `$gt`, `$gte`, `$lt`, `$lte`, `$in`, `$nin` match the query */
const matchesCondition = (value: DataType[keyof DataType], condition: QueryFilter[keyof QueryFilter]): boolean => {
Expand Down
21 changes: 21 additions & 0 deletions packages/@db-driver/utils/validateDriver.db.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { z } from '@green-stack/schemas'

/* --- Schema ---------------------------------------------------------------------------------- */

export const DbDriverSchema = z.object({
createSchemaModel: z.function().args(
z.instanceof(z.ZodObject<z.ZodRawShape>),
z.string().optional(),
),
})

/* --- Types ----------------------------------------------------------------------------------- */

export type DbDriverShape = z.infer<typeof DbDriverSchema>

/** --- validateDriver() ----------------------------------------------------------------------- */
/** -i- Validates whether a DB driver matches the expected methods */
export const validateDriver = <DB_DRIVER extends DbDriverShape>(driver: DB_DRIVER) => {
DbDriverSchema.parse(driver)
return driver
}
12 changes: 7 additions & 5 deletions packages/@green-stack-core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,13 @@
"typescript": "5.3.3"
},
"scripts": {
"build:schema": "tsx --tsconfig ./tsconfig.scripts.json ./run-script.js ./scripts/build-graphql-schema.ts",
"check:workspaces": "tsx --tsconfig ./tsconfig.scripts.json ./run-script.js ./scripts/check-workspaces.ts",
"collect:resolvers": "tsx --tsconfig ./tsconfig.scripts.json ./run-script.js ./scripts/collect-resolvers.ts",
"collect:generators": "tsx --tsconfig ./tsconfig.scripts.json ./run-script.js ./scripts/collect-generators.ts",
"link:routes": "tsx --tsconfig ./tsconfig.scripts.json ./run-script.js ./scripts/link-routes.ts",
"run:script": "tsx --tsconfig ./tsconfig.scripts.json ./run-script.js",
"build:schema": "npm run run:script ./scripts/build-graphql-schema.ts",
"check:workspaces": "npm run run:script ./scripts/check-workspaces.ts",
"collect:resolvers": "npm run run:script ./scripts/collect-resolvers.ts",
"collect:generators": "npm run run:script ./scripts/collect-generators.ts",
"collect:drivers": "npm run run:script ../../packages/@green-stack-core/scripts/collect-drivers.ts",
"link:routes": "npm run run:script ./scripts/link-routes.ts",
"test": "cd ../../ && bun test --tsconfig-override ./packages/@green-stack-core/tsconfig.json --preload ./packages/@green-stack-core/preload.test.ts --verbose"
}
}
Loading

0 comments on commit 1a8784d

Please sign in to comment.