Yuzhe's Blog

yuzhes

@faster-crud v0.2.0: From 4 Packages to 18 — A Full Framework Ecosystem

@faster-crud v0.2.0: From 4 Packages to 18

GitHub: bkmashiro/nest-faster-crud
npm: @faster-crud

When I released @faster-crud v0.1.x, it covered a single use case: type-safe CRUD for NestJS + TypeORM with Vue 3 frontend bindings. Useful, but narrow.

v0.2.0 is a different story.


What Shipped in v0.2.0

7 ORM / Database Adapters

PackageDatabase
@faster-crud/typeormTypeORM (MySQL, Postgres, SQLite…)
@faster-crud/prismaPrisma
@faster-crud/drizzleDrizzle ORM
@faster-crud/mongooseMongoDB via Mongoose
@faster-crud/mikro-ormMikroORM
@faster-crud/expressExpress (framework adapter)
@faster-crud/fastifyFastify (framework adapter)

Every adapter exposes the same ResourceService interface — swap your ORM without touching your controllers.

3 Frontend Frameworks

// Vue 3 (existing)
const { data, total, create, update, remove } = useCrud<User>('/api/users')

// React (new)
const { data, total, create, update, remove } = useCrud<User>('/api/users')

// Svelte 5 (new — runes style)
const store = createCrudStore<User>('/api/users')
// $: store.data, store.total, etc.

// SolidJS (new)
const store = createCrudStore<User>('/api/users')
// createResource-based reactive signals

All four share the same ResourceMeta protocol — one schema definition powers every UI.

API Layer Adapters

// Hono (existing)
app.route('/users', createCrudRouter(User, userService))

// tRPC (new)
const appRouter = createCrudRouter(User, userService)
// gives you list / get / create / update / remove procedures

// GraphQL (new)
@Module({ providers: [CrudResolver(User, UserService)] })
// generates @ObjectType, @InputType, @Query, @Mutation automatically

Developer Tooling

@faster-crud/gen — CLI code generator:

npx @faster-crud/gen add User --fields "name:string,email:string,age:number"
# Scaffolds: entity, service, module, controller, tests

@faster-crud/validation — standalone validation without class-validator:

const errors = validateEntity(dto, User)
// built-in: required, email, length, range, pattern

@faster-crud/auth — JWT integration:

@Controller('users')
@Protected()  // requires JWT
class UsersController extends CrudControllerFactory(User, UserService) {
  @AdminOnly()  // requires role: 'admin'
  remove(@Param('id') id: number) { ... }
}

Architecture: Why Everything Shares One Schema

The key insight behind @faster-crud is that a single entity class with decorators contains everything needed to generate the entire CRUD stack:

@Resource('users')
class User {
  @Col() id!: number

  @Searchable()
  @Rule.required()
  @Col({ ui: { widget: 'text', label: 'Username' } })
  name!: string

  @Hidden('list')   // visible in get, hidden in list
  @Col()
  email!: string

  @Ignore()         // excluded from all CRUD
  passwordHash!: string
}

From this single definition, @faster-crud derives:

The ResourceMeta endpoint (GET /__crud/meta) serializes this at runtime so frontends can introspect the schema dynamically without code generation.


The Filter Operator System

One of the more elegant pieces: a uniform filter query language that maps to each ORM’s native query builder.

// HTTP query
GET /users?filters[name][op]=like&filters[name][value]=john
GET /users?filters[age][op]=between&filters[age][value][]=18&filters[age][value][]=30

// TypeScript type
type FilterValue = {
  op: 'eq' | 'ne' | 'lt' | 'lte' | 'gt' | 'gte' | 'like' | 'in' | 'between'
  value: any
}

Each adapter translates these to native queries:

OperatorTypeORMPrismaDrizzleMongoose
likeLike('%val%'){ contains: val }like(col, '%val%'){ $regex: val }
betweenBetween(a, b){ gte: a, lte: b }between(col, a, b){ $gte: a, $lte: b }
neNot(val){ not: val }ne(col, val){ $ne: val }

Testing Strategy: 300+ Tests

Every package ships with unit tests that mock the underlying ORM/framework:

// prisma adapter test
const prismaModel = {
  create: jest.fn(async ({ data }) => ({ id: 1, ...data })),
  findMany: jest.fn(async () => []),
  count: jest.fn(async () => 0),
  // ...
}

const UserService = PrismaResourceService(User, prismaModel)
const service = new UserService()

await service.list({ filters: { name: { op: 'like', value: 'John' } } })

expect(prismaModel.findMany).toHaveBeenCalledWith({
  where: { name: { contains: 'John' } },
  orderBy: undefined,
  skip: 0,
  take: 10,
})

Total: 300+ tests across 18 packages, all passing in CI.


VitePress Documentation

The ecosystem now has a full documentation site under docs/:

npm run docs:dev   # local preview
npm run docs:build # static site

What’s Next


The full package list is on npmjs.com and the source is at bkmashiro/nest-faster-crud.