DEV Community

Zenql
Zenql

Posted on

ZenQL, Powerful, Fluent Queries In Golang

a new way to interact with your data in golang

Zenql is an internal DSL (Domain Specific Language) for golang. trying to provide a new way to work with various data-sources in an integrated environment. datasources can be of any kind, such as golang internal data-types (channels, slices) and async datasources like (csv,json,postgres db, mysql db).

zenql is inspired by C# linq and Java streams. for collection processing we have a dedicated query engine named thor, which uses operator fusion pattern to process the query-chain in a single execution unit. this approach can be very performant. our benchmarks shows that thor engine filtered a slice of 50,000,000 items in just 2 seconds.

an expressive query on collections using zenql:

Group[bool, ComplexObjectToSearch](
    From(items).Where(func(search ComplexObjectToSearch) bool {
        return search.Age > 20
    }),
    func(item ComplexObjectToSearch) bool {
        return item.Flag
    }
).Collect()

Enter fullscreen mode Exit fullscreen mode

Polymorphic queries

but what about async datasources? After all the idea is that we provide A Polymorphic Query Language. the key to process async data-sources is to use the zenql stream api's. besides when we have a large data-set is that really practical to load all the data inside the memory and process them? and how can we query our data in different places and infrastructures? sometimes the data can be in-memory, other times its in a files (csv, json) and most of times its in a relational database.

luckily we provided a very capable Domain-Specific-Language for golang to be compatible with all these environments in an integrated way. the idea is that we use different kinds of adapters and zenql processing the data in a unified way.

1 - FromData to initiate stream from slices.
2 - FromChannel to initiate stream Channels.
3 - FromSqlRows to initiate stream an RDBMS (mysql,postgres).
4 - FromJsonArr to initiate stream from a json file.
5 - FromCsvFile to initiate stream from a csv file.

after initiating the stream, we can use zenql stream Pipelines to process your data.

A Real‑World Example of MySql Streams

Imagine a scenario with a large user base where you need to process users individually, such as validating each one against an external web service. Loading all records into memory is neither efficient nor scalable. Conversely, repeatedly opening and closing a database connection for every single row creates a significant performance bottleneck. With the new Zenql Streams API, you can initiate a stream using a single database connection to process rows iteratively, just like a cursor. This approach significantly reduces memory consumption and optimizes performance by eliminating unnecessary database round-trips.


    ctx, cancel := context.WithCancel(context.Background())

    defer cancel()

    constr := "root:1245Sa@tcp(127.0.0.1:30306)/Test?parseTime=true&charset=utf8mb4"

    if conn, err := db.connect("mysql",constr); err != nil {
        t.Fatal(err)
    } else {

        defer conn.Close()

        id := 0
        stream :=
            db.FromSqlRows[UserModel](ctx, conn,
                "select * from Test.users where id>?", func(rows *sql.Rows) (UserModel, error) {
                    var id, age int
                    var name string
                    var err error
                    var active bool

                    err = rows.Scan(&id, &name, &age,&active)
                    model := UserModel{
                        UserId:   id,
                        Age:      age,
                        UserName: name,
                        Active: active
                    }
                    return model, err
                }, id)

        if stream.Initiated {
            for v := range stream.FilterStream(func(model UserModel) bool {
                return model.Age > 25
            }).Throttle(time.Millisecond * 5000).Channel {

                /// business logic

                business_logic_satisfied := true

                if business_logic_satisfied {

                    result := Exec(conn, "update Test.users set Active = ? where Id =?", 1, v.UserId)
                    if result.Err != nil {
                        t.Error(result.Err)
                    } else {
                        fmt.Println(v, " - updated. ", result.RowsAffected)
                    }
                }

            }
        } else {
            fmt.Println("stream not initiated")
        }

Enter fullscreen mode Exit fullscreen mode

want to try ZenQL? visit this Repository and be surprised!

Top comments (3)

Collapse
 
mrhujaifa profile image
Flamekit

🤍

Collapse
 
andreimerlescu profile image
Andrei Merlescu

This is super cool! I love how Go can have C# inspired LINQ compatibility. I thought it looked familiar, until I saw that in the documentation on GitHub directly. Did you use an AI to build it?

Collapse
 
zenql profile image
Zenql • Edited

Hi. Glad you like it. I use ai to research. I don't involve it in coding. it makes things unnecessarily complicated and that can be dangerous imho. I use it for troubleshooting too. Don't forget to star and introduce the repository my friend!