squint

m3tti 2025-05-04T08:18:41.694929Z

React native with squint is such a breeze πŸŽ† 🎊

πŸŽ‰ 5
m3tti 2025-05-04T18:05:09.586379Z

hey i'm currently fiddling around with bun and i saw that they have a build in sqlite driver. Is there something like honysql for squnit?

seancorfield 2025-05-04T18:24:47.816229Z

HoneySQL supports cljs - if it doesn't work with Squint, lmk

borkdude 2025-05-04T19:02:39.684669Z

I don’t think honeysql works today with squint since squint doesn’t have multimethods (yet). Maybe there is a JS library for it? What would be cool is if we could compile honeysql with squint so we can expose it to the entire JS world like we did with codemirror clojure-mode

seancorfield 2025-05-04T19:03:43.671329Z

I don't think HoneySQL uses multimethods...?

seancorfield 2025-05-04T19:04:05.681069Z

(v1 did but v2 does not)

borkdude 2025-05-04T19:04:22.836269Z

Oh then I misremembered. I can give a shot at compiling honeysql with squint tomorrow to see if it works

πŸ‘πŸ» 1
m3tti 2025-05-04T19:04:44.595409Z

that would be awesome especially for bun cause it has sql drivers allready

m3tti 2025-05-04T19:04:56.383009Z

for postgres and sqlite that would be a total win imho

borkdude 2025-05-04T19:21:22.011429Z

I had a quick look. Currently squint trips over the use of #'h/sym->kw since squint doesn't have vars (CLJS also doesn't have vars, but it fakes them when using this notation). The next thing squint fails over is the usage of :extend-via-metadata The next thing that fails is Error: nth not supported on this type function(a,b,c,d,e). No clue what this is yet.

borkdude 2025-05-04T19:21:54.381149Z

Note that squint (currently) also doesn't have symbols. so symbol? won't work either

m3tti 2025-05-04T19:22:31.088069Z

regarding the symbols wouldn't it work to use javascript native symbols?

borkdude 2025-05-04T19:23:59.918149Z

Ah, the nth error is about using require without a vector like (:require clojure.string). Squint doesn't support that yet.

borkdude 2025-05-04T19:24:17.968019Z

JavaScript symbols and Clojure symbols are very different things

borkdude 2025-05-04T19:26:44.357829Z

ok got it compiling now:

$ npx squint compile
[squint] Compiling CLJS file: /private/tmp/honeysql/src/honey/sql/helpers.cljc
[squint] Wrote file: /private/tmp/honeysql/js/honey/sql/helpers.mjs
[squint] Compiling CLJS file: /private/tmp/honeysql/src/honey/sql/pg_ops.cljc
[squint] Wrote file: /private/tmp/honeysql/js/honey/sql/pg_ops.mjs
[squint] Compiling CLJS file: /private/tmp/honeysql/src/honey/sql/protocols.cljc
[squint] Wrote file: /private/tmp/honeysql/js/honey/sql/protocols.mjs
[squint] Compiling CLJS file: /private/tmp/honeysql/src/honey/sql/util.cljc
[squint] Wrote file: /private/tmp/honeysql/js/honey/sql/util.mjs
[squint] Compiling CLJS file: /private/tmp/honeysql/src/honey/sql.cljc
[squint] Wrote file: /private/tmp/honeysql/js/honey/sql.mjs
but haven't tried to use it yet, I think it'll fail due to symbol? etc

🀯 1
borkdude 2025-05-04T19:29:17.937229Z

it currently trips over a conflict between an alias and a function name:

import * as str from 'squint-cljs/src/squint/string.js';
import { str, join, split_by_separator, into_STAR_ } from './sql/util.mjs';

borkdude 2025-05-04T19:29:35.119049Z

I guess I can just not use the more efficient str for now

borkdude 2025-05-04T19:31:01.331729Z

now tripping over some invalid syntax produced here:

})()) : ((("else") ? (throw squint_core.ex_info("bigquery * only supports except and replace", ({ "clause": k36, "arg": arg37 }))) : (null))))));

borkdude 2025-05-04T19:31:37.225189Z

perhaps produced by compiling cond or so. interesting

borkdude 2025-05-04T19:33:53.248939Z

ok, this is valid:

var x = "else" ? 1 : 2

borkdude 2025-05-04T19:34:11.989409Z

but apparently this isn't:

var x = "else" ? (throw 1) : 2

borkdude 2025-05-04T19:34:46.838609Z

I'll have to give up for now, but I think with some effort it can be made to work

❀️ 1
borkdude 2025-05-04T19:34:54.697659Z

I'll push my WIP to some repo

borkdude 2025-05-04T19:36:51.825009Z

https://github.com/borkdude/honeysql/tree/squint-wip

borkdude 2025-05-04T19:38:49.098129Z

yeah the issue with throw is that when the expression is in value position, cond can produce code to be invalid. apparently you can't use throw anywhere in values in JS. https://squint-cljs.github.io/squint/?src=KGxldCBbdiAoY29uZAogICAgICAgICAgKHRydWU%2FICg9IDEgMSkpCiAgICAgICAgICAodGhyb3cgKGV4LWluZm8gIk8gbm8iIHt9KSkpXSk%3D

borkdude 2025-05-04T19:39:01.840669Z

I'll log that as an issue

borkdude 2025-05-04T19:39:39.485339Z

(https://github.com/squint-cljs/squint/issues/661)

borkdude 2025-05-04T20:28:00.500349Z

ah clever, CLJS wraps the throw in an IIFE when in value position

borkdude 2025-05-04T21:23:05.159489Z

found another bug in squint: https://github.com/squint-cljs/squint/issues/662 and when working around that found a bug in clj-kondo: https://github.com/clj-kondo/clj-kondo/issues/2535 I'm really the one winning here by finding new issues, thanks :)

πŸ’ͺ 1
borkdude 2025-05-04T21:25:02.843529Z

now that I have stuff more or less running, I'm running into the Keyword stuff which doesn't exist in squint. I think I will run into the Symbol, PersistentVector, etc stuff as well which don't exist in squint

borkdude 2025-05-04T21:27:38.724029Z

it's also running into this one:

(assert (= (set @base-clause-order)
           (set @current-clause-order)
           (set (keys @clause-format))))
since equality in squint is just JS equality

borkdude 2025-05-04T21:28:45.310089Z

wow first non-erroring load in node (by commenting out stuff):

$ node
Welcome to Node.js v20.11.1.
Type ".help" for more information.
> var sql = await import("./js/honey/sql.mjs")

borkdude 2025-05-04T21:30:31.641689Z

> sql.format({"select": "*"})
Uncaught ReferenceError: binding is not defined
lol, yes, binding isn't defined in squint since binding totally doesn't work with ES6 modules

borkdude 2025-05-04T21:44:30.187809Z

by hacking a little bit more, I got this running now:

> var sql = await import("./js/honey/sql.mjs")
undefined
> sql.format({"select": "*"})
[ 'SELECT *' ]
> sql.format({"select": "*", "from": "mytable"})
[ 'SELECT * FROM m, y, t, a, b, l, e' ]
So at least it's doing something πŸ˜…

πŸ™Œ 2
3
borkdude 2025-05-04T22:13:20.286559Z

btw honeysql does work with nbb on bun

Harold 2025-05-05T02:59:44.361129Z

πŸ‘

m3tti 2025-05-05T09:03:06.042259Z

you know whats really funny now if it works completly you can even use alasql πŸ˜„ to query your json structures with honeysql. https://github.com/AlaSQL/alasql

borkdude 2025-05-05T09:04:04.740319Z

yeah sure. should work with nbb today :)

m3tti 2025-05-05T09:04:33.734779Z

yeah but it would be nice to have it on the frontend to πŸ˜„

m3tti 2025-05-05T09:04:54.799139Z

even if my initial request was related to bun πŸ˜„

m3tti 2025-05-05T09:05:37.738679Z

but now if i think further that would be super "technically" cool.

borkdude 2025-05-05T09:05:45.098979Z

I've had an idea how I can have both keywords and strings in squint while maintaining backward compatibility in squint. If I would compile a keyword to x = new String("mykeyword"); x.keyword = true or so. Perhaps that could work in addition with keyword? etc. And comparing x to "mykeyword" as a string would still return true. But this would probably have an effect on performance and code size.

m3tti 2025-05-05T09:06:44.501229Z

ok that looks interesting but sure i guess performance wise it would have impact

m3tti 2025-05-05T09:06:57.093809Z

due to the fact that we have than an object

borkdude 2025-05-05T09:07:37.975639Z

yeah probably not a good idea. It would also break this:

> var m = new Map();
undefined             
m.set("foo", 1)
Map(1) { 'foo' => 1 }
> m.set(new String("foo"), 2)
Map(2) { 'foo' => 1, [String: 'foo'] => 2 }

m3tti 2025-05-05T09:09:27.799739Z

just a stupid idea that comes to my mind. keywords are basically global symbols right. Would it be possible to have them just in a global variable and reference them? i guess than the compilation would get more complicated. so like a global map

borkdude 2025-05-05T09:11:05.981159Z

that's an optimization that can only be done globally if you are compiling a final artifact. The CLJS compiler does this in advanced mode. But in squint keywords are just strings

borkdude 2025-05-05T09:11:35.720779Z

another way to do kind of the same is to use a WeakMap in JavaScript

borkdude 2025-05-05T09:11:48.802119Z

but then you'd have to do a lookup in the map every time you create a keyword

m3tti 2025-05-05T09:12:08.424149Z

exactly that was my point with the lookup it would be tedious πŸ˜„

m3tti 2025-05-05T09:12:25.038079Z

and regarding having a simple tool at hand question is if its worth it

borkdude 2025-05-05T09:13:29.994179Z

in JS you have a library callled squel.js - it's not as great as honeysql though as it doesn't really use data notation

m3tti 2025-05-05T09:13:58.929889Z

yeah saw it too looked quite promising

m3tti 2025-05-05T10:18:38.086419Z

btw i also had this scrappy fiddle around as i saw that i couldn't find an easy to use solution πŸ˜„

(defn prepare-select [{:keys [select from where order-by]}]
  (str
   "SELECT "
   (map gen-columns select)
   " FROM "
   (name from)
   (when where
     " WHERE "
     (map gen-conditions where))
   (when order-by
     " ORDER BY "
     order-by)))

(defn gen-columns [cols]
  (if (= cols :*)
    "*"
    (str/join ", " cols)))

(defn gen-condition [[op column value]]
  (str
   (name column)
   " "
   (name op)
   " "
   value))

(gen-condition [:= :test 123])

(defn gen-conditions [conds]
  (str/join " AND "
            (map gen-condition conds)))

(gen-conditions [[:= :test 123]
                 [:= :brokkli 1]])

(prepare-select {:select :*
                 :from :test
                 :where [[:= :test 123]
                         [:= :brokkli 323]]})
really poor mans version πŸ˜„