From 224b7c7a557b6060535fe127de7be29d5142d568 Mon Sep 17 00:00:00 2001 From: Patrick Spek Date: Thu, 1 Apr 2021 07:55:09 +0200 Subject: Two posts, lost forever on my old desktop rip sessifet.tyil.net --- .../2020-12-14-raku-modules-in-gentoo-portage.md | 114 +++++++++++++++++++++ .../2020-12-15-merging-json-in-postgresql.md | 50 +++++++++ 2 files changed, 164 insertions(+) create mode 100644 src/_posts/2020-12-14-raku-modules-in-gentoo-portage.md create mode 100644 src/_posts/2020-12-15-merging-json-in-postgresql.md diff --git a/src/_posts/2020-12-14-raku-modules-in-gentoo-portage.md b/src/_posts/2020-12-14-raku-modules-in-gentoo-portage.md new file mode 100644 index 0000000..2d268d1 --- /dev/null +++ b/src/_posts/2020-12-14-raku-modules-in-gentoo-portage.md @@ -0,0 +1,114 @@ +--- +layout: post +tags: Raku Gentoo +social: + email: mailto:~tyil/public-inbox@lists.sr.ht&subject=Raku modules in Gentoo's Portage +description: > + Updates are important. This article aims to help you to learn from my + mistakes, so your updates will go smooth. +--- + +The last couple of days I've been taking another look at getting modules for +the Raku programming language into Gentoo's Portage tree. Making new packages +available in Gentoo is incredibly easy with their overlay system. + +The more complex part was Raku's side of things. While most languages just have +a certain directory to drop files in, Raku *should* use a +`CompUnit::Repository` object, which exposes the `.install` method. This is +obviously slower than just copying the files around, but there are merits to +this method. For one, it allows installation of the same module with different +versions, or from different authors. It also handles all the Unicode complexity +for you. + +{% admonition_md note %} +There *is* a +[CompUnit::Repository::FileSystem](https://docs.raku.org/type/CompUnit::Repository::FileSystem) +which would allow me to just copy over files to the right directory, however, I +quite like the ability to have multiple versions of the same module installed. +This is actually something Portage is designed with, too! +{% endadmonition_md %} + +After an email to the Raku users mailing list, I got some pointers over IRC. I +let these sink in for a couple days, considering how to approach the problem +properly. Then, one night, a solution came to mind, and I set out to test it. + +*It actually worked*. And a similar method should be usable for other +distributions too, such as Debian, OpenSUSE or Archlinux, to create packages +out of Raku modules. This should greatly improve the ability to ship Raku +programs to end-users, without requiring them to learn how Raku's ecosystem is +modeled, or which module manager it uses. + +The most important part of this approach is the +[`module-installer.raku`](https://git.sr.ht/~tyil/raku-overlay/tree/7494c81524ec1845c77dabfbb3303a34eb4b89f4/item/dev-lang/raku/files/module-installer.raku) +program, which is part of `dev-lang/raku::raku-overlay`. It accepts a path to +the module to install. It does not depend on any one module manager, so it can +be used to bootstrap a user-friendly module manager (such as +[`zef`](https://github.com/ugexe/zef/)) for the user. + +{% highlight raku %} +#| Install a Raku module. +sub MAIN ( + #| The path to the Raku module sources. + IO() $path, + + #| The repository to install it in. Options are "site" (ment for + #| user-installed modules), "vendor" (ment for distributions that want + #| to include more modules) and "core" (ment for modules distributed + #| along with Raku itself). + Str:D :$repo = 'site', + + #| Force installation of the module. + Bool:D :$force = True, +) { + CATCH { + default { $_.say; exit 1; } + } + + die "This script should be used by Portage only!" unless %*ENV; + + my $prefix = %*ENV.IO.add('usr/share/perl6').add($repo); + my $repository = CompUnit::Repository::Installation.new(:$prefix); + my $meta-file = $path.add('META6.json'); + my $dist = Distribution::Path.new($path, :$meta-file); + + $repository.install($dist, :$force); +} +{% endhighlight %} + +It's a fairly straightforward program. It checks for `$D` to be set in the +environment, which is a variable Portage sets as the destination directory to +install new files in. This directory gets merged into the root filesystem to +finalize installation of any package. + +If `$D` is set, I append the path used by Raku in Gentoo to it, followed by a +repo name. Next I create a `CompUnit::Repository` using this path. This is a +trick to get the files to appear in the right directory for Portage, to +eventually merge them in the system-wide `site` module repo used by Raku. +Additionally, I can use the `CompUnit::Repository`'s `install` method to handle +all the Raku specific parts that I don't want to handle myself. + +This leaves one last issue. By creating this new repo, I also get a couple +files that already exist in the system wide `site` repo. Portage will complain +about possible file collisions and refuse to install the package if these +remain. However, this can be solved rather easily by calling `rm` on these files. + +{% highlight sh %} +rm -- "${D}/usr/share/perl6/site/version" +rm -- "${D}/usr/share/perl6/site/repo.lock" +rm -- "${D}/usr/share/perl6/site/precomp/.lock" +{% endhighlight %} + +And with this, my test module, `IO::Path::XDG`, installs cleanly through the +power of Portage, and is usable by all users using the system-wide Raku +installation. + +To make this work for other distributions, the `module-installer.raku` program +should be modified slightly. Most notably, the `$prefix` must be altered to +point towards the right directory, so the files will be installed into whatever +directory will end up being packaged. Other than that, the standard means of +packaging can be followed. + +For the Gentoo users, this overlay is available at +[SourceHut](https://git.sr.ht/~tyil/raku-overlay). It currently holds only +`IO::Path::XDG` (`dev-raku/io-path-xdg`), but you are invited to try it out and +report any issues you may encounter. diff --git a/src/_posts/2020-12-15-merging-json-in-postgresql.md b/src/_posts/2020-12-15-merging-json-in-postgresql.md new file mode 100644 index 0000000..0d7e087 --- /dev/null +++ b/src/_posts/2020-12-15-merging-json-in-postgresql.md @@ -0,0 +1,50 @@ +--- +layout: post +tags: PostgreSQL Programming JSON +social: + email: mailto:~tyil/public-inbox@lists.sr.ht&subject=Merging JSON objects in PostgreSQL +description: > + Left unsatisfied trying to find a nice way to merge two JSON objects in + PostgreSQL, I whipped up my own. This small post shows off my glorious + concoction for future generations." +--- + +At my `$day-job` we have a lot of `jsonb` in our database. From time to time, I +have to manually run a query to fix something in there. This week was one of +those times. + +While you can pretty much do everything you need with regards to JSON editing +with `jsonb_se`t, I thought it might be nice if I were able to *merge* a given +JSON object into an existing object. This might be cleaner in some situations, +but mostly it is fun to figure it out. And who doesn’t like spending time with +`plpgsql`? + +The way I wanted to have it work is like this: + +{% highlight sql %} +UPDATE user SET properties = jsonb_merge(properties, '{"notifications": {"new_case": false, "new_document": true}}'); +{% endhighlight %} + +And this is the eventual function I produced to do it: + +{% highlight sql %} +CREATE OR REPLACE FUNCTION jsonb_merge(original jsonb, delta jsonb) RETURNS jsonb AS $$ + DECLARE result jsonb; + BEGIN + SELECT + json_object_agg( + COALESCE(original_key, delta_key), + CASE + WHEN original_value IS NULL THEN delta_value + WHEN delta_value IS NULL THEN original_value + WHEN (jsonb_typeof(original_value) <> 'object' OR jsonb_typeof(delta_value) <> 'object') THEN delta_value + ELSE jsonb_merge(original_value, delta_value) + END + ) + INTO result + FROM jsonb_each(original) e1(original_key, original_value) + FULL JOIN jsonb_each(delta) e2(delta_key, delta_value) ON original_key = delta_key; + RETURN result; +END +$$ LANGUAGE plpgsql; +{% endhighlight %} -- cgit v1.1