@chickyky/arangoose-adminjs-adapter
v0.0.5
Published
AdminJS database adapter for arangoose (ArangoDB)
Downloads
176
Readme
@arangoose/adminjs-adapter
AdminJS v7 database adapter for arangoose. Register it once and pass arangoose models straight to AdminJS as resources.
Install
Not published to npm — consumed through the workspace:
// your app's package.json
"dependencies": {
"arangoose": "workspace:*",
"@arangoose/adminjs-adapter": "workspace:*"
}adminjs (^7.0.0) is a peer dependency.
Node >= 20.19 required. AdminJS v7 is ESM-only and this adapter is built as CommonJS, so it relies on require() of an ES module — unflagged in Node 20.19 / 22.12 and later.
Setup
import AdminJS from 'adminjs';
import AdminJSExpress from '@adminjs/express';
import express from 'express';
import { connect } from 'arangoose';
import * as AdminJSArangoose from '@arangoose/adminjs-adapter';
import { UserModel, PostModel } from './models';
AdminJS.registerAdapter({
Database: AdminJSArangoose.Database,
Resource: AdminJSArangoose.Resource,
});
await connect({
url: process.env.ARANGO_URL!,
database: process.env.ARANGO_DB!,
username: process.env.ARANGO_USER,
password: process.env.ARANGO_PASSWORD,
});
await UserModel.ensureCollection();
await PostModel.ensureCollection();
const admin = new AdminJS({
rootPath: '/admin',
resources: [
{ resource: UserModel, options: { navigation: { name: 'Data' } } },
{ resource: PostModel },
],
});
const app = express();
app.use(admin.options.rootPath, AdminJSExpress.buildRouter(admin));
app.listen(3000);Pass models via resources (recommended — it accepts per-resource options), or via databases, where each model expands to its single resource:
const admin = new AdminJS({ databases: [UserModel, PostModel] });What gets mapped
Properties
Built from the schema definition. _key, _id and _rev are prepended and are not editable; _key is the record id AdminJS uses in URLs.
| Schema field | AdminJS property type |
| ---------------------------- | --------------------- |
| String | string |
| Number | float |
| Boolean | boolean |
| Date | datetime |
| Array, Object, 'Mixed' | mixed |
| { ref: 'Model' } | reference |
Also carried over:
required: true→isRequired()enum: [...]→availableValues(), which AdminJS renders as a select- nested definitions →
subProperties(), flattened asparent.child
const PostSchema = new Schema({
title: { type: String, required: true }, // required text input
status: { type: String, enum: ['draft', 'published'] }, // select
author: { type: String, ref: 'User' }, // reference picker
views: Number, // numeric input
published: Boolean, // checkbox
publishedAt: Date, // datetime picker
address: { city: String }, // sub-property "address.city"
});Filters
Equality filters, plus AdminJS from/to range filters translated to $gte/$lte and cast to the property's type. Filter paths that the resource does not declare are ignored — they arrive from the query string, so they are not passed through to AQL.
Writes
create, update and delete go through the arangoose model, so schema casting, validation, hooks and plugins all apply. Admin forms submit everything as strings; arangoose casts them back to Number/Boolean/Date before validating. _id and _rev are stripped from writes since ArangoDB manages them.
A failed validation surfaces as an error in the AdminJS form.
Exports
| Export | What it is |
| -------------------------------------- | ---------------------------------------------------- |
| Database | BaseDatabase implementation; wraps one model |
| Resource | BaseResource implementation; the real adapter |
| Property | BaseProperty implementation |
| buildProperties(definition, prefix?) | Schema definition → Property[], exported for tests |
| toArangooseFilter(filter) | AdminJS Filter → arangoose filter object |
Limitations
- One resource per model.
Database.resources()returns exactly one; there is no collection discovery from the database. - Search is exact-match. Arangoose has no
$regex/$like, so AdminJS's text filters match exactly rather than substring. - Sorting is single-key, as AdminJS only sends one
sortBy. - No soft-delete awareness in the UI. If a model uses
softDeletePlugin, deletes from the admin panel stamp the field and the rows disappear from the list; there is no "restore" action. - Tenant-scoped models are scoped on list/count but not on
findOne/update/delete, which are key-based. Do not expose a tenant-scoped resource to users of another tenant.
