Skip to content

Commit 51881a1

Browse files
committed
feat: multiple versions for the pg_hashids extension
Build multiple versions of the pg_hashids extension on different PostgreSQL versions. Add test for the extensions and their upgrade on PostgreSQL 15 and 17.
1 parent 24430ee commit 51881a1

File tree

5 files changed

+253
-20
lines changed

5 files changed

+253
-20
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ result*
1919
.history
2020
.envrc
2121
.direnv
22+
.nixos-test-history
2223

2324

2425
#IDE

nix/checks.nix

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,7 @@
309309
;
310310
}
311311
// pkgs.lib.optionalAttrs (system == "x86_64-linux") {
312+
pg_hashids = import ./ext/tests/pg_hashids.nix { inherit self; inherit pkgs; };
312313
wrappers = import ./ext/tests/wrappers.nix {
313314
inherit self;
314315
inherit pkgs;

nix/ext/pg_hashids.nix

Lines changed: 86 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3,33 +3,99 @@
33
stdenv,
44
fetchFromGitHub,
55
postgresql,
6+
buildEnv,
67
}:
7-
8-
stdenv.mkDerivation rec {
8+
let
99
pname = "pg_hashids";
10-
version = "cd0e1b31d52b394a0df64079406a14a4f7387cd6";
10+
build =
11+
version: hash: revision:
12+
stdenv.mkDerivation rec {
13+
inherit pname version;
1114

12-
buildInputs = [ postgresql ];
15+
buildInputs = [ postgresql ];
1316

14-
src = fetchFromGitHub {
15-
owner = "iCyberon";
16-
repo = pname;
17-
rev = "${version}";
18-
hash = "sha256-Nmb7XLqQflYZfqj0yrewfb1Hl5YgEB5wfjBunPwIuOU=";
19-
};
17+
src = fetchFromGitHub {
18+
owner = "iCyberon";
19+
repo = pname;
20+
rev = version;
21+
inherit hash;
22+
};
23+
24+
installPhase = ''
25+
mkdir -p $out/{lib,share/postgresql/extension}
26+
27+
mv ${pname}${postgresql.dlSuffix} $out/lib/${pname}-${version}${postgresql.dlSuffix}
28+
29+
create_sql_files() {
30+
if test -f ${pname}--${version}.sql; then
31+
cp ${pname}--${version}.sql $out/share/postgresql/extension
32+
fi
33+
echo "Creating SQL files for previous versions..."
34+
if [[ "${version}" == "${latestVersion}" ]]; then
35+
cp *.sql $out/share/postgresql/extension
36+
37+
# anything after 1.2.1 is unreleased
38+
cp pg_hashids--1.3.sql $out/share/postgresql/extension/pg_hashids--${version}.sql
39+
cp pg_hashids--1.2.1--1.3.sql $out/share/postgresql/extension/pg_hashids--1.2.1--${version}.sql
40+
fi
41+
}
42+
43+
create_control_files() {
44+
sed -e "/^default_version =/d" \
45+
-e "s|^module_pathname = .*|module_pathname = '\$libdir/${pname}'|" \
46+
${pname}.control > $out/share/postgresql/extension/${pname}--${version}.control
47+
48+
if [[ "${version}" == "${latestVersion}" ]]; then
49+
{
50+
echo "default_version = '${latestVersion}'"
51+
cat $out/share/postgresql/extension/${pname}--${latestVersion}.control
52+
} > $out/share/postgresql/extension/${pname}.control
53+
ln -sfn ${pname}-${latestVersion}${postgresql.dlSuffix} $out/lib/${pname}${postgresql.dlSuffix}
54+
fi
55+
}
2056
21-
installPhase = ''
22-
mkdir -p $out/{lib,share/postgresql/extension}
57+
create_sql_files
58+
create_control_files
59+
'';
2360

24-
cp *${postgresql.dlSuffix} $out/lib
25-
cp *.sql $out/share/postgresql/extension
26-
cp *.control $out/share/postgresql/extension
61+
meta = with lib; {
62+
description = "Generate short unique IDs in PostgreSQL";
63+
homepage = "https://github.com/iCyberon/pg_hashids";
64+
license = licenses.postgresql;
65+
inherit (postgresql.meta) platforms;
66+
};
67+
};
68+
allVersions = (builtins.fromJSON (builtins.readFile ./versions.json)).pg_hashids;
69+
supportedVersions = lib.filterAttrs (
70+
_: value: builtins.elem (lib.versions.major postgresql.version) value.postgresql
71+
) allVersions;
72+
versions = lib.naturalSort (lib.attrNames supportedVersions);
73+
latestVersion = lib.last versions;
74+
numberOfVersions = builtins.length versions;
75+
packages = builtins.attrValues (
76+
lib.mapAttrs (name: value: build name value.hash (value.revision or name)) supportedVersions
77+
);
78+
in
79+
buildEnv {
80+
name = pname;
81+
paths = packages;
82+
pathsToLink = [
83+
"/lib"
84+
"/share/postgresql/extension"
85+
];
86+
postBuild = ''
87+
# checks
88+
(set -x
89+
test "$(ls -A $out/lib/${pname}*${postgresql.dlSuffix} | wc -l)" = "${
90+
toString (numberOfVersions + 1)
91+
}"
92+
)
2793
'';
2894

29-
meta = with lib; {
30-
description = "Generate short unique IDs in PostgreSQL";
31-
homepage = "https://github.com/iCyberon/pg_hashids";
32-
platforms = postgresql.meta.platforms;
33-
license = licenses.postgresql;
95+
passthru = {
96+
inherit versions numberOfVersions;
97+
pname = "${pname}-all";
98+
version =
99+
"multi-" + lib.concatStringsSep "-" (map (v: lib.replaceStrings [ "." ] [ "-" ] v) versions);
34100
};
35101
}

nix/ext/tests/pg_hashids.nix

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
{ self, pkgs }:
2+
let
3+
pname = "pg_hashids";
4+
inherit (pkgs) lib;
5+
installedExtension = postgresMajorVersion:
6+
self.packages.${pkgs.system}."psql_${postgresMajorVersion}/exts/${pname}-all";
7+
versions = postgresqlMajorVersion: (installedExtension postgresqlMajorVersion).versions;
8+
postgresqlWithExtension = postgresql:
9+
let
10+
majorVersion = lib.versions.major postgresql.version;
11+
pkg = pkgs.buildEnv {
12+
name = "postgresql-${majorVersion}-${pname}";
13+
paths = [ postgresql postgresql.lib (installedExtension majorVersion) ];
14+
passthru = {
15+
inherit (postgresql) version psqlSchema;
16+
lib = pkg;
17+
withPackages = _: pkg;
18+
};
19+
nativeBuildInputs = [ pkgs.makeWrapper ];
20+
pathsToLink = [ "/" "/bin" "/lib" ];
21+
postBuild = ''
22+
wrapProgram $out/bin/postgres --set NIX_PGLIBDIR $out/lib
23+
wrapProgram $out/bin/pg_ctl --set NIX_PGLIBDIR $out/lib
24+
wrapProgram $out/bin/pg_upgrade --set NIX_PGLIBDIR $out/lib
25+
'';
26+
};
27+
in pkg;
28+
in self.inputs.nixpkgs.lib.nixos.runTest {
29+
name = pname;
30+
hostPkgs = pkgs;
31+
nodes.server = { config, ... }: {
32+
virtualisation = {
33+
forwardPorts = [{
34+
from = "host";
35+
host.port = 13022;
36+
guest.port = 22;
37+
}];
38+
};
39+
services.openssh = { enable = true; };
40+
users.users.root.openssh.authorizedKeys.keys = [
41+
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIo+ulCUfJjnCVgfM4946Ih5Nm8DeZZiayYeABHGPEl7 jfroche"
42+
];
43+
44+
services.postgresql = {
45+
enable = true;
46+
package =
47+
postgresqlWithExtension self.packages.${pkgs.system}.postgresql_15;
48+
};
49+
50+
specialisation.postgresql17.configuration = {
51+
services.postgresql = {
52+
package = lib.mkForce
53+
(postgresqlWithExtension self.packages.${pkgs.system}.postgresql_17);
54+
};
55+
56+
systemd.services.postgresql-migrate = {
57+
serviceConfig = {
58+
Type = "oneshot";
59+
RemainAfterExit = true;
60+
User = "postgres";
61+
Group = "postgres";
62+
StateDirectory = "postgresql";
63+
WorkingDirectory =
64+
"${builtins.dirOf config.services.postgresql.dataDir}";
65+
};
66+
script = let
67+
oldPostgresql =
68+
postgresqlWithExtension self.packages.${pkgs.system}.postgresql_15;
69+
newPostgresql =
70+
postgresqlWithExtension self.packages.${pkgs.system}.postgresql_17;
71+
oldDataDir = "${
72+
builtins.dirOf config.services.postgresql.dataDir
73+
}/${oldPostgresql.psqlSchema}";
74+
newDataDir = "${
75+
builtins.dirOf config.services.postgresql.dataDir
76+
}/${newPostgresql.psqlSchema}";
77+
in ''
78+
if [[ ! -d ${newDataDir} ]]; then
79+
install -d -m 0700 -o postgres -g postgres "${newDataDir}"
80+
${newPostgresql}/bin/initdb -D "${newDataDir}"
81+
${newPostgresql}/bin/pg_upgrade --old-datadir "${oldDataDir}" --new-datadir "${newDataDir}" \
82+
--old-bindir "${oldPostgresql}/bin" --new-bindir "${newPostgresql}/bin"
83+
else
84+
echo "${newDataDir} already exists"
85+
fi
86+
'';
87+
};
88+
89+
systemd.services.postgresql = {
90+
after = [ "postgresql-migrate.service" ];
91+
requires = [ "postgresql-migrate.service" ];
92+
};
93+
};
94+
95+
};
96+
testScript = { nodes, ... }:
97+
let
98+
pg17-configuration =
99+
"${nodes.server.system.build.toplevel}/specialisation/postgresql17";
100+
in ''
101+
versions = {
102+
"15": [${lib.concatStringsSep ", " (map (s: ''"${s}"'') (versions "15"))}],
103+
"17": [${lib.concatStringsSep ", " (map (s: ''"${s}"'') (versions "17"))}],
104+
}
105+
106+
def run_sql(query):
107+
return server.succeed(f"""sudo -u postgres psql -t -A -F\",\" -c \"{query}\" """).strip()
108+
109+
def check_upgrade_path(pg_version):
110+
with subtest("Check ${pname} upgrade path"):
111+
firstVersion = versions[pg_version][0]
112+
server.succeed("sudo -u postgres psql -c 'DROP EXTENSION IF EXISTS ${pname};'")
113+
run_sql(f"""CREATE EXTENSION ${pname} WITH VERSION '{firstVersion}';""")
114+
installed_version = run_sql(r"""SELECT extversion FROM pg_extension WHERE extname = '${pname}';""")
115+
assert installed_version == firstVersion, f"Expected ${pname} version {firstVersion}, but found {installed_version}"
116+
for version in versions[pg_version][1:]:
117+
run_sql(f"""ALTER EXTENSION ${pname} UPDATE TO '{version}';""")
118+
installed_version = run_sql(r"""SELECT extversion FROM pg_extension WHERE extname = '${pname}';""")
119+
assert installed_version == version, f"Expected ${pname} version {version}, but found {installed_version}"
120+
121+
start_all()
122+
123+
server.wait_for_unit("multi-user.target")
124+
server.wait_for_unit("postgresql.service")
125+
126+
check_upgrade_path("15")
127+
128+
with subtest("Check ${pname} latest extension version"):
129+
server.succeed("sudo -u postgres psql -c 'DROP EXTENSION ${pname};'")
130+
server.succeed("sudo -u postgres psql -c 'CREATE EXTENSION ${pname};'")
131+
installed_extensions=run_sql(r"""SELECT extname, extversion FROM pg_extension;""")
132+
latestVersion = versions["15"][-1]
133+
assert f"${pname},{latestVersion}" in installed_extensions
134+
135+
with subtest("switch to postgresql 17"):
136+
server.succeed(
137+
"${pg17-configuration}/bin/switch-to-configuration test >&2"
138+
)
139+
140+
with subtest("Check ${pname} latest extension version"):
141+
installed_extensions=run_sql(r"""SELECT extname, extversion FROM pg_extension;""")
142+
latestVersion = versions["17"][-1]
143+
assert f"${pname},{latestVersion}" in installed_extensions
144+
145+
check_upgrade_path("17")
146+
'';
147+
}

nix/ext/versions.json

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,5 +20,23 @@
2020
],
2121
"hash": "sha256-G0eQk2bY5CNPMeokN/nb05g03CuiplRf902YXFVQFbs="
2222
}
23+
},
24+
"pg_hashids": {
25+
"1.2.1": {
26+
"postgresql": [
27+
"15",
28+
"17"
29+
],
30+
"revision": "v1.2.1",
31+
"hash": "sha256-2yQ0JrhwZF9dGEIydOviDpQ+3ZhJ8T16dQt6KIirAJ0="
32+
},
33+
"1.3.0-cd0e1b31d52b394a0df64079406a14a4f7387cd6": {
34+
"postgresql": [
35+
"15",
36+
"17"
37+
],
38+
"revision": "cd0e1b31d52b394a0df64079406a14a4f7387cd6",
39+
"hash": "sha256-Nmb7XLqQflYZfqj0yrewfb1Hl5YgEB5wfjBunPwIuOU="
40+
}
2341
}
2442
}

0 commit comments

Comments
 (0)