From 4c5c5c651dcc1354a2c09fe684505d09898ddd88 Mon Sep 17 00:00:00 2001 From: baxiry Date: Tue, 9 Jul 2024 01:30:44 +0300 Subject: [PATCH] init sub query --- engine/filter.go | 17 +++++++++-- engine/manager.go | 14 +++++++++ engine/queries.go | 71 +++++++++++++++++++++++++++++++++++++++++++-- engine/store.go | 18 ++---------- static/reconnect.js | 2 ++ static/shell.js | 27 +++++++++-------- 6 files changed, 114 insertions(+), 35 deletions(-) diff --git a/engine/filter.go b/engine/filter.go index f399477..1455814 100644 --- a/engine/filter.go +++ b/engine/filter.go @@ -27,6 +27,8 @@ func match(filter gjson.Result, data string) (result bool, err error) { //fmt.Println("here with: ", subQueryKey.String()) switch subQueryKey.String() { + + // comparition case "$gt": if !(dataVal.String() > subQueryVal.String()) { result = false @@ -62,24 +64,25 @@ func match(filter gjson.Result, data string) (result bool, err error) { } return result + // case "$or": // not in result = false return result - case "$st": // is start with + case "$st": // is it start with ? if !strings.HasPrefix(dataVal.String(), subQueryVal.String()) { result = false } return result - case "$en": // is end with + case "$en": // is it end with if !strings.HasSuffix(dataVal.String(), subQueryVal.String()) { result = false } return result - case "$c": // is contains + case "$c": // is it contains if !strings.Contains(dataVal.String(), subQueryVal.String()) { result = false } @@ -130,6 +133,7 @@ func match(filter gjson.Result, data string) (result bool, err error) { result = false } return result + case "$in": // in array for _, v := range subQueryVal.Array() { if dataVal.String() == v.String() { @@ -148,7 +152,14 @@ func match(filter gjson.Result, data string) (result bool, err error) { } return result + //case "$ins": // is it is sub query ? + default: + if subQueryKey.Str == "$ins" { + fmt.Println("queryVal : ", subQueryVal.Raw) + fmt.Println("ids: ", getIds(subQueryVal)) + } + // {$and:[{name:{$eq:"adam"}},{name:{$eq:"jawad"}}]} // {$or: [{name:{$eq:"adam"}}, {name:{$eq:"jawad"}}]} diff --git a/engine/manager.go b/engine/manager.go index be311f4..4846277 100644 --- a/engine/manager.go +++ b/engine/manager.go @@ -6,6 +6,20 @@ import ( "github.com/tidwall/gjson" ) +func (db *DB) CreateCollection(collection string) error { + query := fmt.Sprintf(`CREATE TABLE IF NOT EXISTS %s (record json);`, collection) + _, err := db.db.Exec(query) + if err != nil { + return err + } + lid, err := getLastId(db.db, collection) + if err != nil { + return err + } + db.lastid[collection] = lid + return nil +} + func getCollections() string { table, result := "", `["` res, err := db.db.Query("SELECT name FROM sqlite_master WHERE type='table'") diff --git a/engine/queries.go b/engine/queries.go index 8047929..e5805fd 100644 --- a/engine/queries.go +++ b/engine/queries.go @@ -194,6 +194,70 @@ func (db *DB) updateById(query gjson.Result) (result string) { return id + " updated" } +func getIds(query gjson.Result) string { + + coll := query.Get("collection").Str + if coll == "" { + return `{"error":"forgot collection name "}` + } + + mtch := query.Get("match") + + if mtch.String() == "" { + fmt.Println("match.Str is empty") + } + + skip := query.Get("skip").Int() + limit := query.Get("limit").Int() + if limit == 0 { + limit = 100 + } + + stmt := `select rowid, record from ` + coll + + rows, err := db.db.Query(stmt) + if err != nil { + return err.Error() + } + defer rows.Close() + + record := "" + rowids := "" + rowid := "" + + for rows.Next() { + if limit == 0 { + break + } + if skip != 0 { + skip-- + continue + } + + record = "" + rowid = "" + err := rows.Scan(&rowid, &record) + if err != nil { + return err.Error() // TODO standaring errors + } + + ok, err := match(mtch, record) + if err != nil { + return err.Error() + } + + if ok { + rowids += rowid + "," + limit-- + } + } + + if rowids == "" { + return "" + } + return rowids[:len(rowids)-1] +} + // Find finds any obs match creteria. func (db *DB) findMany(query gjson.Result) (res string) { @@ -255,14 +319,13 @@ func (db *DB) findMany(query gjson.Result) (res string) { order := query.Get("orderBy").Str reverse := query.Get("reverse").Int() - fmt.Println("reverse :", reverse) if order != "" { listData = orderBy(order, int(reverse), listData) } // TODO aggrigate here - // remove|rename some fields + // remove or rename some fields flds := query.Get("fields") listData = reFields(listData, flds) @@ -394,10 +457,12 @@ func (db *DB) findById(query gjson.Result) (res string) { // Insert func (db *DB) insertOne(query gjson.Result) (res string) { coll := query.Get("collection").Str - data := query.Get("data").Str + data := query.Get("data").String() // .Str not works with json obj + fmt.Println(coll, "\n", data) err := db.insert(coll, data) if err != nil { + fmt.Println(err) return err.Error() } diff --git a/engine/store.go b/engine/store.go index 22a0adc..ce56303 100644 --- a/engine/store.go +++ b/engine/store.go @@ -86,9 +86,11 @@ func (db *DB) insert(collection, obj string) error { db.lastid[collection]++ data := `{"_id":` + fmt.Sprint(db.lastid[collection]) + ", " + d[1:] + fmt.Println("data: ", data) + fmt.Println("coll: ", collection) _, err := db.db.Exec(`insert into ` + collection + `(record) values('` + data + `');`) // fast if err != nil { - //println(err) + fmt.Println(err) db.lastid[collection]-- return err } @@ -96,20 +98,6 @@ func (db *DB) insert(collection, obj string) error { return nil } -func (db *DB) CreateCollection(collection string) error { - query := fmt.Sprintf(`CREATE TABLE IF NOT EXISTS %s (record json);`, collection) - _, err := db.db.Exec(query) - if err != nil { - return err - } - lid, err := getLastId(db.db, collection) - if err != nil { - return err - } - db.lastid[collection] = lid - return nil -} - // Close db func (db *DB) Close() { db.db.Close() diff --git a/static/reconnect.js b/static/reconnect.js index 56bb7ac..468a726 100644 --- a/static/reconnect.js +++ b/static/reconnect.js @@ -1,2 +1,4 @@ + //github.com/joewalnes/reconnecting-websocket !function(a,b){"function"==typeof define&&define.amd?define([],b):"undefined"!=typeof module&&module.exports?module.exports=b():a.ReconnectingWebSocket=b()}(this,function(){function a(b,c,d){function l(a,b){var c=document.createEvent("CustomEvent");return c.initCustomEvent(a,!1,!1,b),c}var e={debug:!1,automaticOpen:!0,reconnectInterval:1e3,maxReconnectInterval:3e4,reconnectDecay:1.5,timeoutInterval:2e3};d||(d={});for(var f in e)this[f]="undefined"!=typeof d[f]?d[f]:e[f];this.url=b,this.reconnectAttempts=0,this.readyState=WebSocket.CONNECTING,this.protocol=null;var h,g=this,i=!1,j=!1,k=document.createElement("div");k.addEventListener("open",function(a){g.onopen(a)}),k.addEventListener("close",function(a){g.onclose(a)}),k.addEventListener("connecting",function(a){g.onconnecting(a)}),k.addEventListener("message",function(a){g.onmessage(a)}),k.addEventListener("error",function(a){g.onerror(a)}),this.addEventListener=k.addEventListener.bind(k),this.removeEventListener=k.removeEventListener.bind(k),this.dispatchEvent=k.dispatchEvent.bind(k),this.open=function(b){h=new WebSocket(g.url,c||[]),b||k.dispatchEvent(l("connecting")),(g.debug||a.debugAll)&&console.debug("ReconnectingWebSocket","attempt-connect",g.url);var d=h,e=setTimeout(function(){(g.debug||a.debugAll)&&console.debug("ReconnectingWebSocket","connection-timeout",g.url),j=!0,d.close(),j=!1},g.timeoutInterval);h.onopen=function(){clearTimeout(e),(g.debug||a.debugAll)&&console.debug("ReconnectingWebSocket","onopen",g.url),g.protocol=h.protocol,g.readyState=WebSocket.OPEN,g.reconnectAttempts=0;var d=l("open");d.isReconnect=b,b=!1,k.dispatchEvent(d)},h.onclose=function(c){if(clearTimeout(e),h=null,i)g.readyState=WebSocket.CLOSED,k.dispatchEvent(l("close"));else{g.readyState=WebSocket.CONNECTING;var d=l("connecting");d.code=c.code,d.reason=c.reason,d.wasClean=c.wasClean,k.dispatchEvent(d),b||j||((g.debug||a.debugAll)&&console.debug("ReconnectingWebSocket","onclose",g.url),k.dispatchEvent(l("close")));var e=g.reconnectInterval*Math.pow(g.reconnectDecay,g.reconnectAttempts);setTimeout(function(){g.reconnectAttempts++,g.open(!0)},e>g.maxReconnectInterval?g.maxReconnectInterval:e)}},h.onmessage=function(b){(g.debug||a.debugAll)&&console.debug("ReconnectingWebSocket","onmessage",g.url,b.data);var c=l("message");c.data=b.data,k.dispatchEvent(c)},h.onerror=function(b){(g.debug||a.debugAll)&&console.debug("ReconnectingWebSocket","onerror",g.url,b),k.dispatchEvent(l("error"))}},1==this.automaticOpen&&this.open(!1),this.send=function(b){if(h)return(g.debug||a.debugAll)&&console.debug("ReconnectingWebSocket","send",g.url,b),h.send(b);throw"INVALID_STATE_ERR : Pausing to reconnect websocket"},this.close=function(a,b){"undefined"==typeof a&&(a=1e3),i=!0,h&&h.close(a,b)},this.refresh=function(){h&&h.close()}}return a.prototype.onopen=function(){},a.prototype.onclose=function(){},a.prototype.onconnecting=function(){},a.prototype.onmessage=function(){},a.prototype.onerror=function(){},a.debugAll=!1,a.CONNECTING=WebSocket.CONNECTING,a.OPEN=WebSocket.OPEN,a.CLOSING=WebSocket.CLOSING,a.CLOSED=WebSocket.CLOSED,a}); + diff --git a/static/shell.js b/static/shell.js index 5344037..cefb614 100644 --- a/static/shell.js +++ b/static/shell.js @@ -7,11 +7,12 @@ for (let [key, value] of Object.entries(yourobject)) { // This configuration is suitable for development situation -const configs = {debug: false, reconnectDecay:1 , reconnectInterval: 200, reconnectDecay:1, maxReconnectInterval:200} +//const configs = {debug: false, reconnectDecay:1 , reconnectInterval: 200, reconnectDecay:1, maxReconnectInterval:200} // WebSocket var ws = new ReconnectingWebSocket('ws://localhost:1111/ws'); + function connection() { ws.onopen = function(){ @@ -74,28 +75,28 @@ queryInput.addEventListener('keydown', function(event) { function prettyJSON(jsonString) { - try { + try { const jsonObject = JSON.parse(jsonString); let res = JSON.stringify(jsonObject, null, 3); return res - } catch (error) { - console.log("invalid json") + } catch (error) { + console.error("invalid json") return jsonString; + } } } -} // Dealing with Textarea Height function calcHeight(value) { - let numberOfLineBreaks = (value.match(/\n/g) || []).length; + let numberOfLineBreaks = (value.match(/\n/g) || []).length; if (numberOfLineBreaks < 3) { numberOfLineBreaks = 3 } - console.log("lines:",numberOfLineBreaks) - // min-height + lines x line-height + padding + border - let newHeight = 20 + numberOfLineBreaks * 20 + 12 + 2; + //console.log("lines:",numberOfLineBreaks) + // min-height + lines x line-height + padding + border + let newHeight = 20 + numberOfLineBreaks * 20 + 12 + 2; - return newHeight; + return newHeight; } let textarea = document.querySelector("textarea"); @@ -108,12 +109,10 @@ textarea.addEventListener("keyup", () => { connection() $(document).on("keypress", function (e) { - console.log("event : ", e) - console.log("input : ", $("#query-input").val()) - + // console.log("event : ", e) + // console.log("input : ", $("#query-input").val()) // TODO some hilit for js object }); -// var queryShow = ""