11-- Create database (idempotent)
2- DECLARE @db sysname = ' $(APP_DB)' ;
3- IF DB_ID (@db) IS NULL
2+ IF DB_ID (' $(DATABASE)' ) IS NULL
43BEGIN
5- DECLARE @sql nvarchar (max ) = N ' CREATE DATABASE [' + @db + N ' ];' ;
6- EXEC (@sql);
4+ CREATE DATABASE [$(DATABASE)];
75END
86GO
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
1614GO
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)' )
2619BEGIN
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
3630GO
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)];
4035GO
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)];
4440GO
4541
4642-- Create PowerSync checkpoints table
47- USE [$(APP_DB)];
43+ -- Powersync requires this table to ensure regular checkpoints appear in CDC
4844IF OBJECT_ID (' dbo._powersync_checkpoints' , ' U' ) IS NULL
4945BEGIN
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' ))
6557BEGIN
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
7364GO
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
7667DECLARE @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' )
8069BEGIN
8170 WAITFOR DELAY ' 00:00:01' ;
8271 SET @tries - = 1 ;
8372END ;
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
8875EXEC sys .sp_cdc_change_job @job_type = N ' capture' , @pollinginterval = 1 ;
8976GO
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
10083BEGIN
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
11597BEGIN
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 )];
132113GO
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' ))
143117BEGIN
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' ))
159128BEGIN
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
183135GO
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
187139BEGIN
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
192154GO
0 commit comments