JavaScript for Automation access to SQLite


#1

JavaScript for Automation, FWIW, allows us to write:

ObjC.import('sqlite3')

and then, things like:

(() => {
    'use strict';

    ObjC.import('sqlite3');

    // GENERIC FUNCTIONS -----------------------------------------------------

    // Just :: a -> Just a
    const Just = x => ({
        type: 'Maybe',
        Nothing: false,
        Just: x
    });

    // Left :: a -> Either a b
    const Left = x => ({
        type: 'Either',
        Left: x
    });

    // Nothing :: () -> Nothing
    const Nothing = () => ({
        type: 'Maybe',
        Nothing: true,
    });

    // Right :: b -> Either a b
    const Right = x => ({
        type: 'Either',
        Right: x
    });

    // Tuple (,) :: a -> b -> (a, b)
    const Tuple = (a, b) => ({
        type: 'Tuple',
        '0': a,
        '1': b
    });

    // bindEither (>>=) :: Either a -> (a -> Either b) -> Either b
    const bindEither = (m, mf) =>
        m.Right !== undefined ? (
            mf(m.Right)
        ) : m;

    // filePath :: String -> FilePath
    const filePath = s =>
        ObjC.unwrap(ObjC.wrap(s)
            .stringByStandardizingPath);

    // showJSON :: a -> String
    const showJSON = x => JSON.stringify(x, null, 2);

    // (x => Maybe [value, remainder] -> initial value -> values
    // unfoldr :: (b -> Maybe (a, b)) -> b -> [a]
    const unfoldr = (f, v) => {
        let xs = [];
        return (
            until(
                mb => mb.Nothing,
                mb => (
                    xs.push(mb.Just[0]),
                    f(mb.Just[1])
                ), Just(Tuple(v, v))
            ),
            xs.slice(1)
        );
    };

    // until :: (a -> Bool) -> (a -> a) -> a -> a
    const until = (p, f, x) => {
        let v = x;
        while (!p(v)) v = f(v);
        return v;
    };

    //------------------------------------------------------------------------
    // MAIN: SIMPLE EXAMPLE OF TABLE-READING FROM JAVASCRIPT FOR AUTOMATION

    const
        strPath = '~/Library/Containers/com.culturedcode.ThingsMac/' +
        'Data/Library/Application\ Support/' +
        'Cultured\ Code/Things/Things.sqlite3',

        strSQL = 'SELECT title FROM TMTask';

    const
        SQLITE_OK = parseInt($.SQLITE_OK, 10),
        SQLITE_ROW = parseInt($.SQLITE_ROW, 10),
        ppDb = Ref();

    const lrRows = (
        bindEither(
            bindEither(
                $.sqlite3_open(filePath(strPath), ppDb) !== SQLITE_OK ? (
                    Left($.sqlite3_errmsg(ppDb[0]))
                ) : Right(ppDb[0]),

                db => {
                    const ppStmt = Ref();
                    return $.sqlite3_prepare_v2(
                        db, strSQL, -1, ppStmt, Ref()
                    ) !== SQLITE_OK ? (
                        Left($.sqlite3_errmsg(db))
                    ) : Right(Tuple(db, ppStmt[0]));
                }
            ),

            tpl => Right(unfoldr(
                stmt => SQLITE_ROW === $.sqlite3_step(stmt) ? (
                    Just(Tuple(
                        $.sqlite3_column_text(stmt, 0),
                        stmt
                    ))
                ) : (
                    $.sqlite3_finalize(stmt),
                    $.sqlite3_close(tpl[0]),
                    Nothing()
                ),
                tpl[1]
            ))
        )
    );

    return showJSON(
        lrRows.Right || lrRows.Left
    );
})();


A better way to use SQLite?