type-query-parser

the purpose of this project is giving types to search object values

Usage no npm install needed!

<script type="module">
  import typeQueryParser from 'https://cdn.skypack.dev/type-query-parser';
</script>

README

npm link & github link

problem

When we parse a search from location, we often get an object like {[key: string]: string|string[]|undefined}, but we really want an object like {[key:string]:number|boolean|Date|string|string[]...} which can describe more types about the values. Also we want to validate these values, if they are invalid we can replace them from an default.

resolve

Here is a tool type-query-parser which can do something like transforming value type and replacing value which is invalid. It parses query with your template.

example (more in test)

basic usage

    import {parse,Parsers} from 'type-query-parser';

    const source = {
        id: '123456',
        name: 'jimmy ',
        active: 'true',
        role: 'MASTER'
    };

    test('stringify before equals parse after', () => {

        const template = {
            id: Parsers.natural(),
            name: Parsers.string(),
            active: Parsers.boolean(),
            role: Parsers.enum(['GUEST', 'USER', 'MASTER', 'ADMIN'])
        };

        const target = parse(source, template);

        expect(target).toEqual({
            id: 123456,
            name: 'jimmy ',
            active: true,
            role: 'MASTER'
        });
    });
    
    test('with defaults', () => {

        const template = {
            id: Parsers.natural(),
            name: Parsers.string(true),
            active: Parsers.boolean(),
            role: Parsers.enum(['GUEST', 'USER'])
        };

        const defaults = {
            role: 'GUEST'
        };

        const target = parse(source, template, defaults);

        expect(target.role).toBe(defaults.role);
    });

string parser

    import {parse,Parsers} from 'type-query-parser';

    test('Parsers.string', () => {

        const query = {
            name: ' jimmy '
        };
        //with out trim
        expect(parse(query, {name: Parsers.string()}).name).toBe(query.name);
        //with trim
        expect(parse(query, {name: Parsers.string(true)}).name).toBe(query.name.trim());
    });

number parser

    import {parse,Parsers} from 'type-query-parser';

    test('Parsers.number', () => {

        const query = {
            price: '12.34'
        };

        expect(parse(query, {price: Parsers.number()}).price).toBe(12.34);
    });

api

parse query to an object you want by template and defaults in opt.

types:

type Parser = (value?: string|string[]) => any|void; any function matches Parser is used to transform value to you want

type Template = { [key: string]: Template | Parser } | Parser[]; any object matches Template is used to structure result you want

type {defaults?:any} the default value you provide, when the value is undefined, the value in defaults with same key will replace the undefined one.

function parse(search:string,template?:Template,defaults?: any)

Parsers provide some Parser, which is helpful, also you can write yourself Parsers.

Parsers.number:

function Parsers.number() return a Parser
 
Parser:(value?:string)=>number|undefined

if the value isNaN (can not be a number), it will return an undefined value, 
else it will provide a number value (typeof returnValue==='number').

Parsers.natural:

function Parsers.natural() return a Parser
 
Parser:(value?:string)=>number|undefined

if the value can not be a natural number, it will return an undefined value, 
else it will provide a natural number value (typeof returnValue==='number').

Parsers.integer:

function Parsers.natural() return a Parser
 
Parser:(value?:string)=>number|undefined

if the value can not be a integer, it will return an undefined value, 
else it will provide a integer value (typeof returnValue==='number').

Parsers.string:

function Parsers.string(trim:boolean) return a Parser
 
Parser:(value?:string)=>string

the value will be a string, if you set trim:true the string value will be trimmed.

Parsers.boolean:

function Parsers.boolean() return a Parser
 
Parser:(value?:string)=>boolean|undefined

if the value trimmed is not 'true' or 'false', it will return an undefined value, 
else it will provide a boolean value (typeof returnValue==='boolean').

Parsers.enum:

function Parsers.enum(array:Array<any>) return a Parser
 
Parser:(value?:string)=>any|undefined

if the value trimmed is not included in array, it will return an undefined value, 
else it will return the one in array which matches value by '==' not '==='.

Parsers.array:

function Parsers.array(mapper?: (data: string) => any) return a Parser
 
Parser: (value?: string | Array<string>)=>Array<any>|Array<string>

if the value is string, it will transform to array by string.split, then the array will map with mapper, 
at last the mapped array will filter out the datas to a new array which data is not undefined.

Parsers.regExp:

function Parsers.regExp(regExp: RegExp) return a Parser
 
Parser:(value?:string)=>string|undefined

if the value 'regExp.test(value)' is passed, it will return value, else it will undefined.

Parsers.date:

function Parsers.date(...dateLikeReduces: Array<DateLikeReduce>) return a Parser
 
Parser:(value?:string)=>DateLike|undefined

type DateLike = string | number | Date;

type DateLikeReduce = (dateLike: DateLike) => DateLike

if the value trimmed can be a Date value, it will return a DateLike value, 
which might be produced by dateLikeReduces, else it will return undefined.

here is some dateLikeReduces provided, they can help you use it more quickly:

startOfDay(dateLike: DateLike)=>Date                // DateLike[2020-05-23 12:11:34] => new Date(2020-05-23 00:00:00:000)
endOfDay(dateLike: DateLike)=>Date                  // DateLike[2020-05-23 12:11:34] => new Date(2020-05-23 23:59:59:999)
toDateString(date: DateLike)=>string                // DateLike[2020-05-23 12:11:34] => '2020-05-23'
toDatetimeString(date: DateLike)=>string            // DateLike[2020-05-23 12:11:34] => '2020-05-23 12:11:34'
pattern(pat: string)=>formatDateLike(dateLike: DateLike)=>string
                                                    // pattern('YYYY-MM-DD HH:mm')=>formatter
                                                    // formatter(DateLike[2020-05-23 12:11:34])
                                                    // =>'2020-05-23 12:11'
                                                    
we can use like this:
import {parse,Parsers} from 'type-query-parser';
import {startOfDay,pattern} from 'type-query-parser/libs';

const template={
    start:Parsers.date(startOfDay,pattern('YYYY-MM-DD HH:mm:ss')),
    end:Parsers.date(endOfDay,toDatetimeString)
};

const data=parse({start:'2020-01-01 11:02:30',end:'2020-12-13 20:02:15'},template);

/*** result ***/
{
    start:'2020-01-01 00:00:00',
    end:'2020-12-13 23:59:59'
}

Parsers.datePattern:

function Parsers.datePattern(...dateLikeReduces: Array<DateLikeReduce>) return a Parser
 
Parser:(value?:string)=>string|undefined

it is just a wrap on Parsers.date, and returns a 'YYYY-MM-DD' formatted string value or undefined.

Parsers.datetimePattern:

function Parsers.datetimePattern(...dateLikeReduces: Array<DateLikeReduce>) return a Parser
 
Parser:(value?:string)=>string|undefined

it is just a wrap on Parsers.date, and returns a 'YYYY-MM-DD HH:mm:ss' formatted string value or undefined.

summary

if you like this tool, give me a little start, thank you.