new home screen
This commit is contained in:
@@ -0,0 +1,164 @@
|
||||
/*
|
||||
* Copyright (c) 2024-2026 Fabian Freund.
|
||||
*
|
||||
* This file is part of WebLibre
|
||||
* (see https://weblibre.eu).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import 'package:drift/drift.dart' show Value;
|
||||
import 'package:drift/native.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:weblibre/data/database/functions/lexo_rank_functions.dart';
|
||||
import 'package:weblibre/data/database/functions/url_functions.dart';
|
||||
import 'package:weblibre/features/geckoview/features/tabs/data/database/database.dart';
|
||||
import 'package:weblibre/features/geckoview/features/tabs/data/entities/tab_source.dart';
|
||||
import 'package:weblibre/features/geckoview/features/tabs/data/models/container_data.dart';
|
||||
|
||||
Future<void> _addContainer(TabDatabase db, String id) {
|
||||
return db.containerDao.addContainer(
|
||||
ContainerData(
|
||||
id: id,
|
||||
name: id,
|
||||
color: Colors.blue,
|
||||
orderKey: id,
|
||||
metadata: ContainerMetadata.withDefaults(contextualIdentity: id),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// Inserts [id] and stamps it, so "most recently used" ordering is explicit
|
||||
/// rather than dependent on insertion timing.
|
||||
Future<void> _addTab(
|
||||
TabDatabase db,
|
||||
String id, {
|
||||
String? containerId,
|
||||
required int minuteOfUse,
|
||||
}) async {
|
||||
await db.tabDao.insertTab(
|
||||
id,
|
||||
source: TabSource.manual,
|
||||
parentId: const Value(null),
|
||||
containerId: Value(containerId),
|
||||
);
|
||||
await db.tabDao.touchTab(
|
||||
id,
|
||||
timestamp: DateTime(2026, 8, 1, 12, minuteOfUse),
|
||||
);
|
||||
}
|
||||
|
||||
void main() {
|
||||
late TabDatabase db;
|
||||
|
||||
setUp(() {
|
||||
db = TabDatabase(
|
||||
NativeDatabase.memory(
|
||||
setup: (database) {
|
||||
registerLexorankFunctions(database);
|
||||
registerUrlFunctions(database);
|
||||
},
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
tearDown(() async {
|
||||
await db.close();
|
||||
});
|
||||
|
||||
group('getTabsFifo', () {
|
||||
test('returns the most recently used tab first', () async {
|
||||
await _addTab(db, 'older', minuteOfUse: 1);
|
||||
await _addTab(db, 'newer', minuteOfUse: 5);
|
||||
|
||||
final tabs = await db.tabDao.getTabsFifo(limit: 1).get();
|
||||
|
||||
expect(tabs.single.id, 'newer');
|
||||
});
|
||||
|
||||
test('skips excluded tabs', () async {
|
||||
// The regression this guards: tab rows are deleted only after the next
|
||||
// selection is made, so the tab being closed is still here — and having
|
||||
// just been active it sorts first, so an unfiltered query resumes the
|
||||
// very tab that is about to disappear.
|
||||
await _addTab(db, 'closing', minuteOfUse: 9);
|
||||
await _addTab(db, 'survivor', minuteOfUse: 1);
|
||||
|
||||
final tabs = await db.tabDao
|
||||
.getTabsFifo(limit: 1, excludedTabIds: {'closing'})
|
||||
.get();
|
||||
|
||||
expect(tabs.single.id, 'survivor');
|
||||
});
|
||||
|
||||
test('returns nothing when every candidate is excluded', () async {
|
||||
await _addTab(db, 'closing', minuteOfUse: 1);
|
||||
|
||||
final tabs = await db.tabDao
|
||||
.getTabsFifo(limit: 1, excludedTabIds: {'closing'})
|
||||
.get();
|
||||
|
||||
expect(tabs, isEmpty);
|
||||
});
|
||||
});
|
||||
|
||||
group('getContainerTabsFifo', () {
|
||||
test('stays within the requested container', () async {
|
||||
await _addContainer(db, 'a');
|
||||
await _addContainer(db, 'b');
|
||||
await _addTab(db, 'other-container', containerId: 'b', minuteOfUse: 9);
|
||||
await _addTab(db, 'wanted', containerId: 'a', minuteOfUse: 1);
|
||||
|
||||
final tabs = await db.tabDao.getContainerTabsFifo('a', limit: 1).get();
|
||||
|
||||
expect(tabs.single.id, 'wanted');
|
||||
});
|
||||
|
||||
test('skips the closing tab within a container', () async {
|
||||
await _addContainer(db, 'a');
|
||||
await _addTab(db, 'closing', containerId: 'a', minuteOfUse: 9);
|
||||
await _addTab(db, 'survivor', containerId: 'a', minuteOfUse: 1);
|
||||
|
||||
final tabs = await db.tabDao
|
||||
.getContainerTabsFifo('a', limit: 1, excludedTabIds: {'closing'})
|
||||
.get();
|
||||
|
||||
expect(tabs.single.id, 'survivor');
|
||||
});
|
||||
|
||||
test('a null container means unassigned, not any container', () async {
|
||||
await _addContainer(db, 'a');
|
||||
await _addTab(db, 'in-container', containerId: 'a', minuteOfUse: 9);
|
||||
await _addTab(db, 'unassigned', minuteOfUse: 1);
|
||||
|
||||
final tabs = await db.tabDao.getContainerTabsFifo(null, limit: 1).get();
|
||||
|
||||
expect(tabs.single.id, 'unassigned');
|
||||
});
|
||||
|
||||
test('skips the closing tab in the unassigned container', () async {
|
||||
// Closing the last unassigned tab must not resume that same tab, nor
|
||||
// fall through into a container.
|
||||
await _addContainer(db, 'a');
|
||||
await _addTab(db, 'in-container', containerId: 'a', minuteOfUse: 5);
|
||||
await _addTab(db, 'closing', minuteOfUse: 9);
|
||||
|
||||
final tabs = await db.tabDao
|
||||
.getContainerTabsFifo(null, limit: 1, excludedTabIds: {'closing'})
|
||||
.get();
|
||||
|
||||
expect(tabs, isEmpty);
|
||||
});
|
||||
});
|
||||
}
|
||||
+4
-1
@@ -5,6 +5,7 @@
|
||||
import 'package:drift/drift.dart';
|
||||
import 'package:drift/internal/migrations.dart';
|
||||
import 'schema_v1.dart' as v1;
|
||||
import 'schema_v2.dart' as v2;
|
||||
|
||||
class GeneratedHelper implements SchemaInstantiationHelper {
|
||||
@override
|
||||
@@ -12,10 +13,12 @@ class GeneratedHelper implements SchemaInstantiationHelper {
|
||||
switch (version) {
|
||||
case 1:
|
||||
return v1.DatabaseAtV1(db);
|
||||
case 2:
|
||||
return v2.DatabaseAtV2(db);
|
||||
default:
|
||||
throw MissingSchemaException(version, versions);
|
||||
}
|
||||
}
|
||||
|
||||
static const versions = const [1];
|
||||
static const versions = const [1, 2];
|
||||
}
|
||||
@@ -0,0 +1,500 @@
|
||||
// dart format width=80
|
||||
// GENERATED BY drift_dev, DO NOT MODIFY.
|
||||
// ignore_for_file: type=lint,unused_import
|
||||
//
|
||||
import 'package:drift/drift.dart';
|
||||
|
||||
class TopSite extends Table with TableInfo<TopSite, TopSiteData> {
|
||||
@override
|
||||
final GeneratedDatabase attachedDatabase;
|
||||
final String? _alias;
|
||||
TopSite(this.attachedDatabase, [this._alias]);
|
||||
late final GeneratedColumn<String> id = GeneratedColumn<String>(
|
||||
'id',
|
||||
aliasedName,
|
||||
false,
|
||||
type: DriftSqlType.string,
|
||||
requiredDuringInsert: true,
|
||||
$customConstraints: 'PRIMARY KEY NOT NULL',
|
||||
);
|
||||
late final GeneratedColumn<String> title = GeneratedColumn<String>(
|
||||
'title',
|
||||
aliasedName,
|
||||
false,
|
||||
type: DriftSqlType.string,
|
||||
requiredDuringInsert: true,
|
||||
$customConstraints: 'NOT NULL',
|
||||
);
|
||||
late final GeneratedColumn<String> url = GeneratedColumn<String>(
|
||||
'url',
|
||||
aliasedName,
|
||||
false,
|
||||
type: DriftSqlType.string,
|
||||
requiredDuringInsert: true,
|
||||
$customConstraints: 'NOT NULL',
|
||||
);
|
||||
late final GeneratedColumn<int> source = GeneratedColumn<int>(
|
||||
'source',
|
||||
aliasedName,
|
||||
false,
|
||||
type: DriftSqlType.int,
|
||||
requiredDuringInsert: true,
|
||||
$customConstraints: 'NOT NULL',
|
||||
);
|
||||
late final GeneratedColumn<String> orderKey = GeneratedColumn<String>(
|
||||
'order_key',
|
||||
aliasedName,
|
||||
false,
|
||||
type: DriftSqlType.string,
|
||||
requiredDuringInsert: true,
|
||||
$customConstraints: 'NOT NULL',
|
||||
);
|
||||
late final GeneratedColumn<int> createdAt = GeneratedColumn<int>(
|
||||
'created_at',
|
||||
aliasedName,
|
||||
false,
|
||||
type: DriftSqlType.int,
|
||||
requiredDuringInsert: true,
|
||||
$customConstraints: 'NOT NULL',
|
||||
);
|
||||
@override
|
||||
List<GeneratedColumn> get $columns => [
|
||||
id,
|
||||
title,
|
||||
url,
|
||||
source,
|
||||
orderKey,
|
||||
createdAt,
|
||||
];
|
||||
@override
|
||||
String get aliasedName => _alias ?? actualTableName;
|
||||
@override
|
||||
String get actualTableName => $name;
|
||||
static const String $name = 'top_site';
|
||||
@override
|
||||
Set<GeneratedColumn> get $primaryKey => {id};
|
||||
@override
|
||||
List<Set<GeneratedColumn>> get uniqueKeys => [
|
||||
{url},
|
||||
];
|
||||
@override
|
||||
TopSiteData map(Map<String, dynamic> data, {String? tablePrefix}) {
|
||||
final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : '';
|
||||
return TopSiteData(
|
||||
id: attachedDatabase.typeMapping.read(
|
||||
DriftSqlType.string,
|
||||
data['${effectivePrefix}id'],
|
||||
)!,
|
||||
title: attachedDatabase.typeMapping.read(
|
||||
DriftSqlType.string,
|
||||
data['${effectivePrefix}title'],
|
||||
)!,
|
||||
url: attachedDatabase.typeMapping.read(
|
||||
DriftSqlType.string,
|
||||
data['${effectivePrefix}url'],
|
||||
)!,
|
||||
source: attachedDatabase.typeMapping.read(
|
||||
DriftSqlType.int,
|
||||
data['${effectivePrefix}source'],
|
||||
)!,
|
||||
orderKey: attachedDatabase.typeMapping.read(
|
||||
DriftSqlType.string,
|
||||
data['${effectivePrefix}order_key'],
|
||||
)!,
|
||||
createdAt: attachedDatabase.typeMapping.read(
|
||||
DriftSqlType.int,
|
||||
data['${effectivePrefix}created_at'],
|
||||
)!,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
TopSite createAlias(String alias) {
|
||||
return TopSite(attachedDatabase, alias);
|
||||
}
|
||||
|
||||
@override
|
||||
List<String> get customConstraints => const ['UNIQUE(url)'];
|
||||
@override
|
||||
bool get dontWriteConstraints => true;
|
||||
}
|
||||
|
||||
class TopSiteData extends DataClass implements Insertable<TopSiteData> {
|
||||
final String id;
|
||||
final String title;
|
||||
final String url;
|
||||
final int source;
|
||||
final String orderKey;
|
||||
final int createdAt;
|
||||
const TopSiteData({
|
||||
required this.id,
|
||||
required this.title,
|
||||
required this.url,
|
||||
required this.source,
|
||||
required this.orderKey,
|
||||
required this.createdAt,
|
||||
});
|
||||
@override
|
||||
Map<String, Expression> toColumns(bool nullToAbsent) {
|
||||
final map = <String, Expression>{};
|
||||
map['id'] = Variable<String>(id);
|
||||
map['title'] = Variable<String>(title);
|
||||
map['url'] = Variable<String>(url);
|
||||
map['source'] = Variable<int>(source);
|
||||
map['order_key'] = Variable<String>(orderKey);
|
||||
map['created_at'] = Variable<int>(createdAt);
|
||||
return map;
|
||||
}
|
||||
|
||||
factory TopSiteData.fromJson(
|
||||
Map<String, dynamic> json, {
|
||||
ValueSerializer? serializer,
|
||||
}) {
|
||||
serializer ??= driftRuntimeOptions.defaultSerializer;
|
||||
return TopSiteData(
|
||||
id: serializer.fromJson<String>(json['id']),
|
||||
title: serializer.fromJson<String>(json['title']),
|
||||
url: serializer.fromJson<String>(json['url']),
|
||||
source: serializer.fromJson<int>(json['source']),
|
||||
orderKey: serializer.fromJson<String>(json['orderKey']),
|
||||
createdAt: serializer.fromJson<int>(json['createdAt']),
|
||||
);
|
||||
}
|
||||
@override
|
||||
Map<String, dynamic> toJson({ValueSerializer? serializer}) {
|
||||
serializer ??= driftRuntimeOptions.defaultSerializer;
|
||||
return <String, dynamic>{
|
||||
'id': serializer.toJson<String>(id),
|
||||
'title': serializer.toJson<String>(title),
|
||||
'url': serializer.toJson<String>(url),
|
||||
'source': serializer.toJson<int>(source),
|
||||
'orderKey': serializer.toJson<String>(orderKey),
|
||||
'createdAt': serializer.toJson<int>(createdAt),
|
||||
};
|
||||
}
|
||||
|
||||
TopSiteData copyWith({
|
||||
String? id,
|
||||
String? title,
|
||||
String? url,
|
||||
int? source,
|
||||
String? orderKey,
|
||||
int? createdAt,
|
||||
}) => TopSiteData(
|
||||
id: id ?? this.id,
|
||||
title: title ?? this.title,
|
||||
url: url ?? this.url,
|
||||
source: source ?? this.source,
|
||||
orderKey: orderKey ?? this.orderKey,
|
||||
createdAt: createdAt ?? this.createdAt,
|
||||
);
|
||||
TopSiteData copyWithCompanion(TopSiteCompanion data) {
|
||||
return TopSiteData(
|
||||
id: data.id.present ? data.id.value : this.id,
|
||||
title: data.title.present ? data.title.value : this.title,
|
||||
url: data.url.present ? data.url.value : this.url,
|
||||
source: data.source.present ? data.source.value : this.source,
|
||||
orderKey: data.orderKey.present ? data.orderKey.value : this.orderKey,
|
||||
createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return (StringBuffer('TopSiteData(')
|
||||
..write('id: $id, ')
|
||||
..write('title: $title, ')
|
||||
..write('url: $url, ')
|
||||
..write('source: $source, ')
|
||||
..write('orderKey: $orderKey, ')
|
||||
..write('createdAt: $createdAt')
|
||||
..write(')'))
|
||||
.toString();
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(id, title, url, source, orderKey, createdAt);
|
||||
@override
|
||||
bool operator ==(Object other) =>
|
||||
identical(this, other) ||
|
||||
(other is TopSiteData &&
|
||||
other.id == this.id &&
|
||||
other.title == this.title &&
|
||||
other.url == this.url &&
|
||||
other.source == this.source &&
|
||||
other.orderKey == this.orderKey &&
|
||||
other.createdAt == this.createdAt);
|
||||
}
|
||||
|
||||
class TopSiteCompanion extends UpdateCompanion<TopSiteData> {
|
||||
final Value<String> id;
|
||||
final Value<String> title;
|
||||
final Value<String> url;
|
||||
final Value<int> source;
|
||||
final Value<String> orderKey;
|
||||
final Value<int> createdAt;
|
||||
final Value<int> rowid;
|
||||
const TopSiteCompanion({
|
||||
this.id = const Value.absent(),
|
||||
this.title = const Value.absent(),
|
||||
this.url = const Value.absent(),
|
||||
this.source = const Value.absent(),
|
||||
this.orderKey = const Value.absent(),
|
||||
this.createdAt = const Value.absent(),
|
||||
this.rowid = const Value.absent(),
|
||||
});
|
||||
TopSiteCompanion.insert({
|
||||
required String id,
|
||||
required String title,
|
||||
required String url,
|
||||
required int source,
|
||||
required String orderKey,
|
||||
required int createdAt,
|
||||
this.rowid = const Value.absent(),
|
||||
}) : id = Value(id),
|
||||
title = Value(title),
|
||||
url = Value(url),
|
||||
source = Value(source),
|
||||
orderKey = Value(orderKey),
|
||||
createdAt = Value(createdAt);
|
||||
static Insertable<TopSiteData> custom({
|
||||
Expression<String>? id,
|
||||
Expression<String>? title,
|
||||
Expression<String>? url,
|
||||
Expression<int>? source,
|
||||
Expression<String>? orderKey,
|
||||
Expression<int>? createdAt,
|
||||
Expression<int>? rowid,
|
||||
}) {
|
||||
return RawValuesInsertable({
|
||||
if (id != null) 'id': id,
|
||||
if (title != null) 'title': title,
|
||||
if (url != null) 'url': url,
|
||||
if (source != null) 'source': source,
|
||||
if (orderKey != null) 'order_key': orderKey,
|
||||
if (createdAt != null) 'created_at': createdAt,
|
||||
if (rowid != null) 'rowid': rowid,
|
||||
});
|
||||
}
|
||||
|
||||
TopSiteCompanion copyWith({
|
||||
Value<String>? id,
|
||||
Value<String>? title,
|
||||
Value<String>? url,
|
||||
Value<int>? source,
|
||||
Value<String>? orderKey,
|
||||
Value<int>? createdAt,
|
||||
Value<int>? rowid,
|
||||
}) {
|
||||
return TopSiteCompanion(
|
||||
id: id ?? this.id,
|
||||
title: title ?? this.title,
|
||||
url: url ?? this.url,
|
||||
source: source ?? this.source,
|
||||
orderKey: orderKey ?? this.orderKey,
|
||||
createdAt: createdAt ?? this.createdAt,
|
||||
rowid: rowid ?? this.rowid,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Map<String, Expression> toColumns(bool nullToAbsent) {
|
||||
final map = <String, Expression>{};
|
||||
if (id.present) {
|
||||
map['id'] = Variable<String>(id.value);
|
||||
}
|
||||
if (title.present) {
|
||||
map['title'] = Variable<String>(title.value);
|
||||
}
|
||||
if (url.present) {
|
||||
map['url'] = Variable<String>(url.value);
|
||||
}
|
||||
if (source.present) {
|
||||
map['source'] = Variable<int>(source.value);
|
||||
}
|
||||
if (orderKey.present) {
|
||||
map['order_key'] = Variable<String>(orderKey.value);
|
||||
}
|
||||
if (createdAt.present) {
|
||||
map['created_at'] = Variable<int>(createdAt.value);
|
||||
}
|
||||
if (rowid.present) {
|
||||
map['rowid'] = Variable<int>(rowid.value);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return (StringBuffer('TopSiteCompanion(')
|
||||
..write('id: $id, ')
|
||||
..write('title: $title, ')
|
||||
..write('url: $url, ')
|
||||
..write('source: $source, ')
|
||||
..write('orderKey: $orderKey, ')
|
||||
..write('createdAt: $createdAt, ')
|
||||
..write('rowid: $rowid')
|
||||
..write(')'))
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
|
||||
class HiddenTopSite extends Table
|
||||
with TableInfo<HiddenTopSite, HiddenTopSiteData> {
|
||||
@override
|
||||
final GeneratedDatabase attachedDatabase;
|
||||
final String? _alias;
|
||||
HiddenTopSite(this.attachedDatabase, [this._alias]);
|
||||
late final GeneratedColumn<String> url = GeneratedColumn<String>(
|
||||
'url',
|
||||
aliasedName,
|
||||
false,
|
||||
type: DriftSqlType.string,
|
||||
requiredDuringInsert: true,
|
||||
$customConstraints: 'PRIMARY KEY NOT NULL',
|
||||
);
|
||||
@override
|
||||
List<GeneratedColumn> get $columns => [url];
|
||||
@override
|
||||
String get aliasedName => _alias ?? actualTableName;
|
||||
@override
|
||||
String get actualTableName => $name;
|
||||
static const String $name = 'hidden_top_site';
|
||||
@override
|
||||
Set<GeneratedColumn> get $primaryKey => {url};
|
||||
@override
|
||||
HiddenTopSiteData map(Map<String, dynamic> data, {String? tablePrefix}) {
|
||||
final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : '';
|
||||
return HiddenTopSiteData(
|
||||
url: attachedDatabase.typeMapping.read(
|
||||
DriftSqlType.string,
|
||||
data['${effectivePrefix}url'],
|
||||
)!,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
HiddenTopSite createAlias(String alias) {
|
||||
return HiddenTopSite(attachedDatabase, alias);
|
||||
}
|
||||
|
||||
@override
|
||||
bool get dontWriteConstraints => true;
|
||||
}
|
||||
|
||||
class HiddenTopSiteData extends DataClass
|
||||
implements Insertable<HiddenTopSiteData> {
|
||||
final String url;
|
||||
const HiddenTopSiteData({required this.url});
|
||||
@override
|
||||
Map<String, Expression> toColumns(bool nullToAbsent) {
|
||||
final map = <String, Expression>{};
|
||||
map['url'] = Variable<String>(url);
|
||||
return map;
|
||||
}
|
||||
|
||||
factory HiddenTopSiteData.fromJson(
|
||||
Map<String, dynamic> json, {
|
||||
ValueSerializer? serializer,
|
||||
}) {
|
||||
serializer ??= driftRuntimeOptions.defaultSerializer;
|
||||
return HiddenTopSiteData(url: serializer.fromJson<String>(json['url']));
|
||||
}
|
||||
@override
|
||||
Map<String, dynamic> toJson({ValueSerializer? serializer}) {
|
||||
serializer ??= driftRuntimeOptions.defaultSerializer;
|
||||
return <String, dynamic>{'url': serializer.toJson<String>(url)};
|
||||
}
|
||||
|
||||
HiddenTopSiteData copyWith({String? url}) =>
|
||||
HiddenTopSiteData(url: url ?? this.url);
|
||||
HiddenTopSiteData copyWithCompanion(HiddenTopSiteCompanion data) {
|
||||
return HiddenTopSiteData(url: data.url.present ? data.url.value : this.url);
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return (StringBuffer('HiddenTopSiteData(')
|
||||
..write('url: $url')
|
||||
..write(')'))
|
||||
.toString();
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => url.hashCode;
|
||||
@override
|
||||
bool operator ==(Object other) =>
|
||||
identical(this, other) ||
|
||||
(other is HiddenTopSiteData && other.url == this.url);
|
||||
}
|
||||
|
||||
class HiddenTopSiteCompanion extends UpdateCompanion<HiddenTopSiteData> {
|
||||
final Value<String> url;
|
||||
final Value<int> rowid;
|
||||
const HiddenTopSiteCompanion({
|
||||
this.url = const Value.absent(),
|
||||
this.rowid = const Value.absent(),
|
||||
});
|
||||
HiddenTopSiteCompanion.insert({
|
||||
required String url,
|
||||
this.rowid = const Value.absent(),
|
||||
}) : url = Value(url);
|
||||
static Insertable<HiddenTopSiteData> custom({
|
||||
Expression<String>? url,
|
||||
Expression<int>? rowid,
|
||||
}) {
|
||||
return RawValuesInsertable({
|
||||
if (url != null) 'url': url,
|
||||
if (rowid != null) 'rowid': rowid,
|
||||
});
|
||||
}
|
||||
|
||||
HiddenTopSiteCompanion copyWith({Value<String>? url, Value<int>? rowid}) {
|
||||
return HiddenTopSiteCompanion(
|
||||
url: url ?? this.url,
|
||||
rowid: rowid ?? this.rowid,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Map<String, Expression> toColumns(bool nullToAbsent) {
|
||||
final map = <String, Expression>{};
|
||||
if (url.present) {
|
||||
map['url'] = Variable<String>(url.value);
|
||||
}
|
||||
if (rowid.present) {
|
||||
map['rowid'] = Variable<int>(rowid.value);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return (StringBuffer('HiddenTopSiteCompanion(')
|
||||
..write('url: $url, ')
|
||||
..write('rowid: $rowid')
|
||||
..write(')'))
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
|
||||
class DatabaseAtV1 extends GeneratedDatabase {
|
||||
DatabaseAtV1(QueryExecutor e) : super(e);
|
||||
late final TopSite topSite = TopSite(this);
|
||||
late final Index idxTopSiteOrderKey = Index(
|
||||
'idx_top_site_order_key',
|
||||
'CREATE INDEX idx_top_site_order_key ON top_site (order_key)',
|
||||
);
|
||||
late final HiddenTopSite hiddenTopSite = HiddenTopSite(this);
|
||||
@override
|
||||
Iterable<TableInfo<Table, Object?>> get allTables =>
|
||||
allSchemaEntities.whereType<TableInfo<Table, Object?>>();
|
||||
@override
|
||||
List<DatabaseSchemaEntity> get allSchemaEntities => [
|
||||
topSite,
|
||||
idxTopSiteOrderKey,
|
||||
hiddenTopSite,
|
||||
];
|
||||
@override
|
||||
int get schemaVersion => 1;
|
||||
}
|
||||
@@ -0,0 +1,649 @@
|
||||
// dart format width=80
|
||||
// GENERATED BY drift_dev, DO NOT MODIFY.
|
||||
// ignore_for_file: type=lint,unused_import
|
||||
//
|
||||
import 'package:drift/drift.dart';
|
||||
|
||||
class TopSite extends Table with TableInfo<TopSite, TopSiteData> {
|
||||
@override
|
||||
final GeneratedDatabase attachedDatabase;
|
||||
final String? _alias;
|
||||
TopSite(this.attachedDatabase, [this._alias]);
|
||||
late final GeneratedColumn<String> id = GeneratedColumn<String>(
|
||||
'id',
|
||||
aliasedName,
|
||||
false,
|
||||
type: DriftSqlType.string,
|
||||
requiredDuringInsert: true,
|
||||
$customConstraints: 'PRIMARY KEY NOT NULL',
|
||||
);
|
||||
late final GeneratedColumn<String> title = GeneratedColumn<String>(
|
||||
'title',
|
||||
aliasedName,
|
||||
false,
|
||||
type: DriftSqlType.string,
|
||||
requiredDuringInsert: true,
|
||||
$customConstraints: 'NOT NULL',
|
||||
);
|
||||
late final GeneratedColumn<String> url = GeneratedColumn<String>(
|
||||
'url',
|
||||
aliasedName,
|
||||
false,
|
||||
type: DriftSqlType.string,
|
||||
requiredDuringInsert: true,
|
||||
$customConstraints: 'NOT NULL',
|
||||
);
|
||||
late final GeneratedColumn<int> source = GeneratedColumn<int>(
|
||||
'source',
|
||||
aliasedName,
|
||||
false,
|
||||
type: DriftSqlType.int,
|
||||
requiredDuringInsert: true,
|
||||
$customConstraints: 'NOT NULL',
|
||||
);
|
||||
late final GeneratedColumn<String> orderKey = GeneratedColumn<String>(
|
||||
'order_key',
|
||||
aliasedName,
|
||||
false,
|
||||
type: DriftSqlType.string,
|
||||
requiredDuringInsert: true,
|
||||
$customConstraints: 'NOT NULL',
|
||||
);
|
||||
late final GeneratedColumn<int> createdAt = GeneratedColumn<int>(
|
||||
'created_at',
|
||||
aliasedName,
|
||||
false,
|
||||
type: DriftSqlType.int,
|
||||
requiredDuringInsert: true,
|
||||
$customConstraints: 'NOT NULL',
|
||||
);
|
||||
@override
|
||||
List<GeneratedColumn> get $columns => [
|
||||
id,
|
||||
title,
|
||||
url,
|
||||
source,
|
||||
orderKey,
|
||||
createdAt,
|
||||
];
|
||||
@override
|
||||
String get aliasedName => _alias ?? actualTableName;
|
||||
@override
|
||||
String get actualTableName => $name;
|
||||
static const String $name = 'top_site';
|
||||
@override
|
||||
Set<GeneratedColumn> get $primaryKey => {id};
|
||||
@override
|
||||
List<Set<GeneratedColumn>> get uniqueKeys => [
|
||||
{url},
|
||||
];
|
||||
@override
|
||||
TopSiteData map(Map<String, dynamic> data, {String? tablePrefix}) {
|
||||
final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : '';
|
||||
return TopSiteData(
|
||||
id: attachedDatabase.typeMapping.read(
|
||||
DriftSqlType.string,
|
||||
data['${effectivePrefix}id'],
|
||||
)!,
|
||||
title: attachedDatabase.typeMapping.read(
|
||||
DriftSqlType.string,
|
||||
data['${effectivePrefix}title'],
|
||||
)!,
|
||||
url: attachedDatabase.typeMapping.read(
|
||||
DriftSqlType.string,
|
||||
data['${effectivePrefix}url'],
|
||||
)!,
|
||||
source: attachedDatabase.typeMapping.read(
|
||||
DriftSqlType.int,
|
||||
data['${effectivePrefix}source'],
|
||||
)!,
|
||||
orderKey: attachedDatabase.typeMapping.read(
|
||||
DriftSqlType.string,
|
||||
data['${effectivePrefix}order_key'],
|
||||
)!,
|
||||
createdAt: attachedDatabase.typeMapping.read(
|
||||
DriftSqlType.int,
|
||||
data['${effectivePrefix}created_at'],
|
||||
)!,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
TopSite createAlias(String alias) {
|
||||
return TopSite(attachedDatabase, alias);
|
||||
}
|
||||
|
||||
@override
|
||||
List<String> get customConstraints => const ['UNIQUE(url)'];
|
||||
@override
|
||||
bool get dontWriteConstraints => true;
|
||||
}
|
||||
|
||||
class TopSiteData extends DataClass implements Insertable<TopSiteData> {
|
||||
final String id;
|
||||
final String title;
|
||||
final String url;
|
||||
final int source;
|
||||
final String orderKey;
|
||||
final int createdAt;
|
||||
const TopSiteData({
|
||||
required this.id,
|
||||
required this.title,
|
||||
required this.url,
|
||||
required this.source,
|
||||
required this.orderKey,
|
||||
required this.createdAt,
|
||||
});
|
||||
@override
|
||||
Map<String, Expression> toColumns(bool nullToAbsent) {
|
||||
final map = <String, Expression>{};
|
||||
map['id'] = Variable<String>(id);
|
||||
map['title'] = Variable<String>(title);
|
||||
map['url'] = Variable<String>(url);
|
||||
map['source'] = Variable<int>(source);
|
||||
map['order_key'] = Variable<String>(orderKey);
|
||||
map['created_at'] = Variable<int>(createdAt);
|
||||
return map;
|
||||
}
|
||||
|
||||
factory TopSiteData.fromJson(
|
||||
Map<String, dynamic> json, {
|
||||
ValueSerializer? serializer,
|
||||
}) {
|
||||
serializer ??= driftRuntimeOptions.defaultSerializer;
|
||||
return TopSiteData(
|
||||
id: serializer.fromJson<String>(json['id']),
|
||||
title: serializer.fromJson<String>(json['title']),
|
||||
url: serializer.fromJson<String>(json['url']),
|
||||
source: serializer.fromJson<int>(json['source']),
|
||||
orderKey: serializer.fromJson<String>(json['orderKey']),
|
||||
createdAt: serializer.fromJson<int>(json['createdAt']),
|
||||
);
|
||||
}
|
||||
@override
|
||||
Map<String, dynamic> toJson({ValueSerializer? serializer}) {
|
||||
serializer ??= driftRuntimeOptions.defaultSerializer;
|
||||
return <String, dynamic>{
|
||||
'id': serializer.toJson<String>(id),
|
||||
'title': serializer.toJson<String>(title),
|
||||
'url': serializer.toJson<String>(url),
|
||||
'source': serializer.toJson<int>(source),
|
||||
'orderKey': serializer.toJson<String>(orderKey),
|
||||
'createdAt': serializer.toJson<int>(createdAt),
|
||||
};
|
||||
}
|
||||
|
||||
TopSiteData copyWith({
|
||||
String? id,
|
||||
String? title,
|
||||
String? url,
|
||||
int? source,
|
||||
String? orderKey,
|
||||
int? createdAt,
|
||||
}) => TopSiteData(
|
||||
id: id ?? this.id,
|
||||
title: title ?? this.title,
|
||||
url: url ?? this.url,
|
||||
source: source ?? this.source,
|
||||
orderKey: orderKey ?? this.orderKey,
|
||||
createdAt: createdAt ?? this.createdAt,
|
||||
);
|
||||
TopSiteData copyWithCompanion(TopSiteCompanion data) {
|
||||
return TopSiteData(
|
||||
id: data.id.present ? data.id.value : this.id,
|
||||
title: data.title.present ? data.title.value : this.title,
|
||||
url: data.url.present ? data.url.value : this.url,
|
||||
source: data.source.present ? data.source.value : this.source,
|
||||
orderKey: data.orderKey.present ? data.orderKey.value : this.orderKey,
|
||||
createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return (StringBuffer('TopSiteData(')
|
||||
..write('id: $id, ')
|
||||
..write('title: $title, ')
|
||||
..write('url: $url, ')
|
||||
..write('source: $source, ')
|
||||
..write('orderKey: $orderKey, ')
|
||||
..write('createdAt: $createdAt')
|
||||
..write(')'))
|
||||
.toString();
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(id, title, url, source, orderKey, createdAt);
|
||||
@override
|
||||
bool operator ==(Object other) =>
|
||||
identical(this, other) ||
|
||||
(other is TopSiteData &&
|
||||
other.id == this.id &&
|
||||
other.title == this.title &&
|
||||
other.url == this.url &&
|
||||
other.source == this.source &&
|
||||
other.orderKey == this.orderKey &&
|
||||
other.createdAt == this.createdAt);
|
||||
}
|
||||
|
||||
class TopSiteCompanion extends UpdateCompanion<TopSiteData> {
|
||||
final Value<String> id;
|
||||
final Value<String> title;
|
||||
final Value<String> url;
|
||||
final Value<int> source;
|
||||
final Value<String> orderKey;
|
||||
final Value<int> createdAt;
|
||||
final Value<int> rowid;
|
||||
const TopSiteCompanion({
|
||||
this.id = const Value.absent(),
|
||||
this.title = const Value.absent(),
|
||||
this.url = const Value.absent(),
|
||||
this.source = const Value.absent(),
|
||||
this.orderKey = const Value.absent(),
|
||||
this.createdAt = const Value.absent(),
|
||||
this.rowid = const Value.absent(),
|
||||
});
|
||||
TopSiteCompanion.insert({
|
||||
required String id,
|
||||
required String title,
|
||||
required String url,
|
||||
required int source,
|
||||
required String orderKey,
|
||||
required int createdAt,
|
||||
this.rowid = const Value.absent(),
|
||||
}) : id = Value(id),
|
||||
title = Value(title),
|
||||
url = Value(url),
|
||||
source = Value(source),
|
||||
orderKey = Value(orderKey),
|
||||
createdAt = Value(createdAt);
|
||||
static Insertable<TopSiteData> custom({
|
||||
Expression<String>? id,
|
||||
Expression<String>? title,
|
||||
Expression<String>? url,
|
||||
Expression<int>? source,
|
||||
Expression<String>? orderKey,
|
||||
Expression<int>? createdAt,
|
||||
Expression<int>? rowid,
|
||||
}) {
|
||||
return RawValuesInsertable({
|
||||
if (id != null) 'id': id,
|
||||
if (title != null) 'title': title,
|
||||
if (url != null) 'url': url,
|
||||
if (source != null) 'source': source,
|
||||
if (orderKey != null) 'order_key': orderKey,
|
||||
if (createdAt != null) 'created_at': createdAt,
|
||||
if (rowid != null) 'rowid': rowid,
|
||||
});
|
||||
}
|
||||
|
||||
TopSiteCompanion copyWith({
|
||||
Value<String>? id,
|
||||
Value<String>? title,
|
||||
Value<String>? url,
|
||||
Value<int>? source,
|
||||
Value<String>? orderKey,
|
||||
Value<int>? createdAt,
|
||||
Value<int>? rowid,
|
||||
}) {
|
||||
return TopSiteCompanion(
|
||||
id: id ?? this.id,
|
||||
title: title ?? this.title,
|
||||
url: url ?? this.url,
|
||||
source: source ?? this.source,
|
||||
orderKey: orderKey ?? this.orderKey,
|
||||
createdAt: createdAt ?? this.createdAt,
|
||||
rowid: rowid ?? this.rowid,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Map<String, Expression> toColumns(bool nullToAbsent) {
|
||||
final map = <String, Expression>{};
|
||||
if (id.present) {
|
||||
map['id'] = Variable<String>(id.value);
|
||||
}
|
||||
if (title.present) {
|
||||
map['title'] = Variable<String>(title.value);
|
||||
}
|
||||
if (url.present) {
|
||||
map['url'] = Variable<String>(url.value);
|
||||
}
|
||||
if (source.present) {
|
||||
map['source'] = Variable<int>(source.value);
|
||||
}
|
||||
if (orderKey.present) {
|
||||
map['order_key'] = Variable<String>(orderKey.value);
|
||||
}
|
||||
if (createdAt.present) {
|
||||
map['created_at'] = Variable<int>(createdAt.value);
|
||||
}
|
||||
if (rowid.present) {
|
||||
map['rowid'] = Variable<int>(rowid.value);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return (StringBuffer('TopSiteCompanion(')
|
||||
..write('id: $id, ')
|
||||
..write('title: $title, ')
|
||||
..write('url: $url, ')
|
||||
..write('source: $source, ')
|
||||
..write('orderKey: $orderKey, ')
|
||||
..write('createdAt: $createdAt, ')
|
||||
..write('rowid: $rowid')
|
||||
..write(')'))
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
|
||||
class HiddenTopSite extends Table
|
||||
with TableInfo<HiddenTopSite, HiddenTopSiteData> {
|
||||
@override
|
||||
final GeneratedDatabase attachedDatabase;
|
||||
final String? _alias;
|
||||
HiddenTopSite(this.attachedDatabase, [this._alias]);
|
||||
late final GeneratedColumn<String> url = GeneratedColumn<String>(
|
||||
'url',
|
||||
aliasedName,
|
||||
false,
|
||||
type: DriftSqlType.string,
|
||||
requiredDuringInsert: true,
|
||||
$customConstraints: 'PRIMARY KEY NOT NULL',
|
||||
);
|
||||
@override
|
||||
List<GeneratedColumn> get $columns => [url];
|
||||
@override
|
||||
String get aliasedName => _alias ?? actualTableName;
|
||||
@override
|
||||
String get actualTableName => $name;
|
||||
static const String $name = 'hidden_top_site';
|
||||
@override
|
||||
Set<GeneratedColumn> get $primaryKey => {url};
|
||||
@override
|
||||
HiddenTopSiteData map(Map<String, dynamic> data, {String? tablePrefix}) {
|
||||
final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : '';
|
||||
return HiddenTopSiteData(
|
||||
url: attachedDatabase.typeMapping.read(
|
||||
DriftSqlType.string,
|
||||
data['${effectivePrefix}url'],
|
||||
)!,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
HiddenTopSite createAlias(String alias) {
|
||||
return HiddenTopSite(attachedDatabase, alias);
|
||||
}
|
||||
|
||||
@override
|
||||
bool get dontWriteConstraints => true;
|
||||
}
|
||||
|
||||
class HiddenTopSiteData extends DataClass
|
||||
implements Insertable<HiddenTopSiteData> {
|
||||
final String url;
|
||||
const HiddenTopSiteData({required this.url});
|
||||
@override
|
||||
Map<String, Expression> toColumns(bool nullToAbsent) {
|
||||
final map = <String, Expression>{};
|
||||
map['url'] = Variable<String>(url);
|
||||
return map;
|
||||
}
|
||||
|
||||
factory HiddenTopSiteData.fromJson(
|
||||
Map<String, dynamic> json, {
|
||||
ValueSerializer? serializer,
|
||||
}) {
|
||||
serializer ??= driftRuntimeOptions.defaultSerializer;
|
||||
return HiddenTopSiteData(url: serializer.fromJson<String>(json['url']));
|
||||
}
|
||||
@override
|
||||
Map<String, dynamic> toJson({ValueSerializer? serializer}) {
|
||||
serializer ??= driftRuntimeOptions.defaultSerializer;
|
||||
return <String, dynamic>{'url': serializer.toJson<String>(url)};
|
||||
}
|
||||
|
||||
HiddenTopSiteData copyWith({String? url}) =>
|
||||
HiddenTopSiteData(url: url ?? this.url);
|
||||
HiddenTopSiteData copyWithCompanion(HiddenTopSiteCompanion data) {
|
||||
return HiddenTopSiteData(url: data.url.present ? data.url.value : this.url);
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return (StringBuffer('HiddenTopSiteData(')
|
||||
..write('url: $url')
|
||||
..write(')'))
|
||||
.toString();
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => url.hashCode;
|
||||
@override
|
||||
bool operator ==(Object other) =>
|
||||
identical(this, other) ||
|
||||
(other is HiddenTopSiteData && other.url == this.url);
|
||||
}
|
||||
|
||||
class HiddenTopSiteCompanion extends UpdateCompanion<HiddenTopSiteData> {
|
||||
final Value<String> url;
|
||||
final Value<int> rowid;
|
||||
const HiddenTopSiteCompanion({
|
||||
this.url = const Value.absent(),
|
||||
this.rowid = const Value.absent(),
|
||||
});
|
||||
HiddenTopSiteCompanion.insert({
|
||||
required String url,
|
||||
this.rowid = const Value.absent(),
|
||||
}) : url = Value(url);
|
||||
static Insertable<HiddenTopSiteData> custom({
|
||||
Expression<String>? url,
|
||||
Expression<int>? rowid,
|
||||
}) {
|
||||
return RawValuesInsertable({
|
||||
if (url != null) 'url': url,
|
||||
if (rowid != null) 'rowid': rowid,
|
||||
});
|
||||
}
|
||||
|
||||
HiddenTopSiteCompanion copyWith({Value<String>? url, Value<int>? rowid}) {
|
||||
return HiddenTopSiteCompanion(
|
||||
url: url ?? this.url,
|
||||
rowid: rowid ?? this.rowid,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Map<String, Expression> toColumns(bool nullToAbsent) {
|
||||
final map = <String, Expression>{};
|
||||
if (url.present) {
|
||||
map['url'] = Variable<String>(url.value);
|
||||
}
|
||||
if (rowid.present) {
|
||||
map['rowid'] = Variable<int>(rowid.value);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return (StringBuffer('HiddenTopSiteCompanion(')
|
||||
..write('url: $url, ')
|
||||
..write('rowid: $rowid')
|
||||
..write(')'))
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
|
||||
class HiddenTopSiteHost extends Table
|
||||
with TableInfo<HiddenTopSiteHost, HiddenTopSiteHostData> {
|
||||
@override
|
||||
final GeneratedDatabase attachedDatabase;
|
||||
final String? _alias;
|
||||
HiddenTopSiteHost(this.attachedDatabase, [this._alias]);
|
||||
late final GeneratedColumn<String> host = GeneratedColumn<String>(
|
||||
'host',
|
||||
aliasedName,
|
||||
false,
|
||||
type: DriftSqlType.string,
|
||||
requiredDuringInsert: true,
|
||||
$customConstraints: 'PRIMARY KEY NOT NULL',
|
||||
);
|
||||
@override
|
||||
List<GeneratedColumn> get $columns => [host];
|
||||
@override
|
||||
String get aliasedName => _alias ?? actualTableName;
|
||||
@override
|
||||
String get actualTableName => $name;
|
||||
static const String $name = 'hidden_top_site_host';
|
||||
@override
|
||||
Set<GeneratedColumn> get $primaryKey => {host};
|
||||
@override
|
||||
HiddenTopSiteHostData map(Map<String, dynamic> data, {String? tablePrefix}) {
|
||||
final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : '';
|
||||
return HiddenTopSiteHostData(
|
||||
host: attachedDatabase.typeMapping.read(
|
||||
DriftSqlType.string,
|
||||
data['${effectivePrefix}host'],
|
||||
)!,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
HiddenTopSiteHost createAlias(String alias) {
|
||||
return HiddenTopSiteHost(attachedDatabase, alias);
|
||||
}
|
||||
|
||||
@override
|
||||
bool get dontWriteConstraints => true;
|
||||
}
|
||||
|
||||
class HiddenTopSiteHostData extends DataClass
|
||||
implements Insertable<HiddenTopSiteHostData> {
|
||||
final String host;
|
||||
const HiddenTopSiteHostData({required this.host});
|
||||
@override
|
||||
Map<String, Expression> toColumns(bool nullToAbsent) {
|
||||
final map = <String, Expression>{};
|
||||
map['host'] = Variable<String>(host);
|
||||
return map;
|
||||
}
|
||||
|
||||
factory HiddenTopSiteHostData.fromJson(
|
||||
Map<String, dynamic> json, {
|
||||
ValueSerializer? serializer,
|
||||
}) {
|
||||
serializer ??= driftRuntimeOptions.defaultSerializer;
|
||||
return HiddenTopSiteHostData(
|
||||
host: serializer.fromJson<String>(json['host']),
|
||||
);
|
||||
}
|
||||
@override
|
||||
Map<String, dynamic> toJson({ValueSerializer? serializer}) {
|
||||
serializer ??= driftRuntimeOptions.defaultSerializer;
|
||||
return <String, dynamic>{'host': serializer.toJson<String>(host)};
|
||||
}
|
||||
|
||||
HiddenTopSiteHostData copyWith({String? host}) =>
|
||||
HiddenTopSiteHostData(host: host ?? this.host);
|
||||
HiddenTopSiteHostData copyWithCompanion(HiddenTopSiteHostCompanion data) {
|
||||
return HiddenTopSiteHostData(
|
||||
host: data.host.present ? data.host.value : this.host,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return (StringBuffer('HiddenTopSiteHostData(')
|
||||
..write('host: $host')
|
||||
..write(')'))
|
||||
.toString();
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => host.hashCode;
|
||||
@override
|
||||
bool operator ==(Object other) =>
|
||||
identical(this, other) ||
|
||||
(other is HiddenTopSiteHostData && other.host == this.host);
|
||||
}
|
||||
|
||||
class HiddenTopSiteHostCompanion
|
||||
extends UpdateCompanion<HiddenTopSiteHostData> {
|
||||
final Value<String> host;
|
||||
final Value<int> rowid;
|
||||
const HiddenTopSiteHostCompanion({
|
||||
this.host = const Value.absent(),
|
||||
this.rowid = const Value.absent(),
|
||||
});
|
||||
HiddenTopSiteHostCompanion.insert({
|
||||
required String host,
|
||||
this.rowid = const Value.absent(),
|
||||
}) : host = Value(host);
|
||||
static Insertable<HiddenTopSiteHostData> custom({
|
||||
Expression<String>? host,
|
||||
Expression<int>? rowid,
|
||||
}) {
|
||||
return RawValuesInsertable({
|
||||
if (host != null) 'host': host,
|
||||
if (rowid != null) 'rowid': rowid,
|
||||
});
|
||||
}
|
||||
|
||||
HiddenTopSiteHostCompanion copyWith({
|
||||
Value<String>? host,
|
||||
Value<int>? rowid,
|
||||
}) {
|
||||
return HiddenTopSiteHostCompanion(
|
||||
host: host ?? this.host,
|
||||
rowid: rowid ?? this.rowid,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Map<String, Expression> toColumns(bool nullToAbsent) {
|
||||
final map = <String, Expression>{};
|
||||
if (host.present) {
|
||||
map['host'] = Variable<String>(host.value);
|
||||
}
|
||||
if (rowid.present) {
|
||||
map['rowid'] = Variable<int>(rowid.value);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return (StringBuffer('HiddenTopSiteHostCompanion(')
|
||||
..write('host: $host, ')
|
||||
..write('rowid: $rowid')
|
||||
..write(')'))
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
|
||||
class DatabaseAtV2 extends GeneratedDatabase {
|
||||
DatabaseAtV2(QueryExecutor e) : super(e);
|
||||
late final TopSite topSite = TopSite(this);
|
||||
late final Index idxTopSiteOrderKey = Index(
|
||||
'idx_top_site_order_key',
|
||||
'CREATE INDEX idx_top_site_order_key ON top_site (order_key)',
|
||||
);
|
||||
late final HiddenTopSite hiddenTopSite = HiddenTopSite(this);
|
||||
late final HiddenTopSiteHost hiddenTopSiteHost = HiddenTopSiteHost(this);
|
||||
@override
|
||||
Iterable<TableInfo<Table, Object?>> get allTables =>
|
||||
allSchemaEntities.whereType<TableInfo<Table, Object?>>();
|
||||
@override
|
||||
List<DatabaseSchemaEntity> get allSchemaEntities => [
|
||||
topSite,
|
||||
idxTopSiteOrderKey,
|
||||
hiddenTopSite,
|
||||
hiddenTopSiteHost,
|
||||
];
|
||||
@override
|
||||
int get schemaVersion => 2;
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
// dart format width=80
|
||||
// ignore_for_file: unused_local_variable, unused_import
|
||||
import 'package:drift/drift.dart';
|
||||
import 'package:drift_dev/api/migrations_native.dart';
|
||||
import 'package:weblibre/features/geckoview/features/top_sites/data/database/database.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'generated/schema.dart';
|
||||
|
||||
import 'generated/schema_v1.dart' as v1;
|
||||
import 'generated/schema_v2.dart' as v2;
|
||||
|
||||
void main() {
|
||||
driftRuntimeOptions.dontWarnAboutMultipleDatabases = true;
|
||||
late SchemaVerifier verifier;
|
||||
|
||||
setUpAll(() {
|
||||
verifier = SchemaVerifier(GeneratedHelper());
|
||||
});
|
||||
|
||||
group('simple database migrations', () {
|
||||
// These simple tests verify all possible schema updates with a simple (no
|
||||
// data) migration. This is a quick way to ensure that written database
|
||||
// migrations properly alter the schema.
|
||||
const versions = GeneratedHelper.versions;
|
||||
for (final (i, fromVersion) in versions.indexed) {
|
||||
group('from $fromVersion', () {
|
||||
for (final toVersion in versions.skip(i + 1)) {
|
||||
test('to $toVersion', () async {
|
||||
final schema = await verifier.schemaAt(fromVersion);
|
||||
final db = TopSiteDatabase(schema.newConnection());
|
||||
await verifier.migrateAndValidate(db, toVersion);
|
||||
await db.close();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// The following template shows how to write tests ensuring your migrations
|
||||
// preserve existing data.
|
||||
// Testing this can be useful for migrations that change existing columns
|
||||
// (e.g. by alterating their type or constraints). Migrations that only add
|
||||
// tables or columns typically don't need these advanced tests. For more
|
||||
// information, see https://drift.simonbinder.eu/migrations/tests/#verifying-data-integrity
|
||||
// TODO: This generated template shows how these tests could be written. Adopt
|
||||
// it to your own needs when testing migrations with data integrity.
|
||||
test('migration from v1 to v2 does not corrupt data', () async {
|
||||
// Add data to insert into the old database, and the expected rows after the
|
||||
// migration.
|
||||
// TODO: Fill these lists
|
||||
final oldTopSiteData = <v1.TopSiteData>[];
|
||||
final expectedNewTopSiteData = <v2.TopSiteData>[];
|
||||
|
||||
final oldHiddenTopSiteData = <v1.HiddenTopSiteData>[];
|
||||
final expectedNewHiddenTopSiteData = <v2.HiddenTopSiteData>[];
|
||||
|
||||
await verifier.testWithDataIntegrity(
|
||||
oldVersion: 1,
|
||||
newVersion: 2,
|
||||
createOld: v1.DatabaseAtV1.new,
|
||||
createNew: v2.DatabaseAtV2.new,
|
||||
openTestedDatabase: TopSiteDatabase.new,
|
||||
createItems: (batch, oldDb) {
|
||||
batch.insertAll(oldDb.topSite, oldTopSiteData);
|
||||
batch.insertAll(oldDb.hiddenTopSite, oldHiddenTopSiteData);
|
||||
},
|
||||
validateItems: (newDb) async {
|
||||
expect(expectedNewTopSiteData, await newDb.select(newDb.topSite).get());
|
||||
expect(
|
||||
expectedNewHiddenTopSiteData,
|
||||
await newDb.select(newDb.hiddenTopSite).get(),
|
||||
);
|
||||
},
|
||||
);
|
||||
});
|
||||
}
|
||||
@@ -1,181 +0,0 @@
|
||||
{
|
||||
"_meta": {
|
||||
"description": "This file contains a serialized version of schema entities for drift.",
|
||||
"version": "1.3.0"
|
||||
},
|
||||
"options": {
|
||||
"store_date_time_values_as_text": false
|
||||
},
|
||||
"entities": [
|
||||
{
|
||||
"id": 0,
|
||||
"references": [],
|
||||
"type": "table",
|
||||
"data": {
|
||||
"name": "top_site",
|
||||
"was_declared_in_moor": true,
|
||||
"columns": [
|
||||
{
|
||||
"name": "id",
|
||||
"getter_name": "id",
|
||||
"moor_type": "string",
|
||||
"nullable": false,
|
||||
"customConstraints": "PRIMARY KEY NOT NULL",
|
||||
"default_dart": null,
|
||||
"default_client_dart": null,
|
||||
"dsl_features": [
|
||||
"primary-key"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "title",
|
||||
"getter_name": "title",
|
||||
"moor_type": "string",
|
||||
"nullable": false,
|
||||
"customConstraints": "NOT NULL",
|
||||
"default_dart": null,
|
||||
"default_client_dart": null,
|
||||
"dsl_features": []
|
||||
},
|
||||
{
|
||||
"name": "url",
|
||||
"getter_name": "url",
|
||||
"moor_type": "string",
|
||||
"nullable": false,
|
||||
"customConstraints": "NOT NULL",
|
||||
"default_dart": null,
|
||||
"default_client_dart": null,
|
||||
"dsl_features": [],
|
||||
"type_converter": {
|
||||
"dart_expr": "const UriConverter()",
|
||||
"dart_type_name": "Uri"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "source",
|
||||
"getter_name": "source",
|
||||
"moor_type": "int",
|
||||
"nullable": false,
|
||||
"customConstraints": "NOT NULL",
|
||||
"default_dart": null,
|
||||
"default_client_dart": null,
|
||||
"dsl_features": [],
|
||||
"type_converter": {
|
||||
"dart_expr": "const EnumIndexConverter<StoredTopSiteSource>(StoredTopSiteSource.values)",
|
||||
"dart_type_name": "StoredTopSiteSource"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "order_key",
|
||||
"getter_name": "orderKey",
|
||||
"moor_type": "string",
|
||||
"nullable": false,
|
||||
"customConstraints": "NOT NULL",
|
||||
"default_dart": null,
|
||||
"default_client_dart": null,
|
||||
"dsl_features": []
|
||||
},
|
||||
{
|
||||
"name": "created_at",
|
||||
"getter_name": "createdAt",
|
||||
"moor_type": "dateTime",
|
||||
"nullable": false,
|
||||
"customConstraints": "NOT NULL",
|
||||
"default_dart": null,
|
||||
"default_client_dart": null,
|
||||
"dsl_features": []
|
||||
}
|
||||
],
|
||||
"is_virtual": false,
|
||||
"without_rowid": false,
|
||||
"constraints": [
|
||||
"UNIQUE(url)"
|
||||
],
|
||||
"unique_keys": [
|
||||
[
|
||||
"url"
|
||||
]
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 1,
|
||||
"references": [
|
||||
0
|
||||
],
|
||||
"type": "index",
|
||||
"data": {
|
||||
"on": 0,
|
||||
"name": "idx_top_site_order_key",
|
||||
"sql": "CREATE INDEX idx_top_site_order_key ON top_site(order_key);",
|
||||
"unique": false,
|
||||
"columns": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"references": [],
|
||||
"type": "table",
|
||||
"data": {
|
||||
"name": "top_site_seed_state",
|
||||
"was_declared_in_moor": true,
|
||||
"columns": [
|
||||
{
|
||||
"name": "seed_id",
|
||||
"getter_name": "seedId",
|
||||
"moor_type": "string",
|
||||
"nullable": false,
|
||||
"customConstraints": "PRIMARY KEY NOT NULL",
|
||||
"default_dart": null,
|
||||
"default_client_dart": null,
|
||||
"dsl_features": [
|
||||
"primary-key"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "applied_at",
|
||||
"getter_name": "appliedAt",
|
||||
"moor_type": "dateTime",
|
||||
"nullable": false,
|
||||
"customConstraints": "NOT NULL",
|
||||
"default_dart": null,
|
||||
"default_client_dart": null,
|
||||
"dsl_features": []
|
||||
}
|
||||
],
|
||||
"is_virtual": false,
|
||||
"without_rowid": false,
|
||||
"constraints": []
|
||||
}
|
||||
}
|
||||
],
|
||||
"fixed_sql": [
|
||||
{
|
||||
"name": "top_site",
|
||||
"sql": [
|
||||
{
|
||||
"dialect": "sqlite",
|
||||
"sql": "CREATE TABLE IF NOT EXISTS \"top_site\" (\"id\" TEXT PRIMARY KEY NOT NULL, \"title\" TEXT NOT NULL, \"url\" TEXT NOT NULL, \"source\" INTEGER NOT NULL, \"order_key\" TEXT NOT NULL, \"created_at\" INTEGER NOT NULL, UNIQUE(url));"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "idx_top_site_order_key",
|
||||
"sql": [
|
||||
{
|
||||
"dialect": "sqlite",
|
||||
"sql": "CREATE INDEX idx_top_site_order_key ON top_site (order_key)"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "top_site_seed_state",
|
||||
"sql": [
|
||||
{
|
||||
"dialect": "sqlite",
|
||||
"sql": "CREATE TABLE IF NOT EXISTS \"top_site_seed_state\" (\"seed_id\" TEXT PRIMARY KEY NOT NULL, \"applied_at\" INTEGER NOT NULL);"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,159 +0,0 @@
|
||||
// dart format width=80
|
||||
// GENERATED BY drift_dev, DO NOT MODIFY.
|
||||
// ignore_for_file: type=lint,unused_import
|
||||
//
|
||||
import 'package:drift/drift.dart';
|
||||
|
||||
class TopSite extends Table with TableInfo {
|
||||
@override
|
||||
final GeneratedDatabase attachedDatabase;
|
||||
final String? _alias;
|
||||
TopSite(this.attachedDatabase, [this._alias]);
|
||||
late final GeneratedColumn<String> id = GeneratedColumn<String>(
|
||||
'id',
|
||||
aliasedName,
|
||||
false,
|
||||
type: DriftSqlType.string,
|
||||
requiredDuringInsert: true,
|
||||
$customConstraints: 'PRIMARY KEY NOT NULL',
|
||||
);
|
||||
late final GeneratedColumn<String> title = GeneratedColumn<String>(
|
||||
'title',
|
||||
aliasedName,
|
||||
false,
|
||||
type: DriftSqlType.string,
|
||||
requiredDuringInsert: true,
|
||||
$customConstraints: 'NOT NULL',
|
||||
);
|
||||
late final GeneratedColumn<String> url = GeneratedColumn<String>(
|
||||
'url',
|
||||
aliasedName,
|
||||
false,
|
||||
type: DriftSqlType.string,
|
||||
requiredDuringInsert: true,
|
||||
$customConstraints: 'NOT NULL',
|
||||
);
|
||||
late final GeneratedColumn<int> source = GeneratedColumn<int>(
|
||||
'source',
|
||||
aliasedName,
|
||||
false,
|
||||
type: DriftSqlType.int,
|
||||
requiredDuringInsert: true,
|
||||
$customConstraints: 'NOT NULL',
|
||||
);
|
||||
late final GeneratedColumn<String> orderKey = GeneratedColumn<String>(
|
||||
'order_key',
|
||||
aliasedName,
|
||||
false,
|
||||
type: DriftSqlType.string,
|
||||
requiredDuringInsert: true,
|
||||
$customConstraints: 'NOT NULL',
|
||||
);
|
||||
late final GeneratedColumn<int> createdAt = GeneratedColumn<int>(
|
||||
'created_at',
|
||||
aliasedName,
|
||||
false,
|
||||
type: DriftSqlType.int,
|
||||
requiredDuringInsert: true,
|
||||
$customConstraints: 'NOT NULL',
|
||||
);
|
||||
@override
|
||||
List<GeneratedColumn> get $columns => [
|
||||
id,
|
||||
title,
|
||||
url,
|
||||
source,
|
||||
orderKey,
|
||||
createdAt,
|
||||
];
|
||||
@override
|
||||
String get aliasedName => _alias ?? actualTableName;
|
||||
@override
|
||||
String get actualTableName => $name;
|
||||
static const String $name = 'top_site';
|
||||
@override
|
||||
Set<GeneratedColumn> get $primaryKey => {id};
|
||||
@override
|
||||
List<Set<GeneratedColumn>> get uniqueKeys => [
|
||||
{url},
|
||||
];
|
||||
@override
|
||||
Never map(Map<String, dynamic> data, {String? tablePrefix}) {
|
||||
throw UnsupportedError('TableInfo.map in schema verification code');
|
||||
}
|
||||
|
||||
@override
|
||||
TopSite createAlias(String alias) {
|
||||
return TopSite(attachedDatabase, alias);
|
||||
}
|
||||
|
||||
@override
|
||||
List<String> get customConstraints => const ['UNIQUE(url)'];
|
||||
@override
|
||||
bool get dontWriteConstraints => true;
|
||||
}
|
||||
|
||||
class TopSiteSeedState extends Table with TableInfo {
|
||||
@override
|
||||
final GeneratedDatabase attachedDatabase;
|
||||
final String? _alias;
|
||||
TopSiteSeedState(this.attachedDatabase, [this._alias]);
|
||||
late final GeneratedColumn<String> seedId = GeneratedColumn<String>(
|
||||
'seed_id',
|
||||
aliasedName,
|
||||
false,
|
||||
type: DriftSqlType.string,
|
||||
requiredDuringInsert: true,
|
||||
$customConstraints: 'PRIMARY KEY NOT NULL',
|
||||
);
|
||||
late final GeneratedColumn<int> appliedAt = GeneratedColumn<int>(
|
||||
'applied_at',
|
||||
aliasedName,
|
||||
false,
|
||||
type: DriftSqlType.int,
|
||||
requiredDuringInsert: true,
|
||||
$customConstraints: 'NOT NULL',
|
||||
);
|
||||
@override
|
||||
List<GeneratedColumn> get $columns => [seedId, appliedAt];
|
||||
@override
|
||||
String get aliasedName => _alias ?? actualTableName;
|
||||
@override
|
||||
String get actualTableName => $name;
|
||||
static const String $name = 'top_site_seed_state';
|
||||
@override
|
||||
Set<GeneratedColumn> get $primaryKey => {seedId};
|
||||
@override
|
||||
Never map(Map<String, dynamic> data, {String? tablePrefix}) {
|
||||
throw UnsupportedError('TableInfo.map in schema verification code');
|
||||
}
|
||||
|
||||
@override
|
||||
TopSiteSeedState createAlias(String alias) {
|
||||
return TopSiteSeedState(attachedDatabase, alias);
|
||||
}
|
||||
|
||||
@override
|
||||
bool get dontWriteConstraints => true;
|
||||
}
|
||||
|
||||
class DatabaseAtV1 extends GeneratedDatabase {
|
||||
DatabaseAtV1(QueryExecutor e) : super(e);
|
||||
late final TopSite topSite = TopSite(this);
|
||||
late final Index idxTopSiteOrderKey = Index(
|
||||
'idx_top_site_order_key',
|
||||
'CREATE INDEX idx_top_site_order_key ON top_site (order_key)',
|
||||
);
|
||||
late final TopSiteSeedState topSiteSeedState = TopSiteSeedState(this);
|
||||
@override
|
||||
Iterable<TableInfo<Table, Object?>> get allTables =>
|
||||
allSchemaEntities.whereType<TableInfo<Table, Object?>>();
|
||||
@override
|
||||
List<DatabaseSchemaEntity> get allSchemaEntities => [
|
||||
topSite,
|
||||
idxTopSiteOrderKey,
|
||||
topSiteSeedState,
|
||||
];
|
||||
@override
|
||||
int get schemaVersion => 1;
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2024-2026 Fabian Freund.
|
||||
*
|
||||
* This file is part of WebLibre
|
||||
* (see https://weblibre.eu).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// dart format width=80
|
||||
// ignore_for_file: unused_local_variable, unused_import
|
||||
import 'package:drift/drift.dart';
|
||||
import 'package:drift_dev/api/migrations_native.dart';
|
||||
import 'package:weblibre/features/geckoview/features/top_sites/data/database/database.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'generated/schema.dart';
|
||||
|
||||
import 'generated/schema_v1.dart' as v1;
|
||||
|
||||
void main() {
|
||||
driftRuntimeOptions.dontWarnAboutMultipleDatabases = true;
|
||||
late SchemaVerifier verifier;
|
||||
|
||||
setUpAll(() {
|
||||
verifier = SchemaVerifier(GeneratedHelper());
|
||||
});
|
||||
|
||||
group('simple database migrations', () {
|
||||
const versions = GeneratedHelper.versions;
|
||||
for (final (i, fromVersion) in versions.indexed) {
|
||||
group('from $fromVersion', () {
|
||||
for (final toVersion in versions.skip(i + 1)) {
|
||||
test('to $toVersion', () async {
|
||||
final schema = await verifier.schemaAt(fromVersion);
|
||||
final db = TopSiteDatabase(schema.newConnection());
|
||||
await verifier.migrateAndValidate(db, toVersion);
|
||||
await db.close();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
test('v1 schema creation works', () async {
|
||||
final schema = await verifier.schemaAt(1);
|
||||
final db = TopSiteDatabase(schema.newConnection());
|
||||
await verifier.migrateAndValidate(db, 1);
|
||||
await db.close();
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user