Skip to content

Commit

Permalink
migrate ohm-grammar-miniquery to this repo
Browse files Browse the repository at this point in the history
  • Loading branch information
wenerme committed Dec 19, 2022
1 parent 91a284d commit 65c3793
Show file tree
Hide file tree
Showing 33 changed files with 2,673 additions and 31 deletions.
2 changes: 2 additions & 0 deletions .npmrc
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,5 @@ strict-peer-dependencies=true
auto-install-peers=true
legacy-peer-deps=false
registry=https://registry.npmmirror.com/
sharp_binary_host="https://npmmirror.com/mirrors/sharp"
sharp_libvips_binary_host="https://npmmirror.com/mirrors/sharp-libvips"
2 changes: 1 addition & 1 deletion components/wener-tiptap/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@
"@tiptap/react": "^2.0.0-beta.202",
"@tiptap/starter-kit": "^2.0.0-beta.202",
"@tiptap/suggestion": "^2.0.0-beta.202",
"@wener/utils": "workspace:1.1.8",
"@wener/utils": "workspace:*",
"classnames": "^2.3.2",
"linkify-it": "^4.0.1",
"markdown-it": "^13.0.1",
Expand Down
8 changes: 8 additions & 0 deletions packages/ohm-grammar-miniquery/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
REPO_ROOT ?= $(shell git rev-parse --show-toplevel)
include $(REPO_ROOT)/node.mk

publish: fmt build
pnpm publish --access public --registry https://registry.npmjs.org --tag latest

cover:
pnpm exec c8 ava
13 changes: 13 additions & 0 deletions packages/ohm-grammar-miniquery/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# ohm-grammar-miniquery

SQL Where like filter expression for sequelize

## Sequelize

```ts
import {toSequelizeWhere} from 'ohm-grammar-miniquery/sequelize';

await User.findAll({
where: toSequelizeWhere(`name like 'wen%' and age > 18`),
});
```
1 change: 1 addition & 0 deletions packages/ohm-grammar-miniquery/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './lib'
1 change: 1 addition & 0 deletions packages/ohm-grammar-miniquery/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './src'
83 changes: 83 additions & 0 deletions packages/ohm-grammar-miniquery/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
{
"name": "ohm-grammar-miniquery",
"version": "1.0.5",
"type": "module",
"description": "MiniQuery grammars for various editions of ORM/SQL.",
"repository": {
"type": "git",
"url": "git+https://github.com/wenerme/js-miniquery.git"
},
"homepage": "https://github.com/wenerme/js-miniquery/tree/main/packages/ohm-grammar-miniquery#readme",
"bugs": {
"url": "https://github.com/wenerme/js-miniquery/issues"
},
"license": "MIT",
"exports": {
".": {
"import": "./lib/index.js",
"require": "./lib/cjs/index.js",
"types": "./src/index.ts"
},
"./sequelize": {
"import": "./lib/sequelize/index.js",
"require": "./lib/cjs/sequelize/index.js",
"types": "./src/sequelize/index.ts"
},
"./package.json": "./package.json"
},
"files": [
"index.js",
"index.ts",
"lib",
"sequelize.js",
"sequelize.ts",
"src",
"tsconfig.json"
],
"keywords": [
"ohm",
"ohm-grammar",
"miniquery",
"sql",
"sequelize",
"peg"
],
"scripts": {
"build": "make build",
"dev": "make dev",
"gen": "ohm generateBundles --withTypes --esm ./src/grammar/miniquery.ohm",
"lint": "make lint",
"test": "make test"
},
"peerDependencies": {
"@sequelize/core": "*",
"ohm-js": "^16"
},
"peerDependenciesMeta": {
"@sequelize/core": {
"optional": true
}
},
"devDependencies": {
"@ohm-js/cli": "^1.1.0",
"c8": "^7.12.0",
"sqlite3": "^5.0.11"
},
"publishConfig": {
"access": "public",
"registry": "https://registry.npmjs.org"
},
"sideEffects": [
"./lib/ast.js"
],
"ava": {
"extensions": {
"ts": "module"
},
"nodeArguments": [
"--conditions=typescript",
"--require=@wener/wode/suppress-experimental.cjs",
"--loader=tsx"
]
}
}
1 change: 1 addition & 0 deletions packages/ohm-grammar-miniquery/sequelize.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './lib/sequelize'
1 change: 1 addition & 0 deletions packages/ohm-grammar-miniquery/sequelize.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './src/sequelize';
9 changes: 9 additions & 0 deletions packages/ohm-grammar-miniquery/src/ast.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import test from 'ava';
import { toMiniQueryAST } from './ast';

test('miniquery ast', (t) => {
for (const v of [`a > -1`]) {
const ast = toMiniQueryAST(v);
t.truthy(ast);
}
});
202 changes: 202 additions & 0 deletions packages/ohm-grammar-miniquery/src/ast.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
import type { ActionDict, IterationNode, MatchResult } from 'ohm-js';
import { MiniQueryGrammar, MiniQuerySemantics } from './grammar';

export type MiniQueryASTNode =
| {
type: 'identifier';
name: string;
}
| {
type: 'logic';
op: 'and' | 'or';
a: MiniQueryASTNode;
b: MiniQueryASTNode;
}
| {
type: 'rel';
op: 'gt' | 'lt' | 'gte' | 'lte' | 'eq' | 'ne' | 'like' | 'has' | 'in' | 'not in' | 'not like' | 'is' | 'is not';
a: MiniQueryASTNode;
b: MiniQueryASTNode;
}
| {
type: 'between';
op: 'between' | 'not between';
a: MiniQueryASTNode;
b: MiniQueryASTNode;
c: MiniQueryASTNode;
}
| {
type: 'call';
name: string;
value: MiniQueryASTNode[];
}
| {
type: 'unary';
op: 'pos' | 'neg' | 'not';
value: MiniQueryASTNode;
}
| {
type: 'paren';
value: MiniQueryASTNode;
}
| {
type: 'array';
value: MiniQueryASTNode[];
}
| {
type: 'int';
value: number;
}
| {
type: 'float';
value: number;
}
| {
type: 'string';
value: string;
}
| {
type: 'null';
}
| {
type: 'bool';
value: boolean;
}
| {
type: 'ref';
name: string[];
};

const Ops: Record<string, string> = {
'&&': 'and',
'||': 'or',
'=': 'eq',
'==': 'eq',
'!=': 'ne',
'<>': 'ne',
'>': 'gt',
'>=': 'gte',
'<': 'lt',
'<=': 'lte',
':': 'has',
};

export function getMiniQueryASTOp(v: string) {
const s = v.toLowerCase().trim().replaceAll(/\s+/g, ' ');
return Ops[s] || s;
}

const actions: ActionDict<any> = {
nonEmpty(first, _, rest: IterationNode, _pad) {
return [first].concat(rest.children).map((v) => v.toAST());
},
rel(a, op, b) {
let v = op.sourceString;
if (op.isIteration()) {
v = op.children.map((vv) => vv.sourceString).join(' ');
}
return {
type: 'rel',
op: getMiniQueryASTOp(v) as any,
a: a.toAST(),
b: b.toAST(),
v: 'bool',
};
},
empty() {
return [];
},
};

export function toMiniQueryAST(s: string | MatchResult) {
let match: MatchResult;
if (typeof s === 'string') {
match = MiniQueryGrammar.match(s);
} else {
match = s;
}
if (match.failed()) {
throw new SyntaxError(`Invalid MiniQuery: ${match.message}`);
}
return MiniQuerySemantics(match).toAST();
}

MiniQuerySemantics.addOperation<MiniQueryASTNode>('toAST()', {
Main(expr, _) {
return expr.toAST();
},
LogicExpr_match(a, op, b) {
return {
type: 'logic',
op: getMiniQueryASTOp(op.sourceString) as any,
a: a.toAST(),
b: b.toAST(),
v: 'bool',
};
},
RelExpr_match: actions.rel,
RelExpr_match_eq: actions.rel,
RelExpr_has: actions.rel,
InExpr_match: actions.rel,
PredicateExpr_like: actions.rel,
PredicateExpr_is: actions.rel,
BetweenExpr_match(a, op, b, _, c) {
return {
type: 'between',
op: op.sourceString as any,
a: a.toAST(),
b: b.toAST(),
c: c.toAST(),
v: 'bool',
};
},
CallExpr_match(n, _, v, _end) {
return { type: 'call', name: n.sourceString, value: v.toAST() };
},
PriExpr_paren(_, v, _end) {
return { type: 'paren', value: v.toAST() };
},
PriExpr_not(op, v) {
return { type: 'unary', op: getMiniQueryASTOp(op.sourceString) as any, value: v.toAST(), v: 'bool' };
},
PriExpr_pos(op, v) {
return { type: 'unary', op: getMiniQueryASTOp(op.sourceString) as any, value: v.toAST() };
},
PriExpr_neg(op, v) {
return { type: 'unary', op: getMiniQueryASTOp(op.sourceString) as any, value: v.toAST() };
},
Array(_, list, _end) {
return { type: 'array', value: list.toAST(), v: Array };
},
int: (s, _, v) => {
return { type: 'int', value: parseInt(`${s.sourceString || ''}${v.sourceString}`), v: 'int' };
},
float: (i, _, f) => {
return { type: 'float', value: parseFloat(`${i?.sourceString || 0}.${f.sourceString}`), v: Number };
},
string: (_, v, _end) => {
return { type: 'string', value: v.sourceString, v: 'string' };
},
ident: (a, b) => {
return { type: 'identifier', name: [a, b].map((v) => v.sourceString).join('') };
},
null: (_) => {
return { type: 'null', v: 'null' };
},
bool: (v) => {
return { type: 'bool', value: v.sourceString.toLowerCase() === 'true', v: 'bool' };
},
ref(a, b, c: IterationNode) {
return {
type: 'ref',
name: [a.sourceString].concat(
c.children.map((v) => {
const ast = v.toAST();
return ast.name || ast.value;
}),
),
};
},
TrailNonEmptyListOf: actions.nonEmpty,
EmptyListOf: actions.empty,
});
6 changes: 6 additions & 0 deletions packages/ohm-grammar-miniquery/src/grammar/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import grammar from './miniquery.ohm-bundle';

export { default as MiniQueryGrammar } from './miniquery.ohm-bundle';
export default grammar;
export const semantics = grammar.createSemantics();
export const MiniQuerySemantics = semantics;
Loading

0 comments on commit 65c3793

Please sign in to comment.