All Projects → caibirdme → Yql

caibirdme / Yql

Licence: mit
yet another query language for rule engine in golang

Programming Languages

go
31211 projects - #10 most used programming language
dsl
153 projects

Projects that are alternatives of or similar to Yql

Kuiper
A lightweight IoT edge analytics software
Stars: ✭ 327 (+52.09%)
Mutual labels:  rule-engine
Rule Engine Front
🔥 🔥 🔥 📌 规则引擎前端 📌 RuleEngine 基于web可视化配置,简单高效快捷。
Stars: ✭ 40 (-81.4%)
Mutual labels:  rule-engine
Psrule
Validate infrastructure as code (IaC) and objects using PowerShell rules.
Stars: ✭ 107 (-50.23%)
Mutual labels:  rule-engine
Drools
Drools is a rule engine, DMN engine and complex event processing (CEP) engine for Java.
Stars: ✭ 4,062 (+1789.3%)
Mutual labels:  rule-engine
Ruler
The Hoa\Ruler library.
Stars: ✭ 612 (+184.65%)
Mutual labels:  rule-engine
Json Rules Engine
A rules engine expressed in JSON
Stars: ✭ 1,159 (+439.07%)
Mutual labels:  rule-engine
Easy Rules
The simple, stupid rules engine for Java
Stars: ✭ 3,522 (+1538.14%)
Mutual labels:  rule-engine
Mon Entreprise
L'assistant officiel de l'entrepreneur
Stars: ✭ 123 (-42.79%)
Mutual labels:  rule-engine
Grule Rule Engine
Rule engine implementation in Golang
Stars: ✭ 729 (+239.07%)
Mutual labels:  rule-engine
Jetlinks Community
JetLinks 基于Java8,Spring Boot 2.x ,WebFlux,Netty,Vert.x,Reactor等开发, 是一个全响应式的企业级物联网平台。支持统一物模型管理,多种设备,多种厂家,统一管理。统一设备连接管理,多协议适配(TCP,MQTT,UDP,CoAP,HTTP等),屏蔽网络编程复杂性,灵活接入不同厂家不同协议等设备。实时数据处理,设备告警,消息通知,数据转发。地理位置,数据可视化等。能帮助你快速建立物联网相关业务系统。
Stars: ✭ 2,405 (+1018.6%)
Mutual labels:  rule-engine
Jetlinks
JetLinks Core
Stars: ✭ 380 (+76.74%)
Mutual labels:  rule-engine
Node Rules
Node-rules is a light weight forward chaining rule engine written in JavaScript.
Stars: ✭ 481 (+123.72%)
Mutual labels:  rule-engine
G Rule
Groovy based lightweight rule engine
Stars: ✭ 76 (-64.65%)
Mutual labels:  rule-engine
Gengine
Rule Engine for Golang
Stars: ✭ 348 (+61.86%)
Mutual labels:  rule-engine
Iot Technical Guide
🐝 IoT Technical Guide --- 从零搭建高性能物联网平台及物联网解决方案和Thingsboard源码分析 ✨ ✨ ✨ (IoT Platform, SaaS, MQTT, CoAP, HTTP, Modbus, OPC, WebSocket, 物模型,Protobuf, PostgreSQL, MongoDB, Spring Security, OAuth2, RuleEngine, Kafka, Docker)
Stars: ✭ 2,334 (+985.58%)
Mutual labels:  rule-engine
Irods
Open Source Data Management Software
Stars: ✭ 321 (+49.3%)
Mutual labels:  rule-engine
Nrules
Rules engine for .NET, based on the Rete matching algorithm, with internal DSL in C#.
Stars: ✭ 1,003 (+366.51%)
Mutual labels:  rule-engine
Kogito Runtimes
Kogito Runtimes - Kogito is a cloud-native business automation technology for building cloud-ready business applications.
Stars: ✭ 188 (-12.56%)
Mutual labels:  rule-engine
Dry Logic
Predicate logic with rule composition
Stars: ✭ 118 (-45.12%)
Mutual labels:  rule-engine
Iotplatform
An open-source IoT platform that enables rapid development, management and scaling of IoT projects. With this IoT platform, you are able to: 1) Provision and control devices, 2) Collect and visualize data from devices, 3) Analyze device data and trigger alarms, 4) Deliver device data to other systems, 5) Enable use-case specific features using customizable rules and plugins.
Stars: ✭ 82 (-61.86%)
Mutual labels:  rule-engine

YQL(Yet another-Query-Language)

Build Status GoDoc

YQL is very similar with the where part of sql. You can see it as another sql which also support comparison between two sets. YQL have nearly no new concepts, so you can use it well short after reading the examples.Though it's designed for rule engine, it can be widely used in your code logic.

Install

go get github.com/caibirdme/yql

Exmaple

See more examples in the yql_test.go and godoc.

	rawYQL := `name='deen' and age>=23 and (hobby in ('soccer', 'swim') or score>90))`
	result, _ := yql.Match(rawYQL, map[string]interface{}{
		"name":  "deen",
		"age":   int64(23),
		"hobby": "basketball",
		"score": int64(100),
	})
	fmt.Println(result)
	rawYQL = `score ∩ (7,1,9,5,3)`
	result, _ = yql.Match(rawYQL, map[string]interface{}{
		"score": []int64{3, 100, 200},
	})
	fmt.Println(result)
	rawYQL = `score in (7,1,9,5,3)`
	result, _ = yql.Match(rawYQL, map[string]interface{}{
		"score": []int64{3, 5, 2},
	})
	fmt.Println(result)
	rawYQL = `score.sum() > 10`
	result, _ = yql.Match(rawYQL, map[string]interface{}{
		"score": []int{1, 2, 3, 4, 5},
	})
	fmt.Println(result)
	//Output:
	//true
	//true
	//false
	//true

And In most cases, you can use Rule to cache the AST and then use Match to get the result, which could avoid hundreds of thousands of repeated parsing process.

	rawYQL := `name='deen' and age>=23 and (hobby in ('soccer', 'swim') or score>90)`
	ruler,_ := yql.Rule(rawYQL)

	result, _ := ruler.Match(map[string]interface{}{
		"name":  "deen",
		"age":   23,
		"hobby": "basketball",
		"score": int64(100),
	})
	fmt.Println(result)
	result, _ = ruler.Match(map[string]interface{}{
		"name":  "deen",
		"age":   23,
		"hobby": "basketball",
		"score": int64(90),
	})
	fmt.Println(result)
	//Output:
	//true
	//false

Though the to be matched data is the type of map[string]interface{}, there're only 5 types supported:

  • int
  • int64
  • float64
  • string
  • bool

Helpers

In score.sum() > 10, sum is a helper function which adds up all the numbers in score, which also means the type of score must be one of the []int,[]int64 or []float64.

This repo is in the early stage, so now there are just a few helpers, feel free to create an issue about your needs. Supported helpers are listed below:

  • sum: ...
  • count: return the length of a slice or 1 if not a slice
  • avg: return the average number of a slice(float64(total)/float64(len(slice)))
  • max: return the maximum number in a slice
  • min: return the minimum number in a slice

Usage scenario

Obviously, it's easy to use in rule engine.

var handlers = map[int]func(map[string]interface{}){
	1: sendEmail,
	2: sendMessage,
	3: alertBoss,
}

data := resolvePostParamsFromRequest(request)
rules := getRulesFromDB(sql)

for _,rule := range rules {
	if success,_ := yql.Match(rule.YQL, data); success {
		handler := handlers[rule.ID]
		handler(data)
		break
	}
}

Also, it can be used in your daily work, which could significantly reduce the deeply embebbed if else statements:

func isVIP(user User) bool {
	rule := fmt.Sprintf("monthly_vip=true and now<%s or eternal_vip=1 or ab_test!=false", user.ExpireTime)
	ok,_ := yql.Match(rule, map[string]interface{}{
		"monthly_vip": user.IsMonthlyVIP,
		"now": time.Now().Unix(),
		"eternal_vip": user.EternalFlag,
		"ab_test": isABTestMatched(user),
	})
	return ok
}

Even, you can use json.Marshal to generate the map[string]interface{} if you don't want to write it manually. Make sure the structure tag should be same as the name in rawYQL.

Syntax

See grammar file

Compatibility promise

The API Matchis stable now. Its grammar won't change any more, and what I only will do next is to optimize, speed up and add more helpers if needed.

Further Trial

Though it's kinder difficult to create a robust new Go compiler, there're still some interesting things could do. For example, bringing lambda function in Go which maybe look like:

var scores = []int{1,2,3,4,5,6,7,8,9,10}
newSlice := yql.Filter(`(v) => v % 2 == 0`).Map(`(v) => v*v`).Call(scores).Interface()
//[]int{4,16,36,64,100}

If the lambda function won't change all time, it can be cached like opcode, which is as fast as the compiled code. And in most cases, who care?(pythoner?)

It's not easy but interesting, isn't it? Welcome to join me, open some issues and talk about your ideas with me. Maybe one day it can become a pre-compile tool like babel in javascript.

Attention

Lambda expression now is in its very early stage, DO NOT USE IT IN PRODUCTION.

You can take a quick preview in test case

type Student struct {
	Age  int
	Name string
}

var students = []Student{
	Student{
		Name: "deen",
		Age:  24,
	},
	Student{
		Name: "bob",
		Age:  22,
	},
	Student{
		Name: "alice",
		Age:  23,
	},
	Student{
		Name: "tom",
		Age:  25,
	},
	Student{
		Name: "jerry",
		Age:  20,
	},
}

t = yql.Filter(`(v) => v.Age > 23 || v.Name == "alice"`).Call(students).Interface()
res,_ := t.([]Student)
// res: Student{"deen",24} Student{"alice", 23} Student{"tom", 25}

Chainable

dst := []int{1, 2, 3, 4, 5, 6, 7}
r := Filter(`(v) => v > 3 && v <= 7`).Map(`(v) =>  v << 2`).Filter(`(v) => v % 8 == 0`).Call(dst)
s, err := r.Interface()
ass := assert.New(t)
ass.NoError(err)
ass.Equal([]int{16, 24}, s)
Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].