Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/obapelumi/adosearch
typed, deeply nested database search for adonis.js applications
https://github.com/obapelumi/adosearch
Last synced: 3 months ago
JSON representation
typed, deeply nested database search for adonis.js applications
- Host: GitHub
- URL: https://github.com/obapelumi/adosearch
- Owner: Obapelumi
- License: mit
- Created: 2022-06-25T09:54:59.000Z (over 2 years ago)
- Default Branch: main
- Last Pushed: 2023-11-07T13:04:09.000Z (about 1 year ago)
- Last Synced: 2024-07-26T11:08:15.982Z (3 months ago)
- Language: TypeScript
- Size: 122 KB
- Stars: 20
- Watchers: 1
- Forks: 3
- Open Issues: 2
-
Metadata Files:
- Readme: README.md
- Contributing: .github/CONTRIBUTING.md
- License: LICENSE.md
Awesome Lists containing this project
- awesome-adonisjs - Adosearch - typed, deeply nested database search for adonis.js applications (Packages)
README
# adosearch
Adosearch is an [Adonis.js Query Scope](https://docs.adonisjs.com/guides/models/query-scopes#document) that makes advanced search across multiple models trivial to implement.
Inspired by the [sofa/eloquence-base](https://github.com/jarektkaczyk/eloquence/wiki/Builder-searchable-and-more) laravel package.## Installation
Using NPM
```
npm install adosearch
```Or Yarn
```
yarn add adosearch
```## Usage
All you have to do is is define it as static property on the model class by calling the `search` function from adosearch.
```ts
import { BaseModel } from '@ioc:Adonis/Lucid/Orm'
import { search } from 'adosearch'export default class User extends BaseModel {
// ... other model properties
public static search = search(this, ['name', 'email', 'username', 'phone'])
}
```And then apply the search scope like so:
```ts
User.query().withScopes((scopes) => scopes.search('john doe'))
```Just like that we've created a Query Scope that searches for `john doe` in the name, email, username & phone columns of the users table.
We could also specify the columns to search on the fly like so:
```ts
// search columns name and email for john doe
User.query().withScopes((scopes) => scopes.search('john doe', ['name', 'email']))
```## Searching Related Models
Adosearch allows you to search across multiple related models several layers deep. For example, if we have a `Post` model that belongs to a `Category` model and has many comments, we would typically set these relationships up in Adonis like so:
```ts
import { column, BaseModel, hasMany, HasMany, belongsTo, BelongsTo } from '@ioc:Adonis/Lucid/Orm'class Post extends BaseModel {
@column()
public title: string@belongsTo(() => Category)
public category: BelongsTo@hasMany(() => Comment)
public comments: HasMany
}class Category extends BaseModel {
@column()
public name: string@hasMany(() => Post)
public posts: HasMany
}class Comment extends BaseModel {
@column()
public text: string@belongsTo(() => Post)
public post: BelongsTo
}
```Now, say we wanted to search for all the posts for a certain category name. We specify that in our `Post` model:
```ts
import { search } from 'adosearch'class Post extends BaseModel {
//... other properties
public static search = search(this, [
// other fields to search
'category.name',
])
}
```And then we can apply the search scope:
```ts
Post.query().withScopes((scopes) => scopes.search('life style'))// or on the fly
Post.query().withScopes((scopes) => scopes.search('life style', ['title', 'category.name']))
```We could go deeper and search for all comments on posts belonging to a category. For example:
```ts
import { search } from 'adosearch'class Comment extends BaseModel {
//... other properties
public static search = search(this, [
// other fields to search
'post.category.name',
])
}
```Apply the search scope:
```ts
Comment.query().withScopes((scopes) => scopes.search('life style'))
```This is a relatively simple example, but we could go as deep as we want while adosearch generates the complex SQL queries for us on the fly.
And guess what? It has type support 🤩
## Computed Search
Adosearch also provides a handy way to change the search value for a specific column before searching for it. In the example below we want to search by post status which are stored as numbers in the database:
```ts
import { column, BaseModel, hasMany, HasMany, belongsTo, BelongsTo } from '@ioc:Adonis/Lucid/Orm'
import { search } from '../src/search'
import Category from './Category'
import Comment from './Comment'enum PostStatus {
draft = 0,
public = 1,
}export default class Post extends BaseModel {
@column()
public title: string@column({ serialize: (s) => PostStatus[s] })
public status: PostStatus@belongsTo(() => Category)
public category: BelongsTo@hasMany(() => Comment)
public comments: HasManypublic static search = search(this, ['title', 'category.name', 'comments.text', 'status'], {
status: (s: string) => PostStatus[s.trim().toLowerCase()],
})
}
```Now when a user types `draft` or `public` it gets converted to the respective enum values before searching the status column in the Database.
## Limitations
1. Does not yet support the `hasManyThrough` relationship.
2. The column suggestions in typescript might include getter properties if their return type is `string | number | bigint | boolean | DateTime`.