Skip to content

Commit 4338b04

Browse files
committed
hail eris
0 parents  commit 4338b04

9 files changed

Lines changed: 816 additions & 0 deletions

File tree

.github/workflows/test.yml

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
name: test pg_ddate
2+
3+
on:
4+
push:
5+
branches: [ main ]
6+
pull_request:
7+
branches: [ main ]
8+
9+
jobs:
10+
test:
11+
runs-on: ubuntu-latest
12+
strategy:
13+
matrix:
14+
postgres: [14, 15, 16, 17]
15+
16+
name: PostgreSQL ${{ matrix.postgres }}
17+
18+
steps:
19+
- name: Checkout code
20+
uses: actions/checkout@v4
21+
22+
- name: Set up Docker Buildx
23+
uses: docker/setup-buildx-action@v3
24+
25+
- name: Build Docker image
26+
run: |
27+
sed -i 's/postgres:16/postgres:${{ matrix.postgres }}/g' Dockerfile
28+
sed -i 's/postgresql-server-dev-16/postgresql-server-dev-${{ matrix.postgres }}/g' Dockerfile
29+
docker build -t pg_ddate .
30+
31+
- name: Run tests
32+
run: |
33+
docker run --rm -d --name pg_ddate_test -e POSTGRES_HOST_AUTH_METHOD=trust pg_ddate
34+
sleep 5
35+
docker cp test.sql pg_ddate_test:/tmp/test.sql
36+
docker exec pg_ddate_test psql -U postgres -v ON_ERROR_STOP=1 -f /tmp/test.sql
37+
38+
test-features:
39+
runs-on: ubuntu-latest
40+
name: Feature Tests
41+
42+
steps:
43+
- name: Checkout code
44+
uses: actions/checkout@v4
45+
46+
- name: Build and test
47+
run: make docker-test
48+
49+
- name: Test holiday input parsing
50+
run: |
51+
docker run --rm -d --name pg_feature_test -e POSTGRES_HOST_AUTH_METHOD=trust pg_ddate
52+
sleep 10
53+
echo "Testing holiday input parsing..."
54+
docker exec pg_feature_test psql -U postgres -v ON_ERROR_STOP=1 -c "
55+
CREATE EXTENSION pg_ddate;
56+
SELECT 'Mungday, Chaos 5, 3191 YOLD'::ddate;
57+
SELECT 'Chaoflux, Chaos 50, 3191 YOLD'::ddate;
58+
SELECT 'Discoflux, Discord 50, 3191 YOLD'::ddate;
59+
"
60+
61+
echo "Testing ~ operator..."
62+
docker exec pg_feature_test psql -U postgres -v ON_ERROR_STOP=1 -c "
63+
SELECT '2025-02-19'::date::ddate ~ 'Chaoflux' AS flux_test;
64+
SELECT '2025-01-01'::date::ddate ~ 'Sweetmorn' AS weekday_test;
65+
SELECT '2025-01-01'::date::ddate ~ '3191 YOLD' AS year_test;
66+
SELECT '2025-01-01'::date::ddate ~ 'Discord' AS false_test;
67+
"
68+
69+
echo "Testing flux holidays are correctly displayed..."
70+
docker exec pg_feature_test psql -U postgres -v ON_ERROR_STOP=1 -c "
71+
SELECT '2025-02-19'::date::ddate; -- Should be Chaoflux
72+
SELECT '2025-05-03'::date::ddate; -- Should be Discoflux
73+
SELECT '2025-07-15'::date::ddate; -- Should be Confuflux
74+
SELECT '2025-09-26'::date::ddate; -- Should be Bureflux
75+
SELECT '2025-12-08'::date::ddate; -- Should be Afflux
76+
"
77+
78+
docker stop pg_feature_test || true

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
pg_ddate.o
2+
pg_ddate.so

Dockerfile

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
FROM postgres:16
2+
3+
RUN apt-get update && apt-get install -y \
4+
build-essential \
5+
postgresql-server-dev-16 \
6+
&& rm -rf /var/lib/apt/lists/*
7+
8+
COPY . /tmp/pg_ddate/
9+
10+
WORKDIR /tmp/pg_ddate
11+
RUN make clean && make && make install
12+
13+
RUN apt-get remove -y build-essential postgresql-server-dev-16 \
14+
&& apt-get autoremove -y \
15+
&& rm -rf /tmp/pg_ddate
16+
17+
USER postgres

Makefile

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
MODULE_big = pg_ddate
2+
OBJS = pg_ddate.o
3+
4+
EXTENSION = pg_ddate
5+
DATA = pg_ddate--1.0.sql
6+
7+
PG_CONFIG = pg_config
8+
PGXS := $(shell $(PG_CONFIG) --pgxs)
9+
include $(PGXS)
10+
11+
# Docker testing targets
12+
.PHONY: docker-build docker-test docker-clean
13+
14+
docker-build:
15+
docker build -t pg_ddate .
16+
17+
docker-test: docker-build
18+
docker run --rm -d --name pg_ddate_test -e POSTGRES_HOST_AUTH_METHOD=trust pg_ddate
19+
sleep 5
20+
docker cp test.sql pg_ddate_test:/tmp/test.sql
21+
docker exec pg_ddate_test psql -U postgres -v ON_ERROR_STOP=1 -f /tmp/test.sql
22+
docker stop pg_ddate_test
23+
24+
docker-clean:
25+
-docker stop pg_ddate_test 2>/dev/null || true
26+
-docker rm pg_ddate_test 2>/dev/null || true
27+
-docker rmi pg_ddate 2>/dev/null || true

README.md

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
# pg_ddate
2+
3+
discordian dates (the most important date system) as a postgresql extension.
4+
5+
see also [my haskell library](https://github.com/hellerve/Data.DDate).
6+
7+
## features
8+
9+
- native `ddate` type for storing discordian dates
10+
- automatic conversion between `date` and `ddate` types
11+
- full comparison operators and b-tree indexing support
12+
- Proper formatting with weekdays and holydays, including st tibb’s
13+
14+
## installation
15+
16+
honestly, i just use docker (there is a dockerfile), but if you must, you need
17+
postgresql development headers installed. so on my machine (macos), for
18+
instance, i need `brew install postgresql`.
19+
20+
then build and install the extension:
21+
22+
```bash
23+
make
24+
sudo make install
25+
```
26+
27+
alternatively, install and try via docker.
28+
29+
## usage
30+
31+
create the extension in your database:
32+
33+
```sql
34+
CREATE EXTENSION pg_ddate;
35+
```
36+
37+
### basics
38+
39+
convert regular dates to discordian dates:
40+
41+
```sql
42+
SELECT '2025-01-01'::date::ddate;
43+
-- Result: Sweetmorn, Chaos 1, 3191 YOLD
44+
45+
SELECT '2025-03-19'::date::ddate;
46+
-- Result: Prickle-Prickle, Discord 5, 3191 YOLD
47+
```
48+
49+
convert discordian dates back to regular dates:
50+
51+
```sql
52+
SELECT 'Chaos 1, 3191 YOLD'::ddate::date;
53+
-- Result: 2025-01-01
54+
```
55+
56+
current date:
57+
58+
```sql
59+
SELECT ddate_now();
60+
```
61+
62+
### comparison and ordering
63+
64+
the `ddate` type supports all standard comparison operators:
65+
66+
```sql
67+
SELECT 'Chaos 1, 3191 YOLD'::ddate < 'Discord 1, 3191 YOLD'::ddate;
68+
-- Result: true
69+
70+
-- will work as expected with ORDER BY
71+
SELECT d FROM discordian_dates ORDER BY d;
72+
```
73+
74+
## license
75+
76+
this extension is released under the postgresql license, though i really
77+
couldn’t care less what you do with it.
78+
79+
<hr/>
80+
81+
hail eris.

pg_ddate--1.0.sql

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
\echo Use "CREATE EXTENSION pg_ddate" to load this file. \quit
2+
3+
CREATE TYPE ddate;
4+
5+
CREATE OR REPLACE FUNCTION ddate_in(cstring)
6+
RETURNS ddate
7+
AS 'MODULE_PATHNAME'
8+
LANGUAGE C IMMUTABLE STRICT;
9+
10+
CREATE OR REPLACE FUNCTION ddate_out(ddate)
11+
RETURNS cstring
12+
AS 'MODULE_PATHNAME'
13+
LANGUAGE C IMMUTABLE STRICT;
14+
15+
CREATE OR REPLACE FUNCTION ddate_recv(internal)
16+
RETURNS ddate
17+
AS 'MODULE_PATHNAME'
18+
LANGUAGE C IMMUTABLE STRICT;
19+
20+
CREATE OR REPLACE FUNCTION ddate_send(ddate)
21+
RETURNS bytea
22+
AS 'MODULE_PATHNAME'
23+
LANGUAGE C IMMUTABLE STRICT;
24+
25+
CREATE TYPE ddate (
26+
internallength = 4,
27+
input = ddate_in,
28+
output = ddate_out,
29+
receive = ddate_recv,
30+
send = ddate_send,
31+
alignment = int4,
32+
storage = plain
33+
);
34+
35+
CREATE OR REPLACE FUNCTION date_to_ddate(date)
36+
RETURNS ddate
37+
AS 'MODULE_PATHNAME'
38+
LANGUAGE C IMMUTABLE STRICT;
39+
40+
CREATE OR REPLACE FUNCTION ddate_to_date(ddate)
41+
RETURNS date
42+
AS 'MODULE_PATHNAME'
43+
LANGUAGE C IMMUTABLE STRICT;
44+
45+
CREATE CAST (date AS ddate) WITH FUNCTION date_to_ddate(date) AS IMPLICIT;
46+
CREATE CAST (ddate AS date) WITH FUNCTION ddate_to_date(ddate) AS IMPLICIT;
47+
48+
CREATE OR REPLACE FUNCTION ddate_eq(ddate, ddate)
49+
RETURNS boolean
50+
AS 'MODULE_PATHNAME'
51+
LANGUAGE C IMMUTABLE STRICT;
52+
53+
CREATE OR REPLACE FUNCTION ddate_ne(ddate, ddate)
54+
RETURNS boolean
55+
AS 'MODULE_PATHNAME'
56+
LANGUAGE C IMMUTABLE STRICT;
57+
58+
CREATE OR REPLACE FUNCTION ddate_lt(ddate, ddate)
59+
RETURNS boolean
60+
AS 'MODULE_PATHNAME'
61+
LANGUAGE C IMMUTABLE STRICT;
62+
63+
CREATE OR REPLACE FUNCTION ddate_le(ddate, ddate)
64+
RETURNS boolean
65+
AS 'MODULE_PATHNAME'
66+
LANGUAGE C IMMUTABLE STRICT;
67+
68+
CREATE OR REPLACE FUNCTION ddate_gt(ddate, ddate)
69+
RETURNS boolean
70+
AS 'MODULE_PATHNAME'
71+
LANGUAGE C IMMUTABLE STRICT;
72+
73+
CREATE OR REPLACE FUNCTION ddate_ge(ddate, ddate)
74+
RETURNS boolean
75+
AS 'MODULE_PATHNAME'
76+
LANGUAGE C IMMUTABLE STRICT;
77+
78+
CREATE OR REPLACE FUNCTION ddate_cmp(ddate, ddate)
79+
RETURNS integer
80+
AS 'MODULE_PATHNAME'
81+
LANGUAGE C IMMUTABLE STRICT;
82+
83+
CREATE OPERATOR = (
84+
leftarg = ddate,
85+
rightarg = ddate,
86+
procedure = ddate_eq,
87+
commutator = =,
88+
negator = <>,
89+
restrict = eqsel,
90+
join = eqjoinsel,
91+
hashes,
92+
merges
93+
);
94+
95+
CREATE OPERATOR <> (
96+
leftarg = ddate,
97+
rightarg = ddate,
98+
procedure = ddate_ne,
99+
commutator = <>,
100+
negator = =,
101+
restrict = neqsel,
102+
join = neqjoinsel
103+
);
104+
105+
CREATE OPERATOR < (
106+
leftarg = ddate,
107+
rightarg = ddate,
108+
procedure = ddate_lt,
109+
commutator = >,
110+
negator = >=,
111+
restrict = scalarltsel,
112+
join = scalarltjoinsel
113+
);
114+
115+
CREATE OPERATOR <= (
116+
leftarg = ddate,
117+
rightarg = ddate,
118+
procedure = ddate_le,
119+
commutator = >=,
120+
negator = >,
121+
restrict = scalarltsel,
122+
join = scalarltjoinsel
123+
);
124+
125+
CREATE OPERATOR > (
126+
leftarg = ddate,
127+
rightarg = ddate,
128+
procedure = ddate_gt,
129+
commutator = <,
130+
negator = <=,
131+
restrict = scalargtsel,
132+
join = scalargtjoinsel
133+
);
134+
135+
CREATE OPERATOR >= (
136+
leftarg = ddate,
137+
rightarg = ddate,
138+
procedure = ddate_ge,
139+
commutator = <=,
140+
negator = <,
141+
restrict = scalargtsel,
142+
join = scalargtjoinsel
143+
);
144+
145+
CREATE OPERATOR CLASS ddate_ops
146+
DEFAULT FOR TYPE ddate USING btree AS
147+
OPERATOR 1 <,
148+
OPERATOR 2 <=,
149+
OPERATOR 3 =,
150+
OPERATOR 4 >=,
151+
OPERATOR 5 >,
152+
FUNCTION 1 ddate_cmp(ddate, ddate);
153+
154+
CREATE OR REPLACE FUNCTION ddate_now()
155+
RETURNS ddate
156+
AS 'MODULE_PATHNAME'
157+
LANGUAGE C VOLATILE;
158+
159+
CREATE OR REPLACE FUNCTION ddate_regexeq(ddate, text)
160+
RETURNS boolean
161+
AS 'MODULE_PATHNAME'
162+
LANGUAGE C IMMUTABLE STRICT;
163+
164+
CREATE OPERATOR ~ (
165+
leftarg = ddate,
166+
rightarg = text,
167+
procedure = ddate_regexeq,
168+
restrict = regexeqsel,
169+
join = regexeqjoinsel
170+
);

0 commit comments

Comments
 (0)