Skip to content

[plugin]: orama schema from json schema #452

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 15 commits into from
Closed
57 changes: 57 additions & 0 deletions packages/schema/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
{
"name": "@orama/schema",
"version": "0.0.1",
"description": "Schema utilities for Orama",
"keywords": [
"orama",
"search",
"schema"
],
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/oramasearch/orama"
},
"bugs": {
"url": "https://github.com/oramasearch/orama"
},
"type": "module",
"sideEffects": false,
"main": "./dist/commonjs.cjs",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.js",
"require": "./dist/commonjs.cjs"
}
},
"types": "./dist/index.d.ts",
"files": [
"dist"
],
"scripts": {
"dev": "swc --delete-dir-on-start -s -w --extensions .ts,.cts -d dist src",
"build": "swc --delete-dir-on-start --extensions .ts,.cts -d dist src",
"postbuild": "tsc -p . --emitDeclarationOnly",
"test": "c8 -c test/config/c8.json tap --rcfile=test/config/tap.yml test/*.test.ts"
},
"dependencies": {
"@orama/orama": "workspace:*"
},
"devDependencies": {
"@swc/cli": "^0.1.59",
"@swc/core": "^1.3.27",
"@types/json-schema": "^7.0.12",
"@types/node": "^18.11.18",
"@types/tap": "^15.0.7",
"c8": "^7.12.0",
"tap": "^16.3.4",
"tsx": "^3.12.2",
"typescript": "^4.9.4"
},
"config": {
"commitizen": {
"path": "cz-conventional-changelog"
}
}
}
3 changes: 3 additions & 0 deletions packages/schema/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { schemaFromJson } from './jsonSchema.js'

export { schemaFromJson }
45 changes: 45 additions & 0 deletions packages/schema/src/jsonSchema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import type { Schema, SearchableType } from '@orama/orama';
import type { JSONSchema4 } from 'json-schema';

const isJsonObject = (jsonSchema: JSONSchema4) => jsonSchema.type === 'object'

const assertTypeObject = (jsonSchema: JSONSchema4) => {
if (!isJsonObject(jsonSchema)) {
throw new Error('Provided JSON schema must be an object type');
}
}

const ORAMA_SUPPORTED_TYPES: Set<JSONSchema4['type']> = new Set(['string', 'number', 'boolean'])

const isArraySupportedByOrama = (jsonSchema: JSONSchema4): boolean => {
if (jsonSchema.type === 'array' && jsonSchema.items && !Array.isArray(jsonSchema.items)) {
return ORAMA_SUPPORTED_TYPES.has(jsonSchema.items.type);
}
return false
}

const isSupportedByOrama = (jsonSchema: JSONSchema4): boolean => {
return ORAMA_SUPPORTED_TYPES.has(jsonSchema.type) || isArraySupportedByOrama(jsonSchema);
}

const extractOramaType = (jsonSchema: JSONSchema4): SearchableType => {
const oramaType = ORAMA_SUPPORTED_TYPES.has(jsonSchema.type) ? jsonSchema.type : `${(jsonSchema.items as JSONSchema4)!.type}[]`

return oramaType as SearchableType
}

export const schemaFromJson = (jsonSchema: JSONSchema4) => {
assertTypeObject(jsonSchema)

const oramaSchema: Schema = {}

for (const [propertyName, propertyDefinition] of Object.entries(jsonSchema.properties || {})) {
if (isSupportedByOrama(propertyDefinition)) {
oramaSchema[propertyName] = extractOramaType(propertyDefinition)
} else if (isJsonObject(propertyDefinition)) {
oramaSchema[propertyName] = schemaFromJson(propertyDefinition)
}
}

return oramaSchema;
}
8 changes: 8 additions & 0 deletions packages/schema/test/config/c8.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"check-coverage": true,
"reporter": ["text", "json"],
"branches": 80,
"functions": 80,
"lines": 80,
"statements": 80
}
8 changes: 8 additions & 0 deletions packages/schema/test/config/tap.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
jobs: 5
timeout: 120
reporter: spec
coverage: false
node-arg:
- --loader=tsx
- --no-warnings=loader
Loading