Skip to content

Commit 2565bdf

Browse files
committed
Simplified mssql init script and renamed env variables for clarity
1 parent 096d477 commit 2565bdf

File tree

5 files changed

+121
-156
lines changed

5 files changed

+121
-156
lines changed

demos/nodejs-mssql/.env

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,18 @@
11
# ==================== MSSQL credentials ================================
2-
# "sa" (sysadmin) is the root user for MSSQL required for initial database setup
3-
SA_PASSWORD=321strongROOTpassword!
2+
ROOT_PASSWORD=321strongROOTpassword!
43
HOSTNAME=mssql-selfhosted
5-
APP_DB=powersync
6-
APP_LOGIN=powersync_user
7-
APP_PASSWORD=strongPOWERSYNCUSERpassword321!
4+
DATABASE=powersync
5+
DB_USER=powersync_user
6+
DB_USER_PASSWORD=strongPOWERSYNCUSERpassword321!
87

9-
PS_DATA_SOURCE_URI=mssql://${APP_LOGIN}:${APP_PASSWORD}@${HOSTNAME}:1433/${APP_DB}
8+
PS_DATA_SOURCE_URI=mssql://${DB_USER}:${DB_USER_PASSWORD}@${HOSTNAME}:1433/${DATABASE}
109

1110
# ==================== Demo config =========================================
1211
DEMO_BACKEND_PORT=6060
1312
DEMO_BACKEND_DATABASE_TYPE=mssql
1413
DEMO_BACKEND_DATABASE_URI=${PS_DATA_SOURCE_URI}
1514
# The front-end demo application is accessible at this port on the host machine
16-
DEMO_CLIENT_PORT=3035
15+
DEMO_CLIENT_PORT=3036
1716
PS_JWKS_URL=http://demo-backend:${DEMO_BACKEND_PORT}/api/auth/keys
1817

1918
# These can be generated by following the instructions in the `key-generator` folder

demos/nodejs-mssql/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ or in the root directory run
2020
docker compose -f demos/nodejs-mssql/docker-compose.yaml up
2121
```
2222

23-
The frontend can be accessed at `http://localhost:3035` in a browser.
23+
The frontend can be accessed at `http://localhost:3036` in a browser.
2424

2525
## Configuration
2626

services/mssql/.env.template

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
ROOT_PASSWORD=321strongROOTpassword!
2+
DATABASE=powersync
3+
DB_USER=powersync_user
4+
DB_USER_PASSWORD=strongPOWERSYNCUSERpassword321!

services/mssql/init.sql

Lines changed: 102 additions & 140 deletions
Original file line numberDiff line numberDiff line change
@@ -1,192 +1,154 @@
11
-- Create database (idempotent)
2-
DECLARE @db sysname = '$(APP_DB)';
3-
IF DB_ID(@db) IS NULL
2+
IF DB_ID('$(DATABASE)') IS NULL
43
BEGIN
5-
DECLARE @sql nvarchar(max) = N'CREATE DATABASE [' + @db + N'];';
6-
EXEC(@sql);
4+
CREATE DATABASE [$(DATABASE)];
75
END
86
GO
97

108
-- Enable CDC at the database level (idempotent)
11-
DECLARE @db sysname = '$(APP_DB)';
12-
DECLARE @cmd nvarchar(max) = N'USE [' + @db + N'];
13-
IF EXISTS (SELECT 1 FROM sys.databases WHERE name = ''' + @db + N''' AND is_cdc_enabled = 0)
14-
EXEC sys.sp_cdc_enable_db;';
15-
EXEC(@cmd);
9+
USE [$(DATABASE)];
10+
IF (SELECT is_cdc_enabled FROM sys.databases WHERE name = '$(DATABASE)') = 0
11+
BEGIN
12+
EXEC sys.sp_cdc_enable_db;
13+
END
1614
GO
1715

18-
19-
-- Create a SQL login (server) and user (db), then grant CDC read access
20-
-- Note: 'cdc_reader' role is auto-created when CDC is enabled on the DB.
21-
DECLARE @db sysname = '$(APP_DB)';
22-
DECLARE @login sysname = '$(APP_LOGIN)';
23-
DECLARE @password nvarchar(128) = '$(APP_PASSWORD)';
24-
-- Create login if missing
25-
IF NOT EXISTS (SELECT 1 FROM sys.server_principals WHERE name = @login)
16+
-- Create a SQL login (server) if missing
17+
USE [master];
18+
IF NOT EXISTS (SELECT 1 FROM sys.server_principals WHERE name = '$(DB_USER)')
2619
BEGIN
27-
DECLARE @mklogin nvarchar(max) = N'CREATE LOGIN [' + @login + N'] WITH PASSWORD = ''' + @password + N''', CHECK_POLICY = ON;';
28-
EXEC(@mklogin);
29-
END;
20+
CREATE LOGIN [$(DB_USER)] WITH PASSWORD = '$(DB_USER_PASSWORD)', CHECK_POLICY = ON;
21+
END
22+
GO
3023

31-
-- Create user in DB if missing
32-
DECLARE @mkuser nvarchar(max) = N'USE [' + @db + N'];
33-
IF NOT EXISTS (SELECT 1 FROM sys.database_principals WHERE name = ''' + @login + N''')
34-
CREATE USER [' + @login + N'] FOR LOGIN [' + @login + N'];';
35-
EXEC(@mkuser);
24+
-- Create DB user for the app DB if missing
25+
USE [$(DATABASE)];
26+
IF NOT EXISTS (SELECT 1 FROM sys.database_principals WHERE name = '$(DB_USER)')
27+
BEGIN
28+
CREATE USER [$(DB_USER)] FOR LOGIN [$(DB_USER)];
29+
END
3630
GO
3731

38-
USE [MASTER];
39-
GRANT VIEW SERVER PERFORMANCE STATE TO [$(APP_LOGIN)];
32+
-- Required for PowerSync to access the sys.dm_db_log_stats DMV
33+
USE [master];
34+
GRANT VIEW SERVER PERFORMANCE STATE TO [$(DB_USER)];
4035
GO
4136

42-
USE [$(APP_DB)];
43-
GRANT VIEW DATABASE PERFORMANCE STATE TO [$(APP_LOGIN)];
37+
-- Required for PowerSync to access the sys.dm_db_log_stats DMV and the sys.dm_db_partition_stats DMV
38+
USE [$(DATABASE)];
39+
GRANT VIEW DATABASE PERFORMANCE STATE TO [$(DB_USER)];
4440
GO
4541

4642
-- Create PowerSync checkpoints table
47-
USE [$(APP_DB)];
43+
-- Powersync requires this table to ensure regular checkpoints appear in CDC
4844
IF OBJECT_ID('dbo._powersync_checkpoints', 'U') IS NULL
4945
BEGIN
50-
CREATE TABLE dbo._powersync_checkpoints (
51-
id INT IDENTITY PRIMARY KEY,
52-
last_updated DATETIME NOT NULL DEFAULT (GETDATE())
53-
);
54-
END;
46+
CREATE TABLE dbo._powersync_checkpoints (
47+
id INT IDENTITY PRIMARY KEY,
48+
last_updated DATETIME NOT NULL DEFAULT (GETDATE())
49+
);
50+
END
5551

56-
GRANT INSERT, UPDATE ON dbo._powersync_checkpoints TO [$(APP_LOGIN)];
52+
GRANT INSERT, UPDATE ON dbo._powersync_checkpoints TO [$(DB_USER)];
53+
GO
5754

58-
-- Enable CDC for checkpoints table
59-
DECLARE @enableCheckpointsTable nvarchar(max) =
60-
'IF NOT EXISTS (
61-
SELECT 1
62-
FROM cdc.change_tables
63-
WHERE source_object_id = OBJECT_ID(N''dbo._powersync_checkpoints'')
64-
)
55+
-- Enable CDC for the powersync checkpoints table
56+
IF NOT EXISTS (SELECT 1 FROM cdc.change_tables WHERE source_object_id = OBJECT_ID(N'dbo._powersync_checkpoints'))
6557
BEGIN
66-
EXEC sys.sp_cdc_enable_table
67-
@source_schema = N''dbo'',
68-
@source_name = N''_powersync_checkpoints'',
69-
@role_name = N''cdc_reader'',
70-
@supports_net_changes = 1;
71-
END;';
72-
EXEC(@enableCheckpointsTable);
58+
EXEC sys.sp_cdc_enable_table
59+
@source_schema = N'dbo',
60+
@source_name = N'_powersync_checkpoints',
61+
@role_name = N'cdc_reader',
62+
@supports_net_changes = 0;
63+
END
7364
GO
7465

75-
-- Wait until capture job exists
66+
-- Wait until capture job exists - usually takes a few seconds after enabling CDC on a table for the first time
7667
DECLARE @tries int = 10;
77-
WHILE @tries > 0 AND NOT EXISTS (
78-
SELECT 1 FROM msdb.dbo.cdc_jobs WHERE job_type = N'capture'
79-
)
68+
WHILE @tries > 0 AND NOT EXISTS (SELECT 1 FROM msdb.dbo.cdc_jobs WHERE job_type = N'capture')
8069
BEGIN
8170
WAITFOR DELAY '00:00:01';
8271
SET @tries -= 1;
8372
END;
8473

8574
-- Set the CDC capture job polling interval to 1 second (default is 5 seconds)
86-
-- Stops cdc job and restarts cdc job for new polling interval to take affect
87-
-- Now it's safe
8875
EXEC sys.sp_cdc_change_job @job_type = N'capture', @pollinginterval = 1;
8976
GO
9077

9178
/* -----------------------------------------------------------
92-
Create tables and enable CDC on them.
93-
You must enable CDC per table to actually capture changes.
94-
Example below creates the demo tables and enables CDC on it.
79+
Create demo lists and todos tables and enables CDC on them.
80+
CDC must be enabled per table to actually capture changes.
9581
------------------------------------------------------------*/
96-
97-
DECLARE @db sysname = '$(APP_DB)';
98-
EXEC(N'USE [' + @db + N'];
99-
IF OBJECT_ID(''dbo.lists'', ''U'') IS NULL
82+
IF OBJECT_ID('dbo.lists', 'U') IS NULL
10083
BEGIN
101-
CREATE TABLE dbo.lists (
102-
id UNIQUEIDENTIFIER NOT NULL DEFAULT NEWID(), -- GUID (36 characters),
103-
created_at DATETIME2 NOT NULL DEFAULT SYSUTCDATETIME(),
104-
name NVARCHAR(MAX) NOT NULL,
105-
owner_id UNIQUEIDENTIFIER NOT NULL,
106-
CONSTRAINT PK_lists PRIMARY KEY (id)
107-
);
108-
END;
109-
');
84+
CREATE TABLE dbo.lists (
85+
id UNIQUEIDENTIFIER NOT NULL DEFAULT NEWID(),
86+
created_at DATETIME2 NOT NULL DEFAULT SYSUTCDATETIME(),
87+
name NVARCHAR(MAX) NOT NULL,
88+
owner_id UNIQUEIDENTIFIER NOT NULL,
89+
CONSTRAINT PK_lists PRIMARY KEY (id)
90+
);
91+
END
11092

111-
GRANT INSERT, UPDATE, DELETE ON dbo.lists TO [$(APP_LOGIN)];
93+
GRANT INSERT, UPDATE, DELETE ON dbo.lists TO [$(DB_USER)];
94+
GO
11295

113-
EXEC(N'USE [' + @db + N'];
114-
IF OBJECT_ID(''dbo.todos'', ''U'') IS NULL
96+
IF OBJECT_ID('dbo.todos', 'U') IS NULL
11597
BEGIN
116-
CREATE TABLE dbo.todos (
117-
id UNIQUEIDENTIFIER NOT NULL DEFAULT NEWID(), -- GUID (36 characters)
118-
created_at DATETIME2 NOT NULL DEFAULT SYSUTCDATETIME(),
119-
completed_at DATETIME2 NULL,
120-
description NVARCHAR(MAX) NOT NULL,
121-
completed BIT NOT NULL DEFAULT 0,
122-
created_by UNIQUEIDENTIFIER NULL,
123-
completed_by UNIQUEIDENTIFIER NULL,
124-
list_id UNIQUEIDENTIFIER NOT NULL,
125-
CONSTRAINT PK_todos PRIMARY KEY (id),
126-
CONSTRAINT FK_todos_lists FOREIGN KEY (list_id) REFERENCES dbo.lists(id) ON DELETE CASCADE
127-
);
128-
END;
129-
');
98+
CREATE TABLE dbo.todos (
99+
id UNIQUEIDENTIFIER NOT NULL DEFAULT NEWID(),
100+
created_at DATETIME2 NOT NULL DEFAULT SYSUTCDATETIME(),
101+
completed_at DATETIME2 NULL,
102+
description NVARCHAR(MAX) NOT NULL,
103+
completed BIT NOT NULL DEFAULT 0,
104+
created_by UNIQUEIDENTIFIER NULL,
105+
completed_by UNIQUEIDENTIFIER NULL,
106+
list_id UNIQUEIDENTIFIER NOT NULL,
107+
CONSTRAINT PK_todos PRIMARY KEY (id),
108+
CONSTRAINT FK_todos_lists FOREIGN KEY (list_id) REFERENCES dbo.lists(id) ON DELETE CASCADE
109+
);
110+
END
130111

131-
GRANT INSERT, UPDATE, DELETE ON dbo.todos TO [$(APP_LOGIN)];
112+
GRANT INSERT, UPDATE, DELETE ON dbo.todos TO [$(DB_USER)];
132113
GO
133114

134115
-- Enable CDC for dbo.lists (idempotent guard)
135-
DECLARE @db sysname = '$(APP_DB)';
136-
DECLARE @login sysname = '$(APP_LOGIN)';
137-
DECLARE @enableListsTable nvarchar(max) = N'USE [' + @db + N'];
138-
IF NOT EXISTS (
139-
SELECT 1
140-
FROM cdc.change_tables
141-
WHERE source_object_id = OBJECT_ID(N''dbo.lists'')
142-
)
116+
IF NOT EXISTS (SELECT 1 FROM cdc.change_tables WHERE source_object_id = OBJECT_ID(N'dbo.lists'))
143117
BEGIN
144-
EXEC sys.sp_cdc_enable_table
145-
@source_schema = N''dbo'',
146-
@source_name = N''lists'',
147-
@role_name = N''cdc_reader'',
148-
@supports_net_changes = 1;
149-
END;';
150-
EXEC(@enableListsTable);
118+
EXEC sys.sp_cdc_enable_table
119+
@source_schema = N'dbo',
120+
@source_name = N'lists',
121+
@role_name = N'cdc_reader',
122+
@supports_net_changes = 0;
123+
END
124+
GO
151125

152126
-- Enable CDC for dbo.todos (idempotent guard)
153-
DECLARE @enableTodosTable nvarchar(max) = N'USE [' + @db + N'];
154-
IF NOT EXISTS (
155-
SELECT 1
156-
FROM cdc.change_tables
157-
WHERE source_object_id = OBJECT_ID(N''dbo.todos'')
158-
)
127+
IF NOT EXISTS (SELECT 1 FROM cdc.change_tables WHERE source_object_id = OBJECT_ID(N'dbo.todos'))
159128
BEGIN
160-
EXEC sys.sp_cdc_enable_table
161-
@source_schema = N''dbo'',
162-
@source_name = N''todos'',
163-
@role_name = N''cdc_reader'',
164-
@supports_net_changes = 1;
165-
END;';
166-
EXEC(@enableTodosTable);
167-
168-
-- Grant minimal rights to read CDC data:
169-
-- 1) read access to base tables (db_datareader)
170-
-- 2) membership in cdc_reader (allows selecting from CDC change tables & functions)
171-
-- 3) the cdc_reader role is only available once CDC is enabled on the database and some tables have been enabled for CDC
172-
DECLARE @grant nvarchar(max) = N'USE [' + @db + N'];
173-
IF NOT EXISTS (SELECT 1 FROM sys.database_role_members rm
174-
JOIN sys.database_principals r ON rm.role_principal_id = r.principal_id AND r.name = ''db_datareader''
175-
JOIN sys.database_principals u ON rm.member_principal_id = u.principal_id AND u.name = ''' + @login + N''')
176-
ALTER ROLE db_datareader ADD MEMBER [' + @login + N'];
177-
178-
IF NOT EXISTS (SELECT 1 FROM sys.database_role_members rm
179-
JOIN sys.database_principals r ON rm.role_principal_id = r.principal_id AND r.name = ''cdc_reader''
180-
JOIN sys.database_principals u ON rm.member_principal_id = u.principal_id AND u.name = ''' + @login + N''')
181-
ALTER ROLE cdc_reader ADD MEMBER [' + @login + N'];';
182-
EXEC(@grant);
129+
EXEC sys.sp_cdc_enable_table
130+
@source_schema = N'dbo',
131+
@source_name = N'todos',
132+
@role_name = N'cdc_reader',
133+
@supports_net_changes = 0;
134+
END
183135
GO
184136

185-
DECLARE @db sysname = '$(APP_DB)';
186-
EXEC(N'USE [' + @db + N'];
137+
-- Grant minimal rights to read CDC data
138+
IF IS_ROLEMEMBER('db_datareader', '$(DB_USER)') = 0
187139
BEGIN
188-
INSERT INTO dbo.lists (id, name, owner_id)
189-
VALUES (NEWID(), ''Do a demo'', NEWID());
190-
END;
191-
');
140+
ALTER ROLE db_datareader ADD MEMBER [$(DB_USER)];
141+
END
142+
143+
IF IS_ROLEMEMBER('cdc_reader', '$(DB_USER)') = 0
144+
BEGIN
145+
ALTER ROLE cdc_reader ADD MEMBER [$(DB_USER)];
146+
END
147+
GO
148+
149+
-- Add demo data
150+
BEGIN
151+
INSERT INTO dbo.lists (id, name, owner_id)
152+
VALUES (NEWID(), 'Do a demo', NEWID());
153+
END
192154
GO

services/mssql/mssql.yaml

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,11 @@ services:
88
- "1433:1433"
99
environment:
1010
ACCEPT_EULA: "Y"
11-
MSSQL_SA_PASSWORD: "${SA_PASSWORD}"
11+
MSSQL_SA_PASSWORD: "${ROOT_PASSWORD}"
1212
MSSQL_PID: "Developer"
1313
MSSQL_AGENT_ENABLED: "true" # required for CDC capture/cleanup jobs
1414
volumes:
15-
- mssql-selfhosted-data:/var/opt/mssql
15+
- data:/var/opt/mssql
1616
healthcheck:
1717
test: [ "CMD-SHELL", "/opt/mssql-tools18/bin/sqlcmd -C -S localhost -U sa -P \"$${MSSQL_SA_PASSWORD}\" -Q \"SELECT 1;\" || exit 1" ]
1818
interval: 5s
@@ -27,13 +27,13 @@ services:
2727
mssql-selfhosted:
2828
condition: service_healthy
2929
environment:
30-
SA_PASSWORD: "${SA_PASSWORD}"
31-
APP_DB: "${APP_DB}"
32-
APP_LOGIN: "${APP_LOGIN}"
33-
APP_PASSWORD: "${APP_PASSWORD}"
30+
MSSQL_SA_PASSWORD: "${ROOT_PASSWORD}"
31+
DATABASE: "${DATABASE}"
32+
DB_USER: "${DB_USER}"
33+
DB_USER_PASSWORD: "${DB_USER_PASSWORD}"
3434
volumes:
3535
- ./init.sql:/scripts/init.sql:ro
36-
entrypoint: ["/bin/bash", "-lc", "/opt/mssql-tools18/bin/sqlcmd -C -S mssql-selfhosted,1433 -U sa -P \"$SA_PASSWORD\" -i /scripts/init.sql && echo '✅ MSSQL init done'"]
36+
entrypoint: ["/bin/bash", "-lc", "/opt/mssql-tools18/bin/sqlcmd -C -S mssql-selfhosted,1433 -U sa -P \"$${MSSQL_SA_PASSWORD}\" -i /scripts/init.sql && echo '✅ MSSQL init done'"]
3737

3838
volumes:
39-
mssql-selfhosted-data:
39+
data:

0 commit comments

Comments
 (0)