mirror of
				https://gitea.invidious.io/iv-org/invidious.git
				synced 2024-08-15 00:53:41 +00:00 
			
		
		
		
	Add custom migration implementation
This commit is contained in:
		
							parent
							
								
									e2fc64296d
								
							
						
					
					
						commit
						8ec992a8a3
					
				
					 12 changed files with 358 additions and 0 deletions
				
			
		|  | @ -34,6 +34,7 @@ require "./invidious/channels/*" | ||||||
| require "./invidious/user/*" | require "./invidious/user/*" | ||||||
| require "./invidious/routes/**" | require "./invidious/routes/**" | ||||||
| require "./invidious/jobs/**" | require "./invidious/jobs/**" | ||||||
|  | require "./invidious/migrations/*" | ||||||
| 
 | 
 | ||||||
| CONFIG   = Config.load | CONFIG   = Config.load | ||||||
| HMAC_KEY = CONFIG.hmac_key || Random::Secure.hex(32) | HMAC_KEY = CONFIG.hmac_key || Random::Secure.hex(32) | ||||||
|  | @ -111,6 +112,8 @@ end | ||||||
| OUTPUT = CONFIG.output.upcase == "STDOUT" ? STDOUT : File.open(CONFIG.output, mode: "a") | OUTPUT = CONFIG.output.upcase == "STDOUT" ? STDOUT : File.open(CONFIG.output, mode: "a") | ||||||
| LOGGER = Invidious::LogHandler.new(OUTPUT, CONFIG.log_level) | LOGGER = Invidious::LogHandler.new(OUTPUT, CONFIG.log_level) | ||||||
| 
 | 
 | ||||||
|  | # Run migrations | ||||||
|  | Invidious::Migrator.new(PG_DB).migrate | ||||||
| # Check table integrity | # Check table integrity | ||||||
| Invidious::Database.check_integrity(CONFIG) | Invidious::Database.check_integrity(CONFIG) | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
							
								
								
									
										38
									
								
								src/invidious/migration.cr
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								src/invidious/migration.cr
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,38 @@ | ||||||
|  | abstract class Invidious::Migration | ||||||
|  |   macro inherited | ||||||
|  |     Invidious::Migrator.migrations << self | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   @@version : Int64? | ||||||
|  | 
 | ||||||
|  |   def self.version(version : Int32 | Int64) | ||||||
|  |     @@version = version.to_i64 | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   getter? completed = false | ||||||
|  | 
 | ||||||
|  |   def initialize(@db : DB::Database) | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   abstract def up(conn : DB::Connection) | ||||||
|  | 
 | ||||||
|  |   def migrate | ||||||
|  |     # migrator already ignores completed migrations | ||||||
|  |     # but this is an extra check to make sure a migration doesn't run twice | ||||||
|  |     return if completed? | ||||||
|  | 
 | ||||||
|  |     @db.transaction do |txn| | ||||||
|  |       up(txn.connection) | ||||||
|  |       track(txn.connection) | ||||||
|  |       @completed = true | ||||||
|  |     end | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   def version : Int64 | ||||||
|  |     @@version.not_nil! | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   private def track(conn : DB::Connection) | ||||||
|  |     conn.exec("INSERT INTO #{Invidious::Migrator::MIGRATIONS_TABLE}(version) VALUES ($1)", version) | ||||||
|  |   end | ||||||
|  | end | ||||||
							
								
								
									
										30
									
								
								src/invidious/migrations/0000_create_channels_table.cr
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								src/invidious/migrations/0000_create_channels_table.cr
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,30 @@ | ||||||
|  | module Invidious::Migrations | ||||||
|  |   class CreateChannelsTable < Migration | ||||||
|  |     version 0 | ||||||
|  | 
 | ||||||
|  |     def up(conn : DB::Connection) | ||||||
|  |       conn.exec <<-SQL | ||||||
|  |       CREATE TABLE IF NOT EXISTS public.channels | ||||||
|  |       ( | ||||||
|  |         id text NOT NULL, | ||||||
|  |         author text, | ||||||
|  |         updated timestamp with time zone, | ||||||
|  |         deleted boolean, | ||||||
|  |         subscribed timestamp with time zone, | ||||||
|  |         CONSTRAINT channels_id_key UNIQUE (id) | ||||||
|  |       ); | ||||||
|  |       SQL | ||||||
|  | 
 | ||||||
|  |       conn.exec <<-SQL | ||||||
|  |       GRANT ALL ON TABLE public.channels TO current_user; | ||||||
|  |       SQL | ||||||
|  | 
 | ||||||
|  |       conn.exec <<-SQL | ||||||
|  |       CREATE INDEX IF NOT EXISTS channels_id_idx | ||||||
|  |         ON public.channels | ||||||
|  |         USING btree | ||||||
|  |         (id COLLATE pg_catalog."default"); | ||||||
|  |       SQL | ||||||
|  |     end | ||||||
|  |   end | ||||||
|  | end | ||||||
							
								
								
									
										28
									
								
								src/invidious/migrations/0001_create_videos_table.cr
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								src/invidious/migrations/0001_create_videos_table.cr
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,28 @@ | ||||||
|  | module Invidious::Migrations | ||||||
|  |   class CreateVideosTable < Migration | ||||||
|  |     version 1 | ||||||
|  | 
 | ||||||
|  |     def up(conn : DB::Connection) | ||||||
|  |       conn.exec <<-SQL | ||||||
|  |       CREATE UNLOGGED TABLE IF NOT EXISTS public.videos | ||||||
|  |       ( | ||||||
|  |         id text NOT NULL, | ||||||
|  |         info text, | ||||||
|  |         updated timestamp with time zone, | ||||||
|  |         CONSTRAINT videos_pkey PRIMARY KEY (id) | ||||||
|  |       ); | ||||||
|  |       SQL | ||||||
|  | 
 | ||||||
|  |       conn.exec <<-SQL | ||||||
|  |       GRANT ALL ON TABLE public.videos TO current_user; | ||||||
|  |       SQL | ||||||
|  | 
 | ||||||
|  |       conn.exec <<-SQL | ||||||
|  |       CREATE UNIQUE INDEX IF NOT EXISTS id_idx | ||||||
|  |         ON public.videos | ||||||
|  |         USING btree | ||||||
|  |         (id COLLATE pg_catalog."default"); | ||||||
|  |       SQL | ||||||
|  |     end | ||||||
|  |   end | ||||||
|  | end | ||||||
							
								
								
									
										35
									
								
								src/invidious/migrations/0002_create_channel_videos_table.cr
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								src/invidious/migrations/0002_create_channel_videos_table.cr
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,35 @@ | ||||||
|  | module Invidious::Migrations | ||||||
|  |   class CreateChannelVideosTable < Migration | ||||||
|  |     version 2 | ||||||
|  | 
 | ||||||
|  |     def up(conn : DB::Connection) | ||||||
|  |       conn.exec <<-SQL | ||||||
|  |       CREATE TABLE IF NOT EXISTS public.channel_videos | ||||||
|  |       ( | ||||||
|  |         id text NOT NULL, | ||||||
|  |         title text, | ||||||
|  |         published timestamp with time zone, | ||||||
|  |         updated timestamp with time zone, | ||||||
|  |         ucid text, | ||||||
|  |         author text, | ||||||
|  |         length_seconds integer, | ||||||
|  |         live_now boolean, | ||||||
|  |         premiere_timestamp timestamp with time zone, | ||||||
|  |         views bigint, | ||||||
|  |         CONSTRAINT channel_videos_id_key UNIQUE (id) | ||||||
|  |       ); | ||||||
|  |       SQL | ||||||
|  | 
 | ||||||
|  |       conn.exec <<-SQL | ||||||
|  |       GRANT ALL ON TABLE public.channel_videos TO current_user; | ||||||
|  |       SQL | ||||||
|  | 
 | ||||||
|  |       conn.exec <<-SQL | ||||||
|  |       CREATE INDEX IF NOT EXISTS channel_videos_ucid_idx | ||||||
|  |         ON public.channel_videos | ||||||
|  |         USING btree | ||||||
|  |         (ucid COLLATE pg_catalog."default"); | ||||||
|  |       SQL | ||||||
|  |     end | ||||||
|  |   end | ||||||
|  | end | ||||||
							
								
								
									
										34
									
								
								src/invidious/migrations/0003_create_users_table.cr
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								src/invidious/migrations/0003_create_users_table.cr
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,34 @@ | ||||||
|  | module Invidious::Migrations | ||||||
|  |   class CreateUsersTable < Migration | ||||||
|  |     version 3 | ||||||
|  | 
 | ||||||
|  |     def up(conn : DB::Connection) | ||||||
|  |       conn.exec <<-SQL | ||||||
|  |       CREATE TABLE IF NOT EXISTS public.users | ||||||
|  |       ( | ||||||
|  |         updated timestamp with time zone, | ||||||
|  |         notifications text[], | ||||||
|  |         subscriptions text[], | ||||||
|  |         email text NOT NULL, | ||||||
|  |         preferences text, | ||||||
|  |         password text, | ||||||
|  |         token text, | ||||||
|  |         watched text[], | ||||||
|  |         feed_needs_update boolean, | ||||||
|  |         CONSTRAINT users_email_key UNIQUE (email) | ||||||
|  |       ); | ||||||
|  |       SQL | ||||||
|  | 
 | ||||||
|  |       conn.exec <<-SQL | ||||||
|  |       GRANT ALL ON TABLE public.users TO current_user; | ||||||
|  |       SQL | ||||||
|  | 
 | ||||||
|  |       conn.exec <<-SQL | ||||||
|  |       CREATE UNIQUE INDEX IF NOT EXISTS email_unique_idx | ||||||
|  |         ON public.users | ||||||
|  |         USING btree | ||||||
|  |         (lower(email) COLLATE pg_catalog."default"); | ||||||
|  |       SQL | ||||||
|  |     end | ||||||
|  |   end | ||||||
|  | end | ||||||
							
								
								
									
										28
									
								
								src/invidious/migrations/0004_create_session_ids_table.cr
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								src/invidious/migrations/0004_create_session_ids_table.cr
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,28 @@ | ||||||
|  | module Invidious::Migrations | ||||||
|  |   class CreateSessionIdsTable < Migration | ||||||
|  |     version 4 | ||||||
|  | 
 | ||||||
|  |     def up(conn : DB::Connection) | ||||||
|  |       conn.exec <<-SQL | ||||||
|  |       CREATE TABLE IF NOT EXISTS public.session_ids | ||||||
|  |       ( | ||||||
|  |         id text NOT NULL, | ||||||
|  |         email text, | ||||||
|  |         issued timestamp with time zone, | ||||||
|  |         CONSTRAINT session_ids_pkey PRIMARY KEY (id) | ||||||
|  |       ); | ||||||
|  |       SQL | ||||||
|  | 
 | ||||||
|  |       conn.exec <<-SQL | ||||||
|  |       GRANT ALL ON TABLE public.session_ids TO current_user; | ||||||
|  |       SQL | ||||||
|  | 
 | ||||||
|  |       conn.exec <<-SQL | ||||||
|  |       CREATE INDEX IF NOT EXISTS session_ids_id_idx | ||||||
|  |         ON public.session_ids | ||||||
|  |         USING btree | ||||||
|  |         (id COLLATE pg_catalog."default"); | ||||||
|  |       SQL | ||||||
|  |     end | ||||||
|  |   end | ||||||
|  | end | ||||||
							
								
								
									
										27
									
								
								src/invidious/migrations/0005_create_nonces_table.cr
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								src/invidious/migrations/0005_create_nonces_table.cr
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,27 @@ | ||||||
|  | module Invidious::Migrations | ||||||
|  |   class CreateNoncesTable < Migration | ||||||
|  |     version 5 | ||||||
|  | 
 | ||||||
|  |     def up(conn : DB::Connection) | ||||||
|  |       conn.exec <<-SQL | ||||||
|  |       CREATE TABLE IF NOT EXISTS public.nonces | ||||||
|  |       ( | ||||||
|  |         nonce text, | ||||||
|  |         expire timestamp with time zone, | ||||||
|  |         CONSTRAINT nonces_id_key UNIQUE (nonce) | ||||||
|  |       ); | ||||||
|  |       SQL | ||||||
|  | 
 | ||||||
|  |       conn.exec <<-SQL | ||||||
|  |       GRANT ALL ON TABLE public.nonces TO current_user; | ||||||
|  |       SQL | ||||||
|  | 
 | ||||||
|  |       conn.exec <<-SQL | ||||||
|  |       CREATE INDEX IF NOT EXISTS nonces_nonce_idx | ||||||
|  |         ON public.nonces | ||||||
|  |         USING btree | ||||||
|  |         (nonce COLLATE pg_catalog."default"); | ||||||
|  |       SQL | ||||||
|  |     end | ||||||
|  |   end | ||||||
|  | end | ||||||
							
								
								
									
										20
									
								
								src/invidious/migrations/0006_create_annotations_table.cr
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								src/invidious/migrations/0006_create_annotations_table.cr
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,20 @@ | ||||||
|  | module Invidious::Migrations | ||||||
|  |   class CreateAnnotationsTable < Migration | ||||||
|  |     version 6 | ||||||
|  | 
 | ||||||
|  |     def up(conn : DB::Connection) | ||||||
|  |       conn.exec <<-SQL | ||||||
|  |       CREATE TABLE IF NOT EXISTS public.annotations | ||||||
|  |       ( | ||||||
|  |         id text NOT NULL, | ||||||
|  |         annotations xml, | ||||||
|  |         CONSTRAINT annotations_id_key UNIQUE (id) | ||||||
|  |       ); | ||||||
|  |       SQL | ||||||
|  | 
 | ||||||
|  |       conn.exec <<-SQL | ||||||
|  |       GRANT ALL ON TABLE public.annotations TO current_user; | ||||||
|  |       SQL | ||||||
|  |     end | ||||||
|  |   end | ||||||
|  | end | ||||||
							
								
								
									
										47
									
								
								src/invidious/migrations/0007_create_playlists_table.cr
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								src/invidious/migrations/0007_create_playlists_table.cr
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,47 @@ | ||||||
|  | module Invidious::Migrations | ||||||
|  |   class CreatePlaylistsTable < Migration | ||||||
|  |     version 7 | ||||||
|  | 
 | ||||||
|  |     def up(conn : DB::Connection) | ||||||
|  |       conn.exec <<-SQL | ||||||
|  |       DO | ||||||
|  |       $$ | ||||||
|  |       BEGIN | ||||||
|  |         IF NOT EXISTS (SELECT * | ||||||
|  |                         FROM pg_type typ | ||||||
|  |                         INNER JOIN pg_namespace nsp ON nsp.oid = typ.typnamespace | ||||||
|  |                         WHERE nsp.nspname = 'public' | ||||||
|  |                               AND typ.typname = 'privacy') THEN | ||||||
|  |           CREATE TYPE public.privacy AS ENUM | ||||||
|  |             ( | ||||||
|  |                 'Public', | ||||||
|  |                 'Unlisted', | ||||||
|  |                 'Private' | ||||||
|  |             ); | ||||||
|  |         END IF; | ||||||
|  |       END; | ||||||
|  |       $$ | ||||||
|  |       LANGUAGE plpgsql; | ||||||
|  |       SQL | ||||||
|  | 
 | ||||||
|  |       conn.exec <<-SQL | ||||||
|  |       CREATE TABLE IF NOT EXISTS public.playlists | ||||||
|  |       ( | ||||||
|  |           title text, | ||||||
|  |           id text primary key, | ||||||
|  |           author text, | ||||||
|  |           description text, | ||||||
|  |           video_count integer, | ||||||
|  |           created timestamptz, | ||||||
|  |           updated timestamptz, | ||||||
|  |           privacy privacy, | ||||||
|  |           index int8[] | ||||||
|  |       ); | ||||||
|  |       SQL | ||||||
|  | 
 | ||||||
|  |       conn.exec <<-SQL | ||||||
|  |       GRANT ALL ON public.playlists TO current_user; | ||||||
|  |       SQL | ||||||
|  |     end | ||||||
|  |   end | ||||||
|  | end | ||||||
|  | @ -0,0 +1,27 @@ | ||||||
|  | module Invidious::Migrations | ||||||
|  |   class CreatePlaylistVideosTable < Migration | ||||||
|  |     version 8 | ||||||
|  | 
 | ||||||
|  |     def up(conn : DB::Connection) | ||||||
|  |       conn.exec <<-SQL | ||||||
|  |       CREATE TABLE IF NOT EXISTS public.playlist_videos | ||||||
|  |       ( | ||||||
|  |             title text, | ||||||
|  |             id text, | ||||||
|  |             author text, | ||||||
|  |             ucid text, | ||||||
|  |             length_seconds integer, | ||||||
|  |             published timestamptz, | ||||||
|  |             plid text references playlists(id), | ||||||
|  |             index int8, | ||||||
|  |             live_now boolean, | ||||||
|  |             PRIMARY KEY (index,plid) | ||||||
|  |         ); | ||||||
|  |       SQL | ||||||
|  | 
 | ||||||
|  |       conn.exec <<-SQL | ||||||
|  |       GRANT ALL ON TABLE public.playlist_videos TO current_user; | ||||||
|  |       SQL | ||||||
|  |     end | ||||||
|  |   end | ||||||
|  | end | ||||||
							
								
								
									
										41
									
								
								src/invidious/migrator.cr
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								src/invidious/migrator.cr
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,41 @@ | ||||||
|  | class Invidious::Migrator | ||||||
|  |   MIGRATIONS_TABLE = "invidious_migrations" | ||||||
|  | 
 | ||||||
|  |   class_getter migrations = [] of Invidious::Migration.class | ||||||
|  | 
 | ||||||
|  |   def initialize(@db : DB::Database) | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   def migrate | ||||||
|  |     run_migrations = load_run_migrations | ||||||
|  |     migrations = load_migrations.sort_by(&.version) | ||||||
|  |     migrations_to_run = migrations.reject { |migration| run_migrations.includes?(migration.version) } | ||||||
|  |     if migrations.empty? | ||||||
|  |       puts "No migrations to run." | ||||||
|  |       return | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     migrations_to_run.each do |migration| | ||||||
|  |       puts "Running migration: #{migration.class.name}" | ||||||
|  |       migration.migrate | ||||||
|  |     end | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   private def load_migrations : Array(Invidious::Migration) | ||||||
|  |     self.class.migrations.map(&.new(@db)) | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   private def load_run_migrations : Array(Int64) | ||||||
|  |     create_migrations_table | ||||||
|  |     @db.query_all("SELECT version FROM #{MIGRATIONS_TABLE}", as: Int64) | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   private def create_migrations_table | ||||||
|  |     @db.exec <<-SQL | ||||||
|  |       CREATE TABLE IF NOT EXISTS #{MIGRATIONS_TABLE} ( | ||||||
|  |         id bigserial PRIMARY KEY, | ||||||
|  |         version bigint NOT NULL | ||||||
|  |       ) | ||||||
|  |     SQL | ||||||
|  |   end | ||||||
|  | end | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue