Skip to content

Commit 61b67ac

Browse files
committed
Merge branch 'issue-84-plan-docs-and-packaging' into issue-83-plan-replicator-sync-sqlite
2 parents 1c86f48 + 32c2275 commit 61b67ac

File tree

15 files changed

+564
-35
lines changed

15 files changed

+564
-35
lines changed

.github/workflows/release.yml

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,18 +23,26 @@ jobs:
2323
target: x86_64-unknown-linux-gnu
2424
artifact_name: database-replicator
2525
asset_name: database-replicator-linux-x64-binary
26+
watcher_artifact: sqlite-watcher
27+
watcher_asset: sqlite-watcher-linux-x64
2628
- os: macos-latest
2729
target: x86_64-apple-darwin
2830
artifact_name: database-replicator
2931
asset_name: database-replicator-macos-x64-binary
32+
watcher_artifact: sqlite-watcher
33+
watcher_asset: sqlite-watcher-macos-x64
3034
- os: macos-latest
3135
target: aarch64-apple-darwin
3236
artifact_name: database-replicator
3337
asset_name: database-replicator-macos-arm64-binary
38+
watcher_artifact: sqlite-watcher
39+
watcher_asset: sqlite-watcher-macos-arm64
3440
- os: windows-latest
3541
target: x86_64-pc-windows-msvc
3642
artifact_name: database-replicator.exe
3743
asset_name: database-replicator-windows-x64.exe
44+
watcher_artifact: sqlite-watcher.exe
45+
watcher_asset: sqlite-watcher-windows-x64.exe
3846
steps:
3947
- name: Checkout code
4048
uses: actions/checkout@v4
@@ -75,6 +83,9 @@ jobs:
7583
- name: Build release binary
7684
run: cargo build --release --target ${{ matrix.target }} --verbose
7785

86+
- name: Build sqlite-watcher binary
87+
run: cargo build --release --target ${{ matrix.target }} -p sqlite-watcher --verbose
88+
7889
- name: Strip binary (Linux)
7990
if: matrix.os == 'ubuntu-latest'
8091
run: strip target/${{ matrix.target }}/release/${{ matrix.artifact_name }}
@@ -89,19 +100,38 @@ jobs:
89100
cp target/${{ matrix.target }}/release/${{ matrix.artifact_name }} ${{ matrix.asset_name }}
90101
chmod +x ${{ matrix.asset_name }}
91102
103+
- name: Rename sqlite-watcher (Unix)
104+
if: matrix.os != 'windows-latest'
105+
run: |
106+
cp target/${{ matrix.target }}/release/${{ matrix.watcher_artifact }} ${{ matrix.watcher_asset }}
107+
chmod +x ${{ matrix.watcher_asset }}
108+
92109
- name: Rename binary (Windows)
93110
if: matrix.os == 'windows-latest'
94111
run: |
95112
copy target\${{ matrix.target }}\release\${{ matrix.artifact_name }} ${{ matrix.asset_name }}
96113
shell: cmd
97114

115+
- name: Rename sqlite-watcher (Windows)
116+
if: matrix.os == 'windows-latest'
117+
run: |
118+
copy target\${{ matrix.target }}\release\${{ matrix.watcher_artifact }} ${{ matrix.watcher_asset }}
119+
shell: cmd
120+
98121
- name: Upload artifact
99122
uses: actions/upload-artifact@v4
100123
with:
101124
name: ${{ matrix.asset_name }}
102125
path: ${{ matrix.asset_name }}
103126
if-no-files-found: error
104127

128+
- name: Upload sqlite-watcher artifact
129+
uses: actions/upload-artifact@v4
130+
with:
131+
name: ${{ matrix.watcher_asset }}
132+
path: ${{ matrix.watcher_asset }}
133+
if-no-files-found: error
134+
105135
create-release:
106136
name: Create GitHub Release
107137
needs: build-release

CHANGELOG.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ All notable changes to this project will be documented in this file.
9797

9898
### Changed
9999

100-
- **README-SQLite.md**: Updated all examples to include `-y` flag and added notes explaining that interactive mode only works with PostgreSQL sources.
100+
- **sqlite-watcher-docs/README-SQLite.md**: Updated all examples to include `-y` flag and added notes explaining that interactive mode only works with PostgreSQL sources.
101101

102102
## [7.0.4] - 2025-12-09
103103

@@ -408,7 +408,7 @@ All notable changes to this project will be documented in this file.
408408
- **File-based migration** (local execution only, no remote support)
409409
- **Path validation** with directory traversal prevention
410410
- **Comprehensive security testing**: 14 SQLite-specific tests
411-
- **Documentation**: [README-SQLite.md](README-SQLite.md) with usage examples
411+
- **Documentation**: [sqlite-watcher-docs/README-SQLite.md](sqlite-watcher-docs/README-SQLite.md) with usage examples
412412
- **Integration tests**: Full workflow testing with real SQLite files
413413

414414
#### MongoDB Support (Phase 2)
@@ -491,7 +491,7 @@ All notable changes to this project will be documented in this file.
491491

492492
- **[README.md](README.md)** - Universal landing page with multi-database support
493493
- **[README-PostgreSQL.md](README-PostgreSQL.md)** - Comprehensive PostgreSQL replication guide (1,000+ lines)
494-
- **[README-SQLite.md](README-SQLite.md)** - Complete SQLite migration guide
494+
- **[sqlite-watcher-docs/README-SQLite.md](sqlite-watcher-docs/README-SQLite.md)** - Complete SQLite migration guide
495495
- **[README-MongoDB.md](README-MongoDB.md)** - Complete MongoDB migration guide with periodic refresh
496496
- **[README-MySQL.md](README-MySQL.md)** - Complete MySQL/MariaDB migration guide
497497
- **[docs/plans/multi-database-support.md](docs/plans/multi-database-support.md)** - Implementation plan and architecture

Cargo.lock

Lines changed: 13 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ indicatif = "0.18"
3636
which = "6.0"
3737
home = ">=0.5.4, <0.5.12" # Pin to avoid v0.5.12 which requires unstable edition2024
3838
rand = "0.8"
39-
reqwest = { version = "0.11", features = ["json"] }
39+
# Disable rustls to avoid pulling rustls-pemfile (unmaintained)
40+
reqwest = { version = "0.11", default-features = false, features = ["json", "native-tls"] }
4041
serde = { version = "1.0", features = ["derive"] }
4142
serde_json = "1.0"
4243
sha2 = "0.10"
@@ -55,6 +56,9 @@ tonic = { version = "0.11", features = ["transport"] }
5556
tower = "0.4"
5657
sqlite-watcher = { path = "sqlite-watcher" }
5758

59+
[patch.crates-io]
60+
fxhash = { path = "third-party/fxhash" }
61+
5862
[target.'cfg(unix)'.dependencies]
5963
daemonize = "0.5"
6064

Dockerfile

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,22 @@
22

33
FROM ubuntu:24.04 AS downloader
44
ARG VERSION=latest
5-
ENV BINARY_NAME=database-replicator-linux-x64-binary
5+
ENV REPLICATOR_ASSET=database-replicator-linux-x64-binary
6+
ENV WATCHER_ASSET=sqlite-watcher-linux-x64
67
ENV RELEASE_ROOT=https://github.com/serenorg/database-replicator/releases
78

89
RUN apt-get update && apt-get install -y --no-install-recommends curl ca-certificates && rm -rf /var/lib/apt/lists/*
910

1011
RUN set -eux; \
1112
if [ "$VERSION" = "latest" ]; then \
12-
URL="$RELEASE_ROOT/latest/download/$BINARY_NAME"; \
13+
REP_URL="$RELEASE_ROOT/latest/download/$REPLICATOR_ASSET"; \
14+
WATCH_URL="$RELEASE_ROOT/latest/download/$WATCHER_ASSET"; \
1315
else \
14-
URL="$RELEASE_ROOT/download/$VERSION/$BINARY_NAME"; \
16+
REP_URL="$RELEASE_ROOT/download/$VERSION/$REPLICATOR_ASSET"; \
17+
WATCH_URL="$RELEASE_ROOT/download/$VERSION/$WATCHER_ASSET"; \
1518
fi; \
16-
curl -fL "$URL" -o /tmp/database-replicator && \
17-
chmod +x /tmp/database-replicator
19+
curl -fL "$REP_URL" -o /tmp/database-replicator && chmod +x /tmp/database-replicator && \
20+
curl -fL "$WATCH_URL" -o /tmp/sqlite-watcher && chmod +x /tmp/sqlite-watcher
1821

1922
FROM ubuntu:24.04
2023
LABEL org.opencontainers.image.title="database-replicator" \
@@ -27,6 +30,7 @@ RUN apt-get update && \
2730
useradd -m replicator
2831

2932
COPY --from=downloader /tmp/database-replicator /usr/local/bin/database-replicator
33+
COPY --from=downloader /tmp/sqlite-watcher /usr/local/bin/sqlite-watcher
3034
USER replicator
3135
ENTRYPOINT ["database-replicator"]
3236
CMD ["--help"]

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ database-replicator init \
139139
--target "postgresql://user:pass@host:5432/db"
140140
```
141141

142-
**[📖 Full SQLite Guide →](README-SQLite.md)**
142+
**[📖 Full SQLite Guide →](sqlite-watcher-docs/README-SQLite.md)**
143143

144144
---
145145

@@ -302,7 +302,7 @@ docker run --rm -it \
302302
### Database-Specific Guides
303303

304304
- **[PostgreSQL to PostgreSQL](README-PostgreSQL.md)** - Zero-downtime replication with logical replication
305-
- **[SQLite to PostgreSQL](README-SQLite.md)** - One-time replication using JSONB storage
305+
- **[SQLite to PostgreSQL](sqlite-watcher-docs/README-SQLite.md)** - One-time replication using JSONB storage
306306
- **[MongoDB to PostgreSQL](README-MongoDB.md)** - One-time replication with periodic refresh support
307307
- **[MySQL/MariaDB to PostgreSQL](README-MySQL.md)** - One-time replication with periodic refresh support
308308

scripts/test-sqlite-delta.sh

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
#!/usr/bin/env bash
2+
# Smoke test for sqlite-watcher + database-replicator incremental sync
3+
# Requires: docker, sqlite-watcher, database-replicator, sqlite3
4+
5+
set -euo pipefail
6+
7+
if ! command -v docker >/dev/null; then
8+
echo "[smoke] docker is required" >&2
9+
exit 1
10+
fi
11+
if ! command -v sqlite-watcher >/dev/null; then
12+
echo "[smoke] sqlite-watcher binary not found in PATH" >&2
13+
exit 1
14+
fi
15+
if ! command -v database-replicator >/dev/null; then
16+
echo "[smoke] database-replicator binary not found in PATH" >&2
17+
exit 1
18+
fi
19+
20+
TMPDIR=$(mktemp -d)
21+
QUEUE_DB="$TMPDIR/queue.db"
22+
SOCK="$TMPDIR/watcher.sock"
23+
TOKEN_FILE="$TMPDIR/token"
24+
POSTGRES_PORT=55432
25+
CONTAINER_NAME=sqlite-delta-smoke
26+
27+
cleanup() {
28+
set +e
29+
if [[ -n "${WATCHER_PID:-}" ]]; then
30+
kill "$WATCHER_PID" >/dev/null 2>&1 || true
31+
fi
32+
docker rm -f "$CONTAINER_NAME" >/dev/null 2>&1 || true
33+
rm -rf "$TMPDIR"
34+
}
35+
trap cleanup EXIT
36+
37+
echo "[smoke] preparing token + queue"
38+
mkdir -p "$(dirname "$TOKEN_FILE")"
39+
printf 'smoke-%s' "$RANDOM" > "$TOKEN_FILE"
40+
chmod 600 "$TOKEN_FILE"
41+
42+
sqlite-watcher enqueue --queue-db "$QUEUE_DB" --table demo --id smoke --payload '{"message":"hello-from-watcher"}'
43+
44+
sqlite-watcher serve --queue-db "$QUEUE_DB" --listen "unix:$SOCK" --token-file "$TOKEN_FILE" >/dev/null 2>&1 &
45+
WATCHER_PID=$!
46+
sleep 1
47+
48+
echo "[smoke] starting postgres container"
49+
docker run -d --rm \
50+
--name "$CONTAINER_NAME" \
51+
-e POSTGRES_PASSWORD=postgres \
52+
-p "$POSTGRES_PORT":5432 \
53+
postgres:15 >/dev/null
54+
55+
until docker exec "$CONTAINER_NAME" pg_isready -U postgres >/dev/null 2>&1; do
56+
sleep 1
57+
done
58+
59+
docker exec "$CONTAINER_NAME" psql -U postgres <<'SQL'
60+
CREATE TABLE IF NOT EXISTS demo (
61+
id TEXT PRIMARY KEY,
62+
data JSONB NOT NULL,
63+
_source_type TEXT NOT NULL DEFAULT 'sqlite',
64+
_migrated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
65+
);
66+
CREATE TABLE IF NOT EXISTS sqlite_sync_state (
67+
table_name TEXT PRIMARY KEY,
68+
last_change_id BIGINT NOT NULL DEFAULT 0,
69+
last_wal_frame TEXT,
70+
cursor TEXT,
71+
snapshot_completed BOOLEAN NOT NULL DEFAULT FALSE,
72+
incremental_mode TEXT NOT NULL DEFAULT 'append',
73+
baseline_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
74+
);
75+
INSERT INTO sqlite_sync_state(table_name, snapshot_completed, incremental_mode)
76+
VALUES ('demo', TRUE, 'append')
77+
ON CONFLICT(table_name) DO UPDATE SET snapshot_completed = EXCLUDED.snapshot_completed,
78+
incremental_mode = EXCLUDED.incremental_mode;
79+
SQL
80+
81+
echo "[smoke] running sync-sqlite"
82+
DATABASE_URL="postgresql://postgres:postgres@localhost:$POSTGRES_PORT/postgres"
83+
database-replicator sync-sqlite \
84+
--target "$DATABASE_URL" \
85+
--watcher-endpoint "unix:$SOCK" \
86+
--token-file "$TOKEN_FILE" \
87+
--batch-size 50 \
88+
--incremental-mode append >/dev/null
89+
90+
docker exec "$CONTAINER_NAME" psql -U postgres -tAc "SELECT count(*) FROM demo WHERE id = 'smoke'" | grep -q '^ 1'
91+
92+
echo "[smoke] success! sqlite-watcher + sync-sqlite end-to-end"
93+
echo "[windows] Manual steps: run sqlite-watcher serve with tcp listener, start a Postgres instance (Docker Desktop works), then run database-replicator sync-sqlite with the TCP watcher endpoint."

0 commit comments

Comments
 (0)