This project provides a fully extensible ORM-like system designed for use with both in-memory and persistent backends (e.g., Dexie for IndexedDB, GraphQL APIs). It models core ORM principles (inspired by Django) such as Model, QuerySet, Field abstraction, SignalRegistry, and registry-based model relationships.
- Declarative model and field system
- Powerful filtering and lookup API (inspired by Django)
- Backends for memory, Dexie (IndexedDB), and GraphQL
- Signal hooks (
pre_save,post_save, etc.) - Dynamic model registration and relationship inference
- Testable, extendable, and backend-agnostic architecture
npm install --save linqueryimport{Model,RelationField,modelRegistry,QuerySet}from"linquery"import{MemoryBackend}from"linquery/backends/memory"classGroupextendsModel{idnamestaticbackend=newMemoryBackend()staticobjects=newQuerySet(Group,Group.backend)}classUserextendsModel{idnameagegroupstaticfields={group: RelationField("Group"),}staticbackend=newMemoryBackend()staticobjects=newQuerySet(User,User.backend)}modelRegistry.register(Group)modelRegistry.register(User)constg=Group.new({id: "g1",name: "Dev"})awaitg.save()constu=User.new({id: "u1",name: "Ana",age: 20,group: {id: "g1"}})awaitu.save()constu2=User.new({id: "u2",name: "Bia",age: 16,group: {id: "g1"}})awaitu2.save()constresults=awaitUser.objects.filter({name: "Ana"}).execute()constcount=awaitUser.objects.filter({age: {gte: 18}}).count()constusers=awaitUser.objects.filter({name: {contains: "A"}}).orderBy("-age").limit(5).execute()constgroup=awaituser.getRelated("group")constusers=awaitgroup.getRelatedMany("User","group")User.signals.on("pre_save",User,async(instance)=>{console.log("Saving user",instance.name)})import{MemoryBackend}from"linquery/backends/memory"constmemoryBackend=newMemoryBackend<User,Filter<User>>()import{DexieBackend}from"linquery/backends/dexie"constdexieBackend=newDexieBackend(User,{tableName: "users",indexes: ["name","age"]})import{Graphql}from"linquery/backends/graphql"constgqlBackend=newGraphql<User,UserFilter,UserOrder>((params)=>{returnclient.getUsers(params)// Your GraphQL client call},User)constfiltered=awaitUser.objects.filter({OR: {name: "Ana",OR: {name: "Bia"}},age: {gte: 18}}).execute()If you don’t declare static fields, they will be inferred from class properties.
npm testOr if using Vitest:
npx vitest runAll major features are covered by tests:
- Field serialization/deserialization
- Query chaining (filter, exclude, order, limit)
- Relationship resolution
- Lifecycle signals
MIT
- Add mutation support to GraphQL backend
- Add validation system for fields
- Add support for many-to-many relationships
Contributions welcome!