crystal-lang / crystal-sqlite3

SQLite3 bindings for Crystal
MIT License
139 stars 30 forks source link

Implement support for simple, aggregate, and window functions #75

Open plambert opened 2 years ago

plambert commented 2 years ago

The create_function() support exists, and was added in order to implement the REGEX() callback function. It would be very useful to have a documented Crystal interface to sqlite3_create_function_v2() that could be used similar to this:

@db.create_function returning: Int32.class do |param1, param2|
  # ... do something, returning an Int32
end

Syntax to support returning an array, handling aggregate functions, and handling window functions would be (hopefully) similar.

In addition, for my uses, it doesn't need to be exposed through DB; this is obviously for use cases that are very specific to SQLite and not portable, so having a different interface than Database::DB would be perfectly acceptable, though obviously a lot of the functionality would have to be duplicated.

bcardiff commented 2 years ago

A way to access SQLite custom functions would be:

db = DB.open(DB_URL)
db.setup_connection do |connection|
  connection = connection.as(SQLite3::Connection)
  # .. use custom method of SQLite3::Connection
  connection.create_fun ...
end

I think the sqlite3_create_function_v2 would require a proc with fixed arguments, similar to REGEXP_FN.

On top of that, for convenience, there could be a macro that translate a proc with crystal arguments to the variadic argc/argv as REGEXP_FN. But you won't be able to have a proc like the one to propose since the param1 & param2 are not typed and there would be no clue on how to translate it to the variadic one.

So, the story can be divided in two. Getting binding to sqlite3_create_function_v2 and some example/spec for it seems reasonable. Having a macro for the translation might require a bit more advance crystal stuff and it can be done initially per project basis until it's battle tested enough I think.