Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion builder/codegen.js
Original file line number Diff line number Diff line change
Expand Up @@ -437,7 +437,7 @@ function generateIndexKeyEncoding(type) {
const component = type.keyEncoding[i]

const keyType = type.builder.schema.types.get(`@${type.namespace}/${component}`)
if (keyType?.isEnum) str += ' IndexEncoder.UINT'
if (keyType?.isEnum) str += keyType.strings ? ' IndexEncoder.STRING' : ' IndexEncoder.UINT'
else str += ' ' + IndexTypeMap.get(component)

if (i !== type.keyEncoding.length - 1) str += ',\n'
Expand Down
21 changes: 21 additions & 0 deletions test/basic.js
Original file line number Diff line number Diff line change
Expand Up @@ -607,3 +607,24 @@ test('enum as key type', async function ({ create, bee }, t) {

await db.close()
})

test('enum with strings: true as key type', async function ({ create }, t) {
const db = await create({ fixture: 8 })

await db.insert('@db/tasks', { project: 'alpha', status: 'pending', name: 'task1' })
await db.insert('@db/tasks', { project: 'alpha', status: 'active', name: 'task2' })
await db.insert('@db/tasks', { project: 'beta', status: 'completed', name: 'task3' })
await db.flush()

{
const task = await db.get('@db/tasks', { project: 'alpha', status: 'pending', name: 'task1' })
t.alike(task, { project: 'alpha', status: 'pending', name: 'task1' })
}

{
const all = await db.find('@db/tasks').toArray()
t.is(all.length, 3)
}

await db.close()
})
50 changes: 50 additions & 0 deletions test/fixtures/builders/8.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
const HyperDB = require('../../../builder')
const Hyperschema = require('hyperschema')
const path = require('path')

const SCHEMA_DIR = path.join(__dirname, '../generated/8/hyperschema')
const DB_DIR = path.join(__dirname, '../generated/8/hyperdb')

const schema = Hyperschema.from(SCHEMA_DIR)

const dbSchema = schema.namespace('db')

dbSchema.register({
name: 'status',
enum: ['pending', 'active', 'completed'],
strings: true
})

dbSchema.register({
name: 'task',
fields: [
{
name: 'project',
type: 'string',
required: true
},
{
name: 'status',
type: '@db/status',
required: true
},
{
name: 'name',
type: 'string',
required: true
}
]
})

Hyperschema.toDisk(schema)

const db = HyperDB.from(SCHEMA_DIR, DB_DIR)
const testDb = db.namespace('db')

testDb.collections.register({
name: 'tasks',
schema: '@db/task',
key: ['project', 'status', 'name']
})

HyperDB.toDisk(db)
1 change: 1 addition & 0 deletions test/fixtures/generate.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ require('./builders/4.js')
require('./builders/5.js')
require('./builders/6.js')
require('./builders/7.js')
require('./builders/8.js')
23 changes: 23 additions & 0 deletions test/fixtures/generated/8/hyperdb/db.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"version": 1,
"offset": 0,
"schema": [
{
"name": "tasks",
"namespace": "db",
"id": 0,
"type": 1,
"version": 1,
"versionField": null,
"indexes": [],
"schema": "@db/task",
"derived": false,
"key": [
"project",
"status",
"name"
],
"trigger": null
}
]
}
115 changes: 115 additions & 0 deletions test/fixtures/generated/8/hyperdb/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
// This file is autogenerated by the hyperdb compiler
/* eslint-disable camelcase */

const { IndexEncoder, c, b4a } = require('hyperdb/runtime')
const { version, getEncoding, setVersion } = require('./messages.js')

const versions = { schema: version, db: 1 }

// '@db/tasks' collection key
const collection0_key = new IndexEncoder([
IndexEncoder.STRING,
IndexEncoder.STRING,
IndexEncoder.STRING
], { prefix: 0 })

function collection0_indexify (record) {
const arr = []

const a0 = record.project
if (a0 === undefined) return arr
arr.push(a0)

const a1 = record.status
if (a1 === undefined) return arr
arr.push(a1)

const a2 = record.name
if (a2 === undefined) return arr
arr.push(a2)

return arr
}

// '@db/tasks' value encoding
const collection0_enc = getEncoding('@db/task/hyperdb#0')

// '@db/tasks' reconstruction function
function collection0_reconstruct (schemaVersion, keyBuf, valueBuf) {
const key = collection0_key.decode(keyBuf)
setVersion(schemaVersion)
const state = { start: 0, end: valueBuf.byteLength, buffer: valueBuf }
const type = c.uint.decode(state)
if (type !== 0) throw new Error('Unknown collection type: ' + type)
collection0.decodedVersion = c.uint.decode(state)
const record = collection0_enc.decode(state)
record.project = key[0]
record.status = key[1]
record.name = key[2]
return record
}
// '@db/tasks' key reconstruction function
function collection0_reconstruct_key (keyBuf) {
const key = collection0_key.decode(keyBuf)
return {
project: key[0],
status: key[1],
name: key[2]
}
}

// '@db/tasks'
const collection0 = {
name: '@db/tasks',
id: 0,
version: 1,
encodeKey (record) {
const key = [record.project, record.status, record.name]
return collection0_key.encode(key)
},
encodeKeyRange ({ gt, lt, gte, lte } = {}) {
return collection0_key.encodeRange({
gt: gt ? collection0_indexify(gt) : null,
lt: lt ? collection0_indexify(lt) : null,
gte: gte ? collection0_indexify(gte) : null,
lte: lte ? collection0_indexify(lte) : null
})
},
encodeValue (schemaVersion, collectionVersion, record) {
setVersion(schemaVersion)
const state = { start: 0, end: 2, buffer: null }
collection0_enc.preencode(state, record)
state.buffer = b4a.allocUnsafe(state.end)
state.buffer[state.start++] = 0
state.buffer[state.start++] = collectionVersion
collection0_enc.encode(state, record)
return state.buffer
},
trigger: null,
reconstruct: collection0_reconstruct,
reconstructKey: collection0_reconstruct_key,
indexes: [],
decodedVersion: 0
}

const collections = [
collection0
]

const indexes = [
]

module.exports = { versions, collections, indexes, resolveCollection, resolveIndex }

function resolveCollection (name) {
switch (name) {
case '@db/tasks': return collection0
default: return null
}
}

function resolveIndex (name) {
switch (name) {
default: return null
}
}
160 changes: 160 additions & 0 deletions test/fixtures/generated/8/hyperdb/messages.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
// This file is autogenerated by the hyperschema compiler
// Schema Version: 1
/* eslint-disable camelcase */
/* eslint-disable quotes */
/* eslint-disable space-before-function-paren */

const { c } = require('hyperschema/runtime')

const VERSION = 1

// eslint-disable-next-line no-unused-vars
let version = VERSION

const encoding0_enum = {
pending: 'pending',
active: 'active',
completed: 'completed'
}

// @db/status enum
const encoding0 = {
preencode (state, m) {
state.end++ // max enum is 3 so always one byte
},
encode (state, m) {
switch (m) {
case 'pending':
c.uint.encode(state, 1)
break
case 'active':
c.uint.encode(state, 2)
break
case 'completed':
c.uint.encode(state, 3)
break
default:
throw new Error('Unknown enum')
}
},
decode (state) {
switch (c.uint.decode(state)) {
case 1:
return 'pending'
case 2:
return 'active'
case 3:
return 'completed'
default: return null
}
}
}

// @db/task
const encoding1 = {
preencode(state, m) {
c.string.preencode(state, m.project)
encoding0.preencode(state, m.status)
c.string.preencode(state, m.name)
},
encode(state, m) {
c.string.encode(state, m.project)
encoding0.encode(state, m.status)
c.string.encode(state, m.name)
},
decode(state) {
const r0 = c.string.decode(state)
const r1 = encoding0.decode(state)
const r2 = c.string.decode(state)

return {
project: r0,
status: r1,
name: r2
}
}
}

// @db/task/hyperdb#0
const encoding2 = {
preencode(state, m) {

},
encode(state, m) {

},
decode(state) {
return {
project: null,
status: null,
name: null
}
}
}

function setVersion(v) {
version = v
}

function encode(name, value, v = VERSION) {
version = v
return c.encode(getEncoding(name), value)
}

function decode(name, buffer, v = VERSION) {
version = v
return c.decode(getEncoding(name), buffer)
}

function getEnum(name) {
switch (name) {
case '@db/status':
return encoding0_enum
default:
throw new Error('Enum not found ' + name)
}
}

function getEncoding(name) {
switch (name) {
case '@db/status':
return encoding0
case '@db/task':
return encoding1
case '@db/task/hyperdb#0':
return encoding2
default:
throw new Error('Encoder not found ' + name)
}
}

function getStruct(name, v = VERSION) {
const enc = getEncoding(name)
return {
preencode(state, m) {
version = v
enc.preencode(state, m)
},
encode(state, m) {
version = v
enc.encode(state, m)
},
decode(state) {
version = v
return enc.decode(state)
}
}
}

const resolveStruct = getStruct // compat

module.exports = {
resolveStruct,
getStruct,
getEnum,
getEncoding,
encode,
decode,
setVersion,
version
}
Loading