2021-11-22 16:55:27 -08:00
|
|
|
|
package persistence
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"fmt"
|
2022-12-02 20:33:54 -05:00
|
|
|
|
|
2022-03-06 19:17:43 -08:00
|
|
|
|
sql "github.com/jmoiron/sqlx"
|
2021-12-12 20:10:08 -08:00
|
|
|
|
|
2023-07-30 14:19:07 -03:00
|
|
|
|
"gitlab.com/offline-twitter/twitter_offline_engine/pkg/terminal_utils"
|
2021-11-22 16:55:27 -08:00
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
type VersionMismatchError struct {
|
2022-03-13 17:09:43 -07:00
|
|
|
|
EngineVersion int
|
2021-11-22 16:55:27 -08:00
|
|
|
|
DatabaseVersion int
|
|
|
|
|
}
|
2022-03-13 17:09:43 -07:00
|
|
|
|
|
2021-11-22 16:55:27 -08:00
|
|
|
|
func (e VersionMismatchError) Error() string {
|
|
|
|
|
return fmt.Sprintf(
|
2022-03-13 17:09:43 -07:00
|
|
|
|
`This profile was created with database schema version %d, which is newer than this application's database schema version, %d.
|
2021-11-22 16:55:27 -08:00
|
|
|
|
Please upgrade this application to a newer version to use this profile. Or downgrade the profile's schema version, somehow.`,
|
2022-03-13 17:09:43 -07:00
|
|
|
|
e.DatabaseVersion, e.EngineVersion,
|
2021-11-22 16:55:27 -08:00
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-25 22:53:49 -03:00
|
|
|
|
// The Nth entry is the migration that moves you from version N to version N+1.
|
2021-11-22 16:55:27 -08:00
|
|
|
|
var MIGRATIONS = []string{
|
2022-03-13 17:09:43 -07:00
|
|
|
|
`create table polls (rowid integer primary key,
|
2023-08-03 00:46:10 -03:00
|
|
|
|
id integer unique not null check(typeof(id) = 'integer'),
|
|
|
|
|
tweet_id integer not null,
|
|
|
|
|
num_choices integer not null,
|
2021-11-22 16:55:27 -08:00
|
|
|
|
|
2023-08-03 00:46:10 -03:00
|
|
|
|
choice1 text,
|
|
|
|
|
choice1_votes integer,
|
|
|
|
|
choice2 text,
|
|
|
|
|
choice2_votes integer,
|
|
|
|
|
choice3 text,
|
|
|
|
|
choice3_votes integer,
|
|
|
|
|
choice4 text,
|
|
|
|
|
choice4_votes integer,
|
2021-12-12 19:38:28 -08:00
|
|
|
|
|
2023-08-03 00:46:10 -03:00
|
|
|
|
voting_duration integer not null, -- in seconds
|
|
|
|
|
voting_ends_at integer not null,
|
2021-12-12 19:38:28 -08:00
|
|
|
|
|
2023-08-03 00:46:10 -03:00
|
|
|
|
last_scraped_at integer not null,
|
2021-12-12 19:38:28 -08:00
|
|
|
|
|
2023-08-03 00:46:10 -03:00
|
|
|
|
foreign key(tweet_id) references tweets(id)
|
|
|
|
|
);`,
|
2022-03-13 17:09:43 -07:00
|
|
|
|
`alter table tweets add column is_conversation_scraped boolean default 0;
|
2023-08-03 00:46:10 -03:00
|
|
|
|
alter table tweets add column last_scraped_at integer not null default 0`,
|
2022-03-13 17:09:43 -07:00
|
|
|
|
`update tombstone_types set tombstone_text = 'This Tweet is from a suspended account' where rowid = 2;
|
2023-08-03 00:46:10 -03:00
|
|
|
|
insert into tombstone_types (rowid, short_name, tombstone_text)
|
|
|
|
|
values (5, 'violated', 'This Tweet violated the Twitter Rules'),
|
|
|
|
|
(6, 'no longer exists', 'This Tweet is from an account that no longer exists')`,
|
2022-03-13 17:09:43 -07:00
|
|
|
|
`alter table videos add column thumbnail_remote_url text not null default "missing";
|
2023-08-03 00:46:10 -03:00
|
|
|
|
alter table videos add column thumbnail_local_filename text not null default "missing"`,
|
2023-08-22 20:07:32 -03:00
|
|
|
|
|
|
|
|
|
// 5
|
2022-03-13 17:09:43 -07:00
|
|
|
|
`alter table videos add column duration integer not null default 0;
|
2023-08-03 00:46:10 -03:00
|
|
|
|
alter table videos add column view_count integer not null default 0`,
|
2022-03-13 17:09:43 -07:00
|
|
|
|
`alter table users add column is_banned boolean default 0`,
|
|
|
|
|
`alter table urls add column short_text text not null default ""`,
|
|
|
|
|
`insert into tombstone_types (rowid, short_name, tombstone_text) values (7, 'age-restricted', 'Age-restricted adult content. '
|
2023-08-03 00:46:10 -03:00
|
|
|
|
|| 'This content might not be appropriate for people under 18 years old. To view this media, you’ll need to log in to Twitter')`,
|
2022-03-13 17:09:43 -07:00
|
|
|
|
`alter table users add column is_followed boolean default 0`,
|
2023-08-22 20:07:32 -03:00
|
|
|
|
|
|
|
|
|
// 10
|
2022-03-13 17:09:43 -07:00
|
|
|
|
`create table fake_user_sequence(latest_fake_id integer not null);
|
2023-08-03 00:46:10 -03:00
|
|
|
|
insert into fake_user_sequence values(0x4000000000000000);
|
|
|
|
|
alter table users add column is_id_fake boolean default 0;`,
|
2022-03-13 17:09:43 -07:00
|
|
|
|
`delete from urls where rowid in (select urls.rowid from tweets join urls on tweets.id = urls.tweet_id where urls.text like
|
2023-08-03 00:46:10 -03:00
|
|
|
|
'https://twitter.com/%/status/' || tweets.quoted_tweet_id || "%")`,
|
2022-05-14 18:28:33 -07:00
|
|
|
|
`create table spaces(rowid integer primary key,
|
2023-08-03 00:46:10 -03:00
|
|
|
|
id text unique not null,
|
|
|
|
|
short_url text not null
|
|
|
|
|
);
|
|
|
|
|
alter table tweets add column space_id text references spaces(id)`,
|
2022-12-02 20:33:54 -05:00
|
|
|
|
`alter table videos add column is_blocked_by_dmca boolean not null default 0`,
|
2022-12-24 13:47:43 -05:00
|
|
|
|
`create index if not exists index_tweets_in_reply_to_id on tweets (in_reply_to_id);
|
|
|
|
|
create index if not exists index_urls_tweet_id on urls (tweet_id);
|
|
|
|
|
create index if not exists index_polls_tweet_id on polls (tweet_id);
|
|
|
|
|
create index if not exists index_images_tweet_id on images (tweet_id);
|
|
|
|
|
create index if not exists index_videos_tweet_id on videos (tweet_id);`,
|
2023-08-22 20:07:32 -03:00
|
|
|
|
|
|
|
|
|
// 15
|
2022-12-25 13:06:17 -05:00
|
|
|
|
`alter table spaces add column created_by_id integer references users(id);
|
2022-12-26 12:56:05 -05:00
|
|
|
|
alter table spaces add column state text not null default "";
|
|
|
|
|
alter table spaces add column title text not null default "";
|
|
|
|
|
alter table spaces add column created_at integer;
|
|
|
|
|
alter table spaces add column started_at integer;
|
|
|
|
|
alter table spaces add column ended_at integer;
|
|
|
|
|
alter table spaces add column updated_at integer;
|
2022-12-26 13:08:25 -05:00
|
|
|
|
alter table spaces add column is_available_for_replay boolean not null default 0;
|
2022-12-25 13:06:17 -05:00
|
|
|
|
alter table spaces add column replay_watch_count integer;
|
|
|
|
|
alter table spaces add column live_listeners_count integer;
|
|
|
|
|
alter table spaces add column is_details_fetched boolean not null default 0;
|
|
|
|
|
create table space_participants(rowid integer primary key,
|
|
|
|
|
user_id integer not null,
|
|
|
|
|
space_id not null,
|
|
|
|
|
foreign key(space_id) references spaces(id)
|
|
|
|
|
);`,
|
2022-12-26 13:08:25 -05:00
|
|
|
|
`create index if not exists index_tweets_user_id on tweets (user_id);`,
|
2023-06-08 18:51:50 -03:00
|
|
|
|
`alter table tweets add column is_expandable bool not null default 0;`,
|
2023-06-25 22:53:49 -03:00
|
|
|
|
`create table space_participants_uniq(rowid integer primary key,
|
|
|
|
|
user_id integer not null,
|
|
|
|
|
space_id not null,
|
|
|
|
|
|
|
|
|
|
unique(user_id, space_id)
|
|
|
|
|
foreign key(space_id) references spaces(id)
|
|
|
|
|
-- No foreign key for users, since they may not be downloaded yet and I don't want to
|
|
|
|
|
-- download every user who joins a space
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
insert or replace into space_participants_uniq(rowid, user_id, space_id) select rowid, user_id, space_id from space_participants;
|
|
|
|
|
|
|
|
|
|
drop table space_participants;
|
|
|
|
|
alter table space_participants_uniq rename to space_participants;
|
|
|
|
|
vacuum;`,
|
2023-06-26 13:39:51 -03:00
|
|
|
|
`create table likes(rowid integer primary key,
|
|
|
|
|
sort_order integer unique not null,
|
|
|
|
|
user_id integer not null,
|
|
|
|
|
tweet_id integer not null,
|
|
|
|
|
unique(user_id, tweet_id)
|
|
|
|
|
foreign key(user_id) references users(id)
|
|
|
|
|
foreign key(tweet_id) references tweets(id)
|
|
|
|
|
);`,
|
2023-08-22 20:07:32 -03:00
|
|
|
|
|
|
|
|
|
// 20
|
2023-08-17 18:21:22 -03:00
|
|
|
|
`create index if not exists index_tweets_posted_at on tweets (posted_at);
|
|
|
|
|
create index if not exists index_retweets_retweeted_at on retweets (retweeted_at)`,
|
2023-08-19 22:35:10 -03:00
|
|
|
|
`update spaces set ended_at = ended_at/1000 where ended_at > strftime("%s")*500;
|
|
|
|
|
update spaces set updated_at = updated_at/1000 where updated_at > strftime("%s")*500;
|
|
|
|
|
update spaces set started_at = started_at/1000 where started_at > strftime("%s")*500;
|
|
|
|
|
update spaces set created_at = created_at/1000 where created_at > strftime("%s")*500;`,
|
2023-08-22 20:07:32 -03:00
|
|
|
|
`alter table users add column is_deleted boolean default 0`,
|
2023-10-13 17:55:40 -03:00
|
|
|
|
`begin transaction;
|
|
|
|
|
alter table likes rename to likes_old;
|
|
|
|
|
|
|
|
|
|
create table likes(rowid integer primary key,
|
|
|
|
|
sort_order integer not null,
|
|
|
|
|
user_id integer not null,
|
|
|
|
|
tweet_id integer not null,
|
|
|
|
|
unique(user_id, tweet_id)
|
|
|
|
|
foreign key(user_id) references users(id)
|
|
|
|
|
foreign key(tweet_id) references tweets(id)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
create index if not exists index_likes_user_id on likes (user_id);
|
|
|
|
|
create index if not exists index_likes_tweet_id on likes (tweet_id);
|
|
|
|
|
insert into likes select * from likes_old;
|
|
|
|
|
drop table likes_old;
|
|
|
|
|
commit;
|
|
|
|
|
vacuum;`,
|
2021-11-22 16:55:27 -08:00
|
|
|
|
}
|
2023-06-25 22:53:49 -03:00
|
|
|
|
var ENGINE_DATABASE_VERSION = len(MIGRATIONS)
|
2021-11-22 16:55:27 -08:00
|
|
|
|
|
2023-06-25 22:53:49 -03:00
|
|
|
|
// This should only get called on a newly created Profile.
|
|
|
|
|
// Subsequent updates should change the number, not insert a new row.
|
2021-11-22 16:55:27 -08:00
|
|
|
|
func InitializeDatabaseVersion(db *sql.DB) {
|
2022-03-06 19:17:43 -08:00
|
|
|
|
db.MustExec("insert into database_version (version_number) values (?)", ENGINE_DATABASE_VERSION)
|
2021-11-22 16:55:27 -08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (p Profile) GetDatabaseVersion() (int, error) {
|
|
|
|
|
row := p.DB.QueryRow("select version_number from database_version")
|
|
|
|
|
|
|
|
|
|
var version int
|
|
|
|
|
|
|
|
|
|
err := row.Scan(&version)
|
|
|
|
|
if err != nil {
|
2022-03-13 16:13:16 -07:00
|
|
|
|
return 0, fmt.Errorf("Error checking database version:\n %w", err)
|
2021-11-22 16:55:27 -08:00
|
|
|
|
}
|
|
|
|
|
return version, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (p Profile) check_and_update_version() error {
|
|
|
|
|
version, err := p.GetDatabaseVersion()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if version > ENGINE_DATABASE_VERSION {
|
|
|
|
|
return VersionMismatchError{ENGINE_DATABASE_VERSION, version}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ENGINE_DATABASE_VERSION > version {
|
2021-12-12 20:10:08 -08:00
|
|
|
|
fmt.Printf(terminal_utils.COLOR_YELLOW)
|
|
|
|
|
fmt.Printf("================================================\n")
|
2022-03-06 15:06:06 -08:00
|
|
|
|
fmt.Printf("Database version is out of date. Upgrading database from version %d to version %d!\n", version,
|
|
|
|
|
ENGINE_DATABASE_VERSION)
|
2021-12-12 20:10:08 -08:00
|
|
|
|
fmt.Printf(terminal_utils.COLOR_RESET)
|
2021-11-22 17:03:57 -08:00
|
|
|
|
return p.UpgradeFromXToY(version, ENGINE_DATABASE_VERSION)
|
2021-11-22 16:55:27 -08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-25 22:53:49 -03:00
|
|
|
|
// Run all the migrations from version X to version Y, and update the `database_version` table's `version_number`
|
2021-11-22 16:55:27 -08:00
|
|
|
|
func (p Profile) UpgradeFromXToY(x int, y int) error {
|
|
|
|
|
for i := x; i < y; i++ {
|
2021-12-12 20:10:08 -08:00
|
|
|
|
fmt.Printf(terminal_utils.COLOR_CYAN)
|
2021-11-22 16:55:27 -08:00
|
|
|
|
fmt.Println(MIGRATIONS[i])
|
2021-12-12 20:10:08 -08:00
|
|
|
|
fmt.Printf(terminal_utils.COLOR_RESET)
|
|
|
|
|
|
2022-03-06 19:17:43 -08:00
|
|
|
|
p.DB.MustExec(MIGRATIONS[i])
|
|
|
|
|
p.DB.MustExec("update database_version set version_number = ?", i+1)
|
|
|
|
|
|
2021-12-12 20:10:08 -08:00
|
|
|
|
fmt.Printf(terminal_utils.COLOR_YELLOW)
|
2022-03-06 19:17:43 -08:00
|
|
|
|
fmt.Printf("Now at database schema version %d.\n", i+1)
|
2021-12-12 20:10:08 -08:00
|
|
|
|
fmt.Printf(terminal_utils.COLOR_RESET)
|
2021-11-22 16:55:27 -08:00
|
|
|
|
}
|
2021-12-12 20:10:08 -08:00
|
|
|
|
fmt.Printf(terminal_utils.COLOR_GREEN)
|
|
|
|
|
fmt.Printf("================================================\n")
|
|
|
|
|
fmt.Printf("Database version has been upgraded to version %d.\n", y)
|
|
|
|
|
fmt.Printf(terminal_utils.COLOR_RESET)
|
2021-11-22 16:55:27 -08:00
|
|
|
|
return nil
|
|
|
|
|
}
|