mirror of
https://github.com/lanedirt/AliasVault.git
synced 2025-12-05 19:07:26 -06:00
Compare commits
4 Commits
3d4c148059
...
20c9f08616
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
20c9f08616 | ||
|
|
7f898a2073 | ||
|
|
dbc42fdea4 | ||
|
|
a3db88ee42 |
@@ -321,4 +321,135 @@ type ItemTag = {
|
||||
IsDeleted: number;
|
||||
};
|
||||
|
||||
export { type Alias, type Attachment, type Credential, type EncryptionKey, FieldKey, type FieldKeyValue, type ItemTag, type Passkey, type PasswordSettings, type Tag, type TotpCode };
|
||||
/**
|
||||
* Item types supported by the vault
|
||||
*/
|
||||
type ItemType = 'Login' | 'CreditCard' | 'Identity' | 'Note';
|
||||
/**
|
||||
* Item type representing vault entries in the new field-based data model.
|
||||
* Replaces the old Credential type.
|
||||
*/
|
||||
type Item = {
|
||||
Id: string;
|
||||
Name: string | null;
|
||||
ItemType: ItemType;
|
||||
Logo?: Uint8Array | number[];
|
||||
FolderId?: string | null;
|
||||
FolderPath?: string | null;
|
||||
Tags?: ItemTagRef[];
|
||||
Fields: ItemField[];
|
||||
HasPasskey?: boolean;
|
||||
HasAttachment?: boolean;
|
||||
HasTotp?: boolean;
|
||||
CreatedAt: string;
|
||||
UpdatedAt: string;
|
||||
};
|
||||
/**
|
||||
* Field value within an item
|
||||
*/
|
||||
type ItemField = {
|
||||
FieldKey: string;
|
||||
Label: string;
|
||||
FieldType: FieldType;
|
||||
Value: string | string[];
|
||||
IsHidden: boolean;
|
||||
DisplayOrder: number;
|
||||
};
|
||||
/**
|
||||
* Field types for rendering and validation
|
||||
*/
|
||||
type FieldType = 'Text' | 'Password' | 'Email' | 'URL' | 'Date' | 'Number' | 'Phone' | 'TextArea';
|
||||
/**
|
||||
* Tag reference for display within an item
|
||||
*/
|
||||
type ItemTagRef = {
|
||||
Id: string;
|
||||
Name: string;
|
||||
Color?: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper functions for working with Item model
|
||||
*/
|
||||
/**
|
||||
* Get a single field value by FieldKey
|
||||
*/
|
||||
declare function getFieldValue(item: Item, fieldKey: string): string | undefined;
|
||||
/**
|
||||
* Get all values for a multi-value field
|
||||
*/
|
||||
declare function getFieldValues(item: Item, fieldKey: string): string[];
|
||||
/**
|
||||
* Check if a field exists and has a value
|
||||
*/
|
||||
declare function hasField(item: Item, fieldKey: string): boolean;
|
||||
/**
|
||||
* Group fields by a categorization function
|
||||
*/
|
||||
declare function groupFields(item: Item, grouper: (field: ItemField) => string): Record<string, ItemField[]>;
|
||||
/**
|
||||
* Group fields by standard categories (Login, Alias, Custom)
|
||||
*/
|
||||
declare function groupFieldsByCategory(item: Item): Record<string, ItemField[]>;
|
||||
/**
|
||||
* Convert new Item model to legacy Credential model for backward compatibility.
|
||||
* @deprecated Use Item model directly. This is a temporary compatibility layer.
|
||||
*/
|
||||
declare function itemToCredential(item: Item): Credential;
|
||||
|
||||
/**
|
||||
* System field definition with metadata.
|
||||
* System fields are predefined fields with immutable keys like 'login.username'.
|
||||
* Their metadata (label, type, etc.) is defined here in code, not in the database.
|
||||
*/
|
||||
type SystemFieldDefinition = {
|
||||
/** Unique system field key (e.g., 'login.username') */
|
||||
FieldKey: string;
|
||||
/** Display label for the field */
|
||||
Label: string;
|
||||
/** Field type for rendering/validation */
|
||||
FieldType: FieldType;
|
||||
/** Whether field is hidden/masked by default */
|
||||
IsHidden: boolean;
|
||||
/** Whether field supports multiple values */
|
||||
IsMultiValue: boolean;
|
||||
/** Item types this field applies to */
|
||||
ApplicableToTypes: ItemType[];
|
||||
/** Whether to track field value history */
|
||||
EnableHistory: boolean;
|
||||
/** Category for grouping in UI */
|
||||
Category: 'Login' | 'Alias' | 'Card' | 'Identity' | 'API' | 'Note';
|
||||
/** Default display order within category (lower = first) */
|
||||
DefaultDisplayOrder: number;
|
||||
};
|
||||
/**
|
||||
* Registry of all system-defined fields.
|
||||
* These fields are immutable and their metadata is defined in code.
|
||||
* DO NOT modify these definitions without careful consideration of backwards compatibility.
|
||||
*/
|
||||
declare const SystemFieldRegistry: Record<string, SystemFieldDefinition>;
|
||||
/**
|
||||
* Get system field definition by key.
|
||||
* Returns undefined if the field key is not a system field.
|
||||
*/
|
||||
declare function getSystemField(fieldKey: string): SystemFieldDefinition | undefined;
|
||||
/**
|
||||
* Check if a field key represents a system field.
|
||||
*/
|
||||
declare function isSystemField(fieldKey: string): boolean;
|
||||
/**
|
||||
* Get all system fields applicable to a specific item type.
|
||||
* Results are sorted by DefaultDisplayOrder.
|
||||
*/
|
||||
declare function getSystemFieldsForItemType(itemType: ItemType): SystemFieldDefinition[];
|
||||
/**
|
||||
* Get all system field keys.
|
||||
*/
|
||||
declare function getAllSystemFieldKeys(): string[];
|
||||
/**
|
||||
* Check if a field key matches a known system field prefix.
|
||||
* This is useful for validation even before a specific field is registered.
|
||||
*/
|
||||
declare function isSystemFieldPrefix(fieldKey: string): boolean;
|
||||
|
||||
export { type Alias, type Attachment, type Credential, type EncryptionKey, FieldKey, type FieldKeyValue, type FieldType, type Item, type ItemField, type ItemTag, type ItemTagRef, type ItemType, type Passkey, type PasswordSettings, type SystemFieldDefinition, SystemFieldRegistry, type Tag, type TotpCode, getAllSystemFieldKeys, getFieldValue, getFieldValues, getSystemField, getSystemFieldsForItemType, groupFields, groupFieldsByCategory, hasField, isSystemField, isSystemFieldPrefix, itemToCredential };
|
||||
|
||||
@@ -151,6 +151,219 @@ var FieldKey = {
|
||||
AliasBirthdate: "alias.birthdate"
|
||||
};
|
||||
|
||||
export { FieldKey };
|
||||
// src/vault/ItemMethods.ts
|
||||
function getFieldValue(item, fieldKey) {
|
||||
const field = item.Fields.find((f) => f.FieldKey === fieldKey);
|
||||
if (!field) {
|
||||
return void 0;
|
||||
}
|
||||
return Array.isArray(field.Value) ? field.Value[0] : field.Value;
|
||||
}
|
||||
function getFieldValues(item, fieldKey) {
|
||||
const field = item.Fields.find((f) => f.FieldKey === fieldKey);
|
||||
if (!field) {
|
||||
return [];
|
||||
}
|
||||
return Array.isArray(field.Value) ? field.Value : [field.Value];
|
||||
}
|
||||
function hasField(item, fieldKey) {
|
||||
const value = getFieldValue(item, fieldKey);
|
||||
return value !== void 0 && value !== "";
|
||||
}
|
||||
function groupFields(item, grouper) {
|
||||
const groups = {};
|
||||
item.Fields.forEach((field) => {
|
||||
const group = grouper(field);
|
||||
if (!groups[group]) {
|
||||
groups[group] = [];
|
||||
}
|
||||
groups[group].push(field);
|
||||
});
|
||||
return groups;
|
||||
}
|
||||
function groupFieldsByCategory(item) {
|
||||
return groupFields(item, (field) => {
|
||||
if (field.FieldKey === FieldKey.AliasEmail) {
|
||||
return "Login";
|
||||
}
|
||||
if (field.FieldKey.startsWith("login.")) {
|
||||
return "Login";
|
||||
}
|
||||
if (field.FieldKey.startsWith("alias.")) {
|
||||
return "Alias";
|
||||
}
|
||||
if (field.FieldKey.startsWith("card.")) {
|
||||
return "Card";
|
||||
}
|
||||
if (field.FieldKey.startsWith("identity.")) {
|
||||
return "Identity";
|
||||
}
|
||||
if (field.FieldKey.startsWith("api.")) {
|
||||
return "API";
|
||||
}
|
||||
return "Custom";
|
||||
});
|
||||
}
|
||||
function itemToCredential(item) {
|
||||
return {
|
||||
Id: item.Id,
|
||||
Username: getFieldValue(item, FieldKey.LoginUsername),
|
||||
Password: getFieldValue(item, FieldKey.LoginPassword) || "",
|
||||
ServiceName: item.Name || "",
|
||||
ServiceUrl: getFieldValue(item, FieldKey.LoginUrl),
|
||||
Logo: item.Logo,
|
||||
Notes: getFieldValue(item, FieldKey.LoginNotes),
|
||||
Alias: {
|
||||
FirstName: getFieldValue(item, FieldKey.AliasFirstName),
|
||||
LastName: getFieldValue(item, FieldKey.AliasLastName),
|
||||
NickName: getFieldValue(item, FieldKey.AliasNickname),
|
||||
BirthDate: getFieldValue(item, FieldKey.AliasBirthdate) || "",
|
||||
Gender: getFieldValue(item, FieldKey.AliasGender),
|
||||
Email: getFieldValue(item, FieldKey.AliasEmail)
|
||||
},
|
||||
HasPasskey: item.HasPasskey,
|
||||
HasAttachment: item.HasAttachment
|
||||
};
|
||||
}
|
||||
|
||||
// src/vault/SystemFieldRegistry.ts
|
||||
var SystemFieldRegistry = {
|
||||
// Login Fields
|
||||
"login.username": {
|
||||
FieldKey: "login.username",
|
||||
Label: "Username",
|
||||
FieldType: "Text",
|
||||
IsHidden: false,
|
||||
IsMultiValue: false,
|
||||
ApplicableToTypes: ["Login"],
|
||||
EnableHistory: true,
|
||||
Category: "Login",
|
||||
DefaultDisplayOrder: 10
|
||||
},
|
||||
"login.password": {
|
||||
FieldKey: "login.password",
|
||||
Label: "Password",
|
||||
FieldType: "Password",
|
||||
IsHidden: true,
|
||||
IsMultiValue: false,
|
||||
ApplicableToTypes: ["Login"],
|
||||
EnableHistory: true,
|
||||
Category: "Login",
|
||||
DefaultDisplayOrder: 20
|
||||
},
|
||||
"login.url": {
|
||||
FieldKey: "login.url",
|
||||
Label: "Website",
|
||||
FieldType: "URL",
|
||||
IsHidden: false,
|
||||
IsMultiValue: true,
|
||||
ApplicableToTypes: ["Login"],
|
||||
EnableHistory: false,
|
||||
Category: "Login",
|
||||
DefaultDisplayOrder: 30
|
||||
},
|
||||
"login.notes": {
|
||||
FieldKey: "login.notes",
|
||||
Label: "Notes",
|
||||
FieldType: "TextArea",
|
||||
IsHidden: false,
|
||||
IsMultiValue: false,
|
||||
ApplicableToTypes: ["Login", "CreditCard", "Identity", "Note"],
|
||||
EnableHistory: false,
|
||||
Category: "Login",
|
||||
DefaultDisplayOrder: 100
|
||||
},
|
||||
// Alias Fields
|
||||
"alias.email": {
|
||||
FieldKey: "alias.email",
|
||||
Label: "Email",
|
||||
FieldType: "Email",
|
||||
IsHidden: false,
|
||||
IsMultiValue: false,
|
||||
ApplicableToTypes: ["Login"],
|
||||
EnableHistory: true,
|
||||
Category: "Alias",
|
||||
DefaultDisplayOrder: 10
|
||||
},
|
||||
"alias.first_name": {
|
||||
FieldKey: "alias.first_name",
|
||||
Label: "First Name",
|
||||
FieldType: "Text",
|
||||
IsHidden: false,
|
||||
IsMultiValue: false,
|
||||
ApplicableToTypes: ["Login", "Identity"],
|
||||
EnableHistory: false,
|
||||
Category: "Alias",
|
||||
DefaultDisplayOrder: 20
|
||||
},
|
||||
"alias.last_name": {
|
||||
FieldKey: "alias.last_name",
|
||||
Label: "Last Name",
|
||||
FieldType: "Text",
|
||||
IsHidden: false,
|
||||
IsMultiValue: false,
|
||||
ApplicableToTypes: ["Login", "Identity"],
|
||||
EnableHistory: false,
|
||||
Category: "Alias",
|
||||
DefaultDisplayOrder: 30
|
||||
},
|
||||
"alias.nickname": {
|
||||
FieldKey: "alias.nickname",
|
||||
Label: "Nickname",
|
||||
FieldType: "Text",
|
||||
IsHidden: false,
|
||||
IsMultiValue: false,
|
||||
ApplicableToTypes: ["Login"],
|
||||
EnableHistory: false,
|
||||
Category: "Alias",
|
||||
DefaultDisplayOrder: 40
|
||||
},
|
||||
"alias.gender": {
|
||||
FieldKey: "alias.gender",
|
||||
Label: "Gender",
|
||||
FieldType: "Text",
|
||||
IsHidden: false,
|
||||
IsMultiValue: false,
|
||||
ApplicableToTypes: ["Login", "Identity"],
|
||||
EnableHistory: false,
|
||||
Category: "Alias",
|
||||
DefaultDisplayOrder: 50
|
||||
},
|
||||
"alias.birthdate": {
|
||||
FieldKey: "alias.birthdate",
|
||||
Label: "Birth Date",
|
||||
FieldType: "Date",
|
||||
IsHidden: false,
|
||||
IsMultiValue: false,
|
||||
ApplicableToTypes: ["Login", "Identity"],
|
||||
EnableHistory: false,
|
||||
Category: "Alias",
|
||||
DefaultDisplayOrder: 60
|
||||
}
|
||||
/*
|
||||
* Note: Card, Identity, and API fields can be added here when those item types are implemented
|
||||
* Example:
|
||||
* 'card.number': { ... },
|
||||
* 'card.cardholder_name': { ... },
|
||||
* 'identity.phone_number': { ... },
|
||||
*/
|
||||
};
|
||||
function getSystemField(fieldKey) {
|
||||
return SystemFieldRegistry[fieldKey];
|
||||
}
|
||||
function isSystemField(fieldKey) {
|
||||
return fieldKey in SystemFieldRegistry;
|
||||
}
|
||||
function getSystemFieldsForItemType(itemType) {
|
||||
return Object.values(SystemFieldRegistry).filter((field) => field.ApplicableToTypes.includes(itemType)).sort((a, b) => a.DefaultDisplayOrder - b.DefaultDisplayOrder);
|
||||
}
|
||||
function getAllSystemFieldKeys() {
|
||||
return Object.keys(SystemFieldRegistry);
|
||||
}
|
||||
function isSystemFieldPrefix(fieldKey) {
|
||||
return fieldKey.startsWith("login.") || fieldKey.startsWith("alias.") || fieldKey.startsWith("card.") || fieldKey.startsWith("identity.") || fieldKey.startsWith("api.") || fieldKey.startsWith("note.");
|
||||
}
|
||||
|
||||
export { FieldKey, SystemFieldRegistry, getAllSystemFieldKeys, getFieldValue, getFieldValues, getSystemField, getSystemFieldsForItemType, groupFields, groupFieldsByCategory, hasField, isSystemField, isSystemFieldPrefix, itemToCredential };
|
||||
//# sourceMappingURL=index.js.map
|
||||
//# sourceMappingURL=index.js.map
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -728,14 +728,12 @@ CREATE INDEX IF NOT EXISTS "IX_Attachments_ItemId" ON "Attachments" ("ItemId");
|
||||
|
||||
CREATE TABLE "FieldDefinitions" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_FieldDefinitions" PRIMARY KEY,
|
||||
"FieldKey" TEXT NULL,
|
||||
"EntityType" TEXT NULL,
|
||||
"FieldType" TEXT NOT NULL,
|
||||
"Label" TEXT NOT NULL,
|
||||
"IsMultiValue" INTEGER NOT NULL,
|
||||
"DefaultVisibility" TEXT NULL,
|
||||
"IsHidden" INTEGER NOT NULL,
|
||||
"EnableHistory" INTEGER NOT NULL,
|
||||
"DisplayOrder" INTEGER NOT NULL,
|
||||
"Weight" INTEGER NOT NULL,
|
||||
"ApplicableToTypes" TEXT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
@@ -746,7 +744,7 @@ CREATE TABLE "Folders" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_Folders" PRIMARY KEY,
|
||||
"Name" TEXT NOT NULL,
|
||||
"ParentFolderId" TEXT NULL,
|
||||
"DisplayOrder" INTEGER NOT NULL,
|
||||
"Weight" INTEGER NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL,
|
||||
@@ -764,6 +762,16 @@ CREATE TABLE "Logos" (
|
||||
"IsDeleted" INTEGER NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE "Tags" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_Tags" PRIMARY KEY,
|
||||
"Name" TEXT NOT NULL,
|
||||
"Color" TEXT NULL,
|
||||
"DisplayOrder" INTEGER NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE "Items" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_Items" PRIMARY KEY,
|
||||
"Name" TEXT NULL,
|
||||
@@ -793,9 +801,10 @@ CREATE TABLE "FieldHistories" (
|
||||
CREATE TABLE "FieldValues" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_FieldValues" PRIMARY KEY,
|
||||
"ItemId" TEXT NOT NULL,
|
||||
"FieldDefinitionId" TEXT NOT NULL,
|
||||
"FieldDefinitionId" TEXT NULL,
|
||||
"FieldKey" TEXT NULL,
|
||||
"Value" TEXT NULL,
|
||||
"ValueIndex" INTEGER NOT NULL,
|
||||
"Weight" INTEGER NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL,
|
||||
@@ -803,7 +812,16 @@ CREATE TABLE "FieldValues" (
|
||||
CONSTRAINT "FK_FieldValues_Items_ItemId" FOREIGN KEY ("ItemId") REFERENCES "Items" ("Id") ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE INDEX "IX_FieldDefinitions_FieldKey" ON "FieldDefinitions" ("FieldKey");
|
||||
CREATE TABLE "ItemTags" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_ItemTags" PRIMARY KEY,
|
||||
"ItemId" TEXT NOT NULL,
|
||||
"TagId" TEXT NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL,
|
||||
CONSTRAINT "FK_ItemTags_Items_ItemId" FOREIGN KEY ("ItemId") REFERENCES "Items" ("Id") ON DELETE CASCADE,
|
||||
CONSTRAINT "FK_ItemTags_Tags_TagId" FOREIGN KEY ("TagId") REFERENCES "Tags" ("Id") ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE INDEX "IX_FieldHistories_FieldDefinitionId" ON "FieldHistories" ("FieldDefinitionId");
|
||||
|
||||
@@ -811,9 +829,13 @@ CREATE INDEX "IX_FieldHistories_ItemId" ON "FieldHistories" ("ItemId");
|
||||
|
||||
CREATE INDEX "IX_FieldValues_FieldDefinitionId" ON "FieldValues" ("FieldDefinitionId");
|
||||
|
||||
CREATE INDEX "IX_FieldValues_FieldKey" ON "FieldValues" ("FieldKey");
|
||||
|
||||
CREATE INDEX "IX_FieldValues_ItemId" ON "FieldValues" ("ItemId");
|
||||
|
||||
CREATE INDEX "IX_FieldValues_ItemId_FieldDefinitionId_ValueIndex" ON "FieldValues" ("ItemId", "FieldDefinitionId", "ValueIndex");
|
||||
CREATE INDEX "IX_FieldValues_ItemId_FieldDefinitionId_Weight" ON "FieldValues" ("ItemId", "FieldDefinitionId", "Weight");
|
||||
|
||||
CREATE INDEX "IX_FieldValues_ItemId_FieldKey" ON "FieldValues" ("ItemId", "FieldKey");
|
||||
|
||||
CREATE INDEX "IX_Folders_ParentFolderId" ON "Folders" ("ParentFolderId");
|
||||
|
||||
@@ -821,27 +843,15 @@ CREATE INDEX "IX_Items_FolderId" ON "Items" ("FolderId");
|
||||
|
||||
CREATE INDEX "IX_Items_LogoId" ON "Items" ("LogoId");
|
||||
|
||||
CREATE INDEX "IX_ItemTags_ItemId" ON "ItemTags" ("ItemId");
|
||||
|
||||
CREATE UNIQUE INDEX "IX_ItemTags_ItemId_TagId" ON "ItemTags" ("ItemId", "TagId");
|
||||
|
||||
CREATE INDEX "IX_ItemTags_TagId" ON "ItemTags" ("TagId");
|
||||
|
||||
CREATE UNIQUE INDEX "IX_Logos_Source" ON "Logos" ("Source");
|
||||
|
||||
|
||||
-- Login fields
|
||||
INSERT INTO FieldDefinitions (Id, FieldKey, EntityType, FieldType, Label, IsMultiValue, DefaultVisibility, EnableHistory, DisplayOrder, ApplicableToTypes, CreatedAt, UpdatedAt, IsDeleted)
|
||||
VALUES
|
||||
(lower(hex(randomblob(16))), 'login.username', 'Item', 'Text', 'Username', 0, 'Visible', 1, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'login.password', 'Item', 'Password', 'Password', 0, 'Hidden', 1, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'login.notes', 'Item', 'Text', 'Notes', 0, 'Collapsed', 0, 0, NULL, datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'login.url', 'Item', 'URL', 'Website URLs', 1, 'Visible', 0, 0, '["Login"]', datetime('now'), datetime('now'), 0);
|
||||
|
||||
-- Alias fields
|
||||
INSERT INTO FieldDefinitions (Id, FieldKey, EntityType, FieldType, Label, IsMultiValue, DefaultVisibility, EnableHistory, DisplayOrder, ApplicableToTypes, CreatedAt, UpdatedAt, IsDeleted)
|
||||
VALUES
|
||||
(lower(hex(randomblob(16))), 'alias.email', 'Item', 'Email', 'Alias Email', 0, 'Visible', 1, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'alias.first_name', 'Item', 'Text', 'First Name', 0, 'Visible', 0, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'alias.last_name', 'Item', 'Text', 'Last Name', 0, 'Visible', 0, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'alias.nickname', 'Item', 'Text', 'Nickname', 0, 'Visible', 0, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'alias.gender', 'Item', 'Text', 'Gender', 0, 'Visible', 0, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'alias.birthdate', 'Item', 'Date', 'Birth Date', 0, 'Visible', 0, 0, '["Login"]', datetime('now'), datetime('now'), 0);
|
||||
|
||||
CREATE INDEX "IX_Tags_Name" ON "Tags" ("Name");
|
||||
|
||||
|
||||
INSERT INTO Items (Id, Name, ItemType, LogoId, FolderId, CreatedAt, UpdatedAt, IsDeleted)
|
||||
@@ -891,13 +901,14 @@ CREATE UNIQUE INDEX "IX_Logos_Source" ON "Logos" ("Source");
|
||||
|
||||
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'login.url' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'login.url' AS FieldKey,
|
||||
s.Url AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
s.UpdatedAt AS CreatedAt,
|
||||
s.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
@@ -907,13 +918,14 @@ CREATE UNIQUE INDEX "IX_Logos_Source" ON "Logos" ("Source");
|
||||
|
||||
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'login.username' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'login.username' AS FieldKey,
|
||||
c.Username AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
c.UpdatedAt AS CreatedAt,
|
||||
c.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
@@ -922,13 +934,14 @@ CREATE UNIQUE INDEX "IX_Logos_Source" ON "Logos" ("Source");
|
||||
|
||||
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'login.notes' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'login.notes' AS FieldKey,
|
||||
c.Notes AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
c.UpdatedAt AS CreatedAt,
|
||||
c.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
@@ -937,130 +950,121 @@ CREATE UNIQUE INDEX "IX_Logos_Source" ON "Logos" ("Source");
|
||||
|
||||
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
p.CredentialId AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'login.password' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'login.password' AS FieldKey,
|
||||
p.Value AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
p.UpdatedAt AS CreatedAt,
|
||||
p.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Passwords p
|
||||
INNER JOIN (
|
||||
SELECT CredentialId, MAX(UpdatedAt) AS MaxUpdated
|
||||
SELECT CredentialId, MAX(UpdatedAt) AS MaxUpdated, MAX(Id) AS MaxId
|
||||
FROM Passwords
|
||||
WHERE IsDeleted = 0
|
||||
GROUP BY CredentialId
|
||||
) pm ON p.CredentialId = pm.CredentialId AND p.UpdatedAt = pm.MaxUpdated;
|
||||
) pm ON p.CredentialId = pm.CredentialId AND p.UpdatedAt = pm.MaxUpdated AND p.Id = pm.MaxId
|
||||
WHERE p.IsDeleted = 0;
|
||||
|
||||
|
||||
|
||||
INSERT INTO FieldHistories (Id, ItemId, FieldDefinitionId, ValueSnapshot, ChangedAt, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
p.CredentialId AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'login.password' LIMIT 1) AS FieldDefinitionId,
|
||||
'{"values":["' || p.Value || '"]}' AS ValueSnapshot,
|
||||
p.UpdatedAt AS ChangedAt,
|
||||
p.CreatedAt AS CreatedAt,
|
||||
p.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Passwords p
|
||||
WHERE p.Id NOT IN (
|
||||
SELECT p2.Id FROM Passwords p2
|
||||
INNER JOIN (
|
||||
SELECT CredentialId, MAX(UpdatedAt) AS MaxUpdated
|
||||
FROM Passwords
|
||||
GROUP BY CredentialId
|
||||
) pm ON p2.CredentialId = pm.CredentialId AND p2.UpdatedAt = pm.MaxUpdated
|
||||
);
|
||||
|
||||
|
||||
|
||||
-- Migrate Alias.Email
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'alias.email' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'alias.email' AS FieldKey,
|
||||
a.Email AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
a.UpdatedAt AS CreatedAt,
|
||||
a.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Credentials c
|
||||
INNER JOIN Aliases a ON a.Id = c.AliasId
|
||||
WHERE a.Email IS NOT NULL AND a.Email != '';
|
||||
|
||||
|
||||
-- Migrate Alias.FirstName
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'alias.first_name' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'alias.first_name' AS FieldKey,
|
||||
a.FirstName AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
a.UpdatedAt AS CreatedAt,
|
||||
a.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Credentials c
|
||||
INNER JOIN Aliases a ON a.Id = c.AliasId
|
||||
WHERE a.FirstName IS NOT NULL AND a.FirstName != '';
|
||||
|
||||
|
||||
-- Migrate Alias.LastName
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'alias.last_name' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'alias.last_name' AS FieldKey,
|
||||
a.LastName AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
a.UpdatedAt AS CreatedAt,
|
||||
a.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Credentials c
|
||||
INNER JOIN Aliases a ON a.Id = c.AliasId
|
||||
WHERE a.LastName IS NOT NULL AND a.LastName != '';
|
||||
|
||||
|
||||
-- Migrate Alias.NickName
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'alias.nickname' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'alias.nickname' AS FieldKey,
|
||||
a.NickName AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
a.UpdatedAt AS CreatedAt,
|
||||
a.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Credentials c
|
||||
INNER JOIN Aliases a ON a.Id = c.AliasId
|
||||
WHERE a.NickName IS NOT NULL AND a.NickName != '';
|
||||
|
||||
|
||||
-- Migrate Alias.Gender
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'alias.gender' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'alias.gender' AS FieldKey,
|
||||
a.Gender AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
a.UpdatedAt AS CreatedAt,
|
||||
a.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Credentials c
|
||||
INNER JOIN Aliases a ON a.Id = c.AliasId
|
||||
WHERE a.Gender IS NOT NULL AND a.Gender != '';
|
||||
|
||||
|
||||
-- Migrate Alias.BirthDate
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'alias.birthdate' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'alias.birthdate' AS FieldKey,
|
||||
a.BirthDate AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
a.UpdatedAt AS CreatedAt,
|
||||
a.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
@@ -1160,95 +1164,7 @@ CREATE INDEX "IX_TotpCodes_ItemId" ON "TotpCodes" ("ItemId");
|
||||
COMMIT;
|
||||
|
||||
INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion")
|
||||
VALUES ('20251126211441_1.7.0-FieldBasedDataModelUpdate', '9.0.4');
|
||||
|
||||
BEGIN TRANSACTION;
|
||||
ALTER TABLE "Folders" RENAME COLUMN "DisplayOrder" TO "Weight";
|
||||
|
||||
ALTER TABLE "FieldValues" RENAME COLUMN "ValueIndex" TO "Weight";
|
||||
|
||||
DROP INDEX "IX_FieldValues_ItemId_FieldDefinitionId_ValueIndex";
|
||||
|
||||
CREATE INDEX "IX_FieldValues_ItemId_FieldDefinitionId_Weight" ON "FieldValues" ("ItemId", "FieldDefinitionId", "Weight");
|
||||
|
||||
ALTER TABLE "FieldDefinitions" RENAME COLUMN "DisplayOrder" TO "Weight";
|
||||
|
||||
ALTER TABLE "FieldDefinitions" ADD "IsHidden" INTEGER NOT NULL DEFAULT 0;
|
||||
|
||||
CREATE TABLE "ef_temp_FieldDefinitions" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_FieldDefinitions" PRIMARY KEY,
|
||||
"ApplicableToTypes" TEXT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"EnableHistory" INTEGER NOT NULL,
|
||||
"FieldKey" TEXT NULL,
|
||||
"FieldType" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL,
|
||||
"IsHidden" INTEGER NOT NULL,
|
||||
"IsMultiValue" INTEGER NOT NULL,
|
||||
"Label" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"Weight" INTEGER NOT NULL
|
||||
);
|
||||
|
||||
INSERT INTO "ef_temp_FieldDefinitions" ("Id", "ApplicableToTypes", "CreatedAt", "EnableHistory", "FieldKey", "FieldType", "IsDeleted", "IsHidden", "IsMultiValue", "Label", "UpdatedAt", "Weight")
|
||||
SELECT "Id", "ApplicableToTypes", "CreatedAt", "EnableHistory", "FieldKey", "FieldType", "IsDeleted", "IsHidden", "IsMultiValue", "Label", "UpdatedAt", "Weight"
|
||||
FROM "FieldDefinitions";
|
||||
|
||||
COMMIT;
|
||||
|
||||
PRAGMA foreign_keys = 0;
|
||||
|
||||
BEGIN TRANSACTION;
|
||||
DROP TABLE "FieldDefinitions";
|
||||
|
||||
ALTER TABLE "ef_temp_FieldDefinitions" RENAME TO "FieldDefinitions";
|
||||
|
||||
COMMIT;
|
||||
|
||||
PRAGMA foreign_keys = 1;
|
||||
|
||||
BEGIN TRANSACTION;
|
||||
CREATE INDEX "IX_FieldDefinitions_FieldKey" ON "FieldDefinitions" ("FieldKey");
|
||||
|
||||
COMMIT;
|
||||
|
||||
INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion")
|
||||
VALUES ('20251126221717_1.7.1-RenameColumns', '9.0.4');
|
||||
|
||||
BEGIN TRANSACTION;
|
||||
CREATE TABLE "Tags" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_Tags" PRIMARY KEY,
|
||||
"Name" TEXT NOT NULL,
|
||||
"Color" TEXT NULL,
|
||||
"DisplayOrder" INTEGER NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE "ItemTags" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_ItemTags" PRIMARY KEY,
|
||||
"ItemId" TEXT NOT NULL,
|
||||
"TagId" TEXT NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL,
|
||||
CONSTRAINT "FK_ItemTags_Items_ItemId" FOREIGN KEY ("ItemId") REFERENCES "Items" ("Id") ON DELETE CASCADE,
|
||||
CONSTRAINT "FK_ItemTags_Tags_TagId" FOREIGN KEY ("TagId") REFERENCES "Tags" ("Id") ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE INDEX "IX_ItemTags_ItemId" ON "ItemTags" ("ItemId");
|
||||
|
||||
CREATE UNIQUE INDEX "IX_ItemTags_ItemId_TagId" ON "ItemTags" ("ItemId", "TagId");
|
||||
|
||||
CREATE INDEX "IX_ItemTags_TagId" ON "ItemTags" ("TagId");
|
||||
|
||||
CREATE INDEX "IX_Tags_Name" ON "Tags" ("Name");
|
||||
|
||||
INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion")
|
||||
VALUES ('20251202211204_1.7.2-AddTagTables', '9.0.4');
|
||||
|
||||
COMMIT;
|
||||
VALUES ('20251203162345_1.7.0-FieldBasedDataModelUpdate', '9.0.4');
|
||||
`;
|
||||
var MIGRATION_SCRIPTS = {
|
||||
1: `\uFEFFBEGIN TRANSACTION;
|
||||
@@ -1878,14 +1794,12 @@ CREATE INDEX IF NOT EXISTS "IX_Attachments_ItemId" ON "Attachments" ("ItemId");
|
||||
|
||||
CREATE TABLE "FieldDefinitions" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_FieldDefinitions" PRIMARY KEY,
|
||||
"FieldKey" TEXT NULL,
|
||||
"EntityType" TEXT NULL,
|
||||
"FieldType" TEXT NOT NULL,
|
||||
"Label" TEXT NOT NULL,
|
||||
"IsMultiValue" INTEGER NOT NULL,
|
||||
"DefaultVisibility" TEXT NULL,
|
||||
"IsHidden" INTEGER NOT NULL,
|
||||
"EnableHistory" INTEGER NOT NULL,
|
||||
"DisplayOrder" INTEGER NOT NULL,
|
||||
"Weight" INTEGER NOT NULL,
|
||||
"ApplicableToTypes" TEXT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
@@ -1896,7 +1810,7 @@ CREATE TABLE "Folders" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_Folders" PRIMARY KEY,
|
||||
"Name" TEXT NOT NULL,
|
||||
"ParentFolderId" TEXT NULL,
|
||||
"DisplayOrder" INTEGER NOT NULL,
|
||||
"Weight" INTEGER NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL,
|
||||
@@ -1914,6 +1828,16 @@ CREATE TABLE "Logos" (
|
||||
"IsDeleted" INTEGER NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE "Tags" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_Tags" PRIMARY KEY,
|
||||
"Name" TEXT NOT NULL,
|
||||
"Color" TEXT NULL,
|
||||
"DisplayOrder" INTEGER NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE "Items" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_Items" PRIMARY KEY,
|
||||
"Name" TEXT NULL,
|
||||
@@ -1943,9 +1867,10 @@ CREATE TABLE "FieldHistories" (
|
||||
CREATE TABLE "FieldValues" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_FieldValues" PRIMARY KEY,
|
||||
"ItemId" TEXT NOT NULL,
|
||||
"FieldDefinitionId" TEXT NOT NULL,
|
||||
"FieldDefinitionId" TEXT NULL,
|
||||
"FieldKey" TEXT NULL,
|
||||
"Value" TEXT NULL,
|
||||
"ValueIndex" INTEGER NOT NULL,
|
||||
"Weight" INTEGER NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL,
|
||||
@@ -1953,7 +1878,16 @@ CREATE TABLE "FieldValues" (
|
||||
CONSTRAINT "FK_FieldValues_Items_ItemId" FOREIGN KEY ("ItemId") REFERENCES "Items" ("Id") ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE INDEX "IX_FieldDefinitions_FieldKey" ON "FieldDefinitions" ("FieldKey");
|
||||
CREATE TABLE "ItemTags" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_ItemTags" PRIMARY KEY,
|
||||
"ItemId" TEXT NOT NULL,
|
||||
"TagId" TEXT NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL,
|
||||
CONSTRAINT "FK_ItemTags_Items_ItemId" FOREIGN KEY ("ItemId") REFERENCES "Items" ("Id") ON DELETE CASCADE,
|
||||
CONSTRAINT "FK_ItemTags_Tags_TagId" FOREIGN KEY ("TagId") REFERENCES "Tags" ("Id") ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE INDEX "IX_FieldHistories_FieldDefinitionId" ON "FieldHistories" ("FieldDefinitionId");
|
||||
|
||||
@@ -1961,9 +1895,13 @@ CREATE INDEX "IX_FieldHistories_ItemId" ON "FieldHistories" ("ItemId");
|
||||
|
||||
CREATE INDEX "IX_FieldValues_FieldDefinitionId" ON "FieldValues" ("FieldDefinitionId");
|
||||
|
||||
CREATE INDEX "IX_FieldValues_FieldKey" ON "FieldValues" ("FieldKey");
|
||||
|
||||
CREATE INDEX "IX_FieldValues_ItemId" ON "FieldValues" ("ItemId");
|
||||
|
||||
CREATE INDEX "IX_FieldValues_ItemId_FieldDefinitionId_ValueIndex" ON "FieldValues" ("ItemId", "FieldDefinitionId", "ValueIndex");
|
||||
CREATE INDEX "IX_FieldValues_ItemId_FieldDefinitionId_Weight" ON "FieldValues" ("ItemId", "FieldDefinitionId", "Weight");
|
||||
|
||||
CREATE INDEX "IX_FieldValues_ItemId_FieldKey" ON "FieldValues" ("ItemId", "FieldKey");
|
||||
|
||||
CREATE INDEX "IX_Folders_ParentFolderId" ON "Folders" ("ParentFolderId");
|
||||
|
||||
@@ -1971,27 +1909,15 @@ CREATE INDEX "IX_Items_FolderId" ON "Items" ("FolderId");
|
||||
|
||||
CREATE INDEX "IX_Items_LogoId" ON "Items" ("LogoId");
|
||||
|
||||
CREATE INDEX "IX_ItemTags_ItemId" ON "ItemTags" ("ItemId");
|
||||
|
||||
CREATE UNIQUE INDEX "IX_ItemTags_ItemId_TagId" ON "ItemTags" ("ItemId", "TagId");
|
||||
|
||||
CREATE INDEX "IX_ItemTags_TagId" ON "ItemTags" ("TagId");
|
||||
|
||||
CREATE UNIQUE INDEX "IX_Logos_Source" ON "Logos" ("Source");
|
||||
|
||||
|
||||
-- Login fields
|
||||
INSERT INTO FieldDefinitions (Id, FieldKey, EntityType, FieldType, Label, IsMultiValue, DefaultVisibility, EnableHistory, DisplayOrder, ApplicableToTypes, CreatedAt, UpdatedAt, IsDeleted)
|
||||
VALUES
|
||||
(lower(hex(randomblob(16))), 'login.username', 'Item', 'Text', 'Username', 0, 'Visible', 1, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'login.password', 'Item', 'Password', 'Password', 0, 'Hidden', 1, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'login.notes', 'Item', 'Text', 'Notes', 0, 'Collapsed', 0, 0, NULL, datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'login.url', 'Item', 'URL', 'Website URLs', 1, 'Visible', 0, 0, '["Login"]', datetime('now'), datetime('now'), 0);
|
||||
|
||||
-- Alias fields
|
||||
INSERT INTO FieldDefinitions (Id, FieldKey, EntityType, FieldType, Label, IsMultiValue, DefaultVisibility, EnableHistory, DisplayOrder, ApplicableToTypes, CreatedAt, UpdatedAt, IsDeleted)
|
||||
VALUES
|
||||
(lower(hex(randomblob(16))), 'alias.email', 'Item', 'Email', 'Alias Email', 0, 'Visible', 1, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'alias.first_name', 'Item', 'Text', 'First Name', 0, 'Visible', 0, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'alias.last_name', 'Item', 'Text', 'Last Name', 0, 'Visible', 0, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'alias.nickname', 'Item', 'Text', 'Nickname', 0, 'Visible', 0, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'alias.gender', 'Item', 'Text', 'Gender', 0, 'Visible', 0, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'alias.birthdate', 'Item', 'Date', 'Birth Date', 0, 'Visible', 0, 0, '["Login"]', datetime('now'), datetime('now'), 0);
|
||||
|
||||
CREATE INDEX "IX_Tags_Name" ON "Tags" ("Name");
|
||||
|
||||
|
||||
INSERT INTO Items (Id, Name, ItemType, LogoId, FolderId, CreatedAt, UpdatedAt, IsDeleted)
|
||||
@@ -2041,13 +1967,14 @@ CREATE UNIQUE INDEX "IX_Logos_Source" ON "Logos" ("Source");
|
||||
|
||||
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'login.url' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'login.url' AS FieldKey,
|
||||
s.Url AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
s.UpdatedAt AS CreatedAt,
|
||||
s.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
@@ -2057,13 +1984,14 @@ CREATE UNIQUE INDEX "IX_Logos_Source" ON "Logos" ("Source");
|
||||
|
||||
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'login.username' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'login.username' AS FieldKey,
|
||||
c.Username AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
c.UpdatedAt AS CreatedAt,
|
||||
c.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
@@ -2072,13 +2000,14 @@ CREATE UNIQUE INDEX "IX_Logos_Source" ON "Logos" ("Source");
|
||||
|
||||
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'login.notes' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'login.notes' AS FieldKey,
|
||||
c.Notes AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
c.UpdatedAt AS CreatedAt,
|
||||
c.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
@@ -2087,130 +2016,121 @@ CREATE UNIQUE INDEX "IX_Logos_Source" ON "Logos" ("Source");
|
||||
|
||||
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
p.CredentialId AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'login.password' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'login.password' AS FieldKey,
|
||||
p.Value AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
p.UpdatedAt AS CreatedAt,
|
||||
p.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Passwords p
|
||||
INNER JOIN (
|
||||
SELECT CredentialId, MAX(UpdatedAt) AS MaxUpdated
|
||||
SELECT CredentialId, MAX(UpdatedAt) AS MaxUpdated, MAX(Id) AS MaxId
|
||||
FROM Passwords
|
||||
WHERE IsDeleted = 0
|
||||
GROUP BY CredentialId
|
||||
) pm ON p.CredentialId = pm.CredentialId AND p.UpdatedAt = pm.MaxUpdated;
|
||||
) pm ON p.CredentialId = pm.CredentialId AND p.UpdatedAt = pm.MaxUpdated AND p.Id = pm.MaxId
|
||||
WHERE p.IsDeleted = 0;
|
||||
|
||||
|
||||
|
||||
INSERT INTO FieldHistories (Id, ItemId, FieldDefinitionId, ValueSnapshot, ChangedAt, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
p.CredentialId AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'login.password' LIMIT 1) AS FieldDefinitionId,
|
||||
'{"values":["' || p.Value || '"]}' AS ValueSnapshot,
|
||||
p.UpdatedAt AS ChangedAt,
|
||||
p.CreatedAt AS CreatedAt,
|
||||
p.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Passwords p
|
||||
WHERE p.Id NOT IN (
|
||||
SELECT p2.Id FROM Passwords p2
|
||||
INNER JOIN (
|
||||
SELECT CredentialId, MAX(UpdatedAt) AS MaxUpdated
|
||||
FROM Passwords
|
||||
GROUP BY CredentialId
|
||||
) pm ON p2.CredentialId = pm.CredentialId AND p2.UpdatedAt = pm.MaxUpdated
|
||||
);
|
||||
|
||||
|
||||
|
||||
-- Migrate Alias.Email
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'alias.email' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'alias.email' AS FieldKey,
|
||||
a.Email AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
a.UpdatedAt AS CreatedAt,
|
||||
a.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Credentials c
|
||||
INNER JOIN Aliases a ON a.Id = c.AliasId
|
||||
WHERE a.Email IS NOT NULL AND a.Email != '';
|
||||
|
||||
|
||||
-- Migrate Alias.FirstName
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'alias.first_name' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'alias.first_name' AS FieldKey,
|
||||
a.FirstName AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
a.UpdatedAt AS CreatedAt,
|
||||
a.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Credentials c
|
||||
INNER JOIN Aliases a ON a.Id = c.AliasId
|
||||
WHERE a.FirstName IS NOT NULL AND a.FirstName != '';
|
||||
|
||||
|
||||
-- Migrate Alias.LastName
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'alias.last_name' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'alias.last_name' AS FieldKey,
|
||||
a.LastName AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
a.UpdatedAt AS CreatedAt,
|
||||
a.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Credentials c
|
||||
INNER JOIN Aliases a ON a.Id = c.AliasId
|
||||
WHERE a.LastName IS NOT NULL AND a.LastName != '';
|
||||
|
||||
|
||||
-- Migrate Alias.NickName
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'alias.nickname' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'alias.nickname' AS FieldKey,
|
||||
a.NickName AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
a.UpdatedAt AS CreatedAt,
|
||||
a.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Credentials c
|
||||
INNER JOIN Aliases a ON a.Id = c.AliasId
|
||||
WHERE a.NickName IS NOT NULL AND a.NickName != '';
|
||||
|
||||
|
||||
-- Migrate Alias.Gender
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'alias.gender' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'alias.gender' AS FieldKey,
|
||||
a.Gender AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
a.UpdatedAt AS CreatedAt,
|
||||
a.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Credentials c
|
||||
INNER JOIN Aliases a ON a.Id = c.AliasId
|
||||
WHERE a.Gender IS NOT NULL AND a.Gender != '';
|
||||
|
||||
|
||||
-- Migrate Alias.BirthDate
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'alias.birthdate' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'alias.birthdate' AS FieldKey,
|
||||
a.BirthDate AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
a.UpdatedAt AS CreatedAt,
|
||||
a.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
@@ -2310,93 +2230,7 @@ CREATE INDEX "IX_TotpCodes_ItemId" ON "TotpCodes" ("ItemId");
|
||||
COMMIT;
|
||||
|
||||
INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion")
|
||||
VALUES ('20251126211441_1.7.0-FieldBasedDataModelUpdate', '9.0.4');`,
|
||||
12: `\uFEFFBEGIN TRANSACTION;
|
||||
ALTER TABLE "Folders" RENAME COLUMN "DisplayOrder" TO "Weight";
|
||||
|
||||
ALTER TABLE "FieldValues" RENAME COLUMN "ValueIndex" TO "Weight";
|
||||
|
||||
DROP INDEX "IX_FieldValues_ItemId_FieldDefinitionId_ValueIndex";
|
||||
|
||||
CREATE INDEX "IX_FieldValues_ItemId_FieldDefinitionId_Weight" ON "FieldValues" ("ItemId", "FieldDefinitionId", "Weight");
|
||||
|
||||
ALTER TABLE "FieldDefinitions" RENAME COLUMN "DisplayOrder" TO "Weight";
|
||||
|
||||
ALTER TABLE "FieldDefinitions" ADD "IsHidden" INTEGER NOT NULL DEFAULT 0;
|
||||
|
||||
CREATE TABLE "ef_temp_FieldDefinitions" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_FieldDefinitions" PRIMARY KEY,
|
||||
"ApplicableToTypes" TEXT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"EnableHistory" INTEGER NOT NULL,
|
||||
"FieldKey" TEXT NULL,
|
||||
"FieldType" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL,
|
||||
"IsHidden" INTEGER NOT NULL,
|
||||
"IsMultiValue" INTEGER NOT NULL,
|
||||
"Label" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"Weight" INTEGER NOT NULL
|
||||
);
|
||||
|
||||
INSERT INTO "ef_temp_FieldDefinitions" ("Id", "ApplicableToTypes", "CreatedAt", "EnableHistory", "FieldKey", "FieldType", "IsDeleted", "IsHidden", "IsMultiValue", "Label", "UpdatedAt", "Weight")
|
||||
SELECT "Id", "ApplicableToTypes", "CreatedAt", "EnableHistory", "FieldKey", "FieldType", "IsDeleted", "IsHidden", "IsMultiValue", "Label", "UpdatedAt", "Weight"
|
||||
FROM "FieldDefinitions";
|
||||
|
||||
COMMIT;
|
||||
|
||||
PRAGMA foreign_keys = 0;
|
||||
|
||||
BEGIN TRANSACTION;
|
||||
DROP TABLE "FieldDefinitions";
|
||||
|
||||
ALTER TABLE "ef_temp_FieldDefinitions" RENAME TO "FieldDefinitions";
|
||||
|
||||
COMMIT;
|
||||
|
||||
PRAGMA foreign_keys = 1;
|
||||
|
||||
BEGIN TRANSACTION;
|
||||
CREATE INDEX "IX_FieldDefinitions_FieldKey" ON "FieldDefinitions" ("FieldKey");
|
||||
|
||||
COMMIT;
|
||||
|
||||
INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion")
|
||||
VALUES ('20251126221717_1.7.1-RenameColumns', '9.0.4');`,
|
||||
13: `\uFEFFBEGIN TRANSACTION;
|
||||
CREATE TABLE "Tags" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_Tags" PRIMARY KEY,
|
||||
"Name" TEXT NOT NULL,
|
||||
"Color" TEXT NULL,
|
||||
"DisplayOrder" INTEGER NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE "ItemTags" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_ItemTags" PRIMARY KEY,
|
||||
"ItemId" TEXT NOT NULL,
|
||||
"TagId" TEXT NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL,
|
||||
CONSTRAINT "FK_ItemTags_Items_ItemId" FOREIGN KEY ("ItemId") REFERENCES "Items" ("Id") ON DELETE CASCADE,
|
||||
CONSTRAINT "FK_ItemTags_Tags_TagId" FOREIGN KEY ("TagId") REFERENCES "Tags" ("Id") ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE INDEX "IX_ItemTags_ItemId" ON "ItemTags" ("ItemId");
|
||||
|
||||
CREATE UNIQUE INDEX "IX_ItemTags_ItemId_TagId" ON "ItemTags" ("ItemId", "TagId");
|
||||
|
||||
CREATE INDEX "IX_ItemTags_TagId" ON "ItemTags" ("TagId");
|
||||
|
||||
CREATE INDEX "IX_Tags_Name" ON "Tags" ("Name");
|
||||
|
||||
INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion")
|
||||
VALUES ('20251202211204_1.7.2-AddTagTables', '9.0.4');
|
||||
|
||||
COMMIT;`
|
||||
VALUES ('20251203162345_1.7.0-FieldBasedDataModelUpdate', '9.0.4');`
|
||||
};
|
||||
|
||||
// src/sql/VaultVersions.ts
|
||||
@@ -2484,20 +2318,6 @@ var VAULT_VERSIONS = [
|
||||
description: "Update to Field-Based Data Model",
|
||||
releaseVersion: "0.26.0",
|
||||
compatibleUpToVersion: "0.26.0"
|
||||
},
|
||||
{
|
||||
revision: 13,
|
||||
version: "1.7.1",
|
||||
description: "Rename Columns",
|
||||
releaseVersion: "0.26.0",
|
||||
compatibleUpToVersion: "0.26.0"
|
||||
},
|
||||
{
|
||||
revision: 14,
|
||||
version: "1.8.0",
|
||||
description: "Add Tags Tables",
|
||||
releaseVersion: "0.27.0",
|
||||
compatibleUpToVersion: "0.27.0"
|
||||
}
|
||||
];
|
||||
|
||||
|
||||
@@ -696,14 +696,12 @@ CREATE INDEX IF NOT EXISTS "IX_Attachments_ItemId" ON "Attachments" ("ItemId");
|
||||
|
||||
CREATE TABLE "FieldDefinitions" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_FieldDefinitions" PRIMARY KEY,
|
||||
"FieldKey" TEXT NULL,
|
||||
"EntityType" TEXT NULL,
|
||||
"FieldType" TEXT NOT NULL,
|
||||
"Label" TEXT NOT NULL,
|
||||
"IsMultiValue" INTEGER NOT NULL,
|
||||
"DefaultVisibility" TEXT NULL,
|
||||
"IsHidden" INTEGER NOT NULL,
|
||||
"EnableHistory" INTEGER NOT NULL,
|
||||
"DisplayOrder" INTEGER NOT NULL,
|
||||
"Weight" INTEGER NOT NULL,
|
||||
"ApplicableToTypes" TEXT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
@@ -714,7 +712,7 @@ CREATE TABLE "Folders" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_Folders" PRIMARY KEY,
|
||||
"Name" TEXT NOT NULL,
|
||||
"ParentFolderId" TEXT NULL,
|
||||
"DisplayOrder" INTEGER NOT NULL,
|
||||
"Weight" INTEGER NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL,
|
||||
@@ -732,6 +730,16 @@ CREATE TABLE "Logos" (
|
||||
"IsDeleted" INTEGER NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE "Tags" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_Tags" PRIMARY KEY,
|
||||
"Name" TEXT NOT NULL,
|
||||
"Color" TEXT NULL,
|
||||
"DisplayOrder" INTEGER NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE "Items" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_Items" PRIMARY KEY,
|
||||
"Name" TEXT NULL,
|
||||
@@ -761,9 +769,10 @@ CREATE TABLE "FieldHistories" (
|
||||
CREATE TABLE "FieldValues" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_FieldValues" PRIMARY KEY,
|
||||
"ItemId" TEXT NOT NULL,
|
||||
"FieldDefinitionId" TEXT NOT NULL,
|
||||
"FieldDefinitionId" TEXT NULL,
|
||||
"FieldKey" TEXT NULL,
|
||||
"Value" TEXT NULL,
|
||||
"ValueIndex" INTEGER NOT NULL,
|
||||
"Weight" INTEGER NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL,
|
||||
@@ -771,7 +780,16 @@ CREATE TABLE "FieldValues" (
|
||||
CONSTRAINT "FK_FieldValues_Items_ItemId" FOREIGN KEY ("ItemId") REFERENCES "Items" ("Id") ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE INDEX "IX_FieldDefinitions_FieldKey" ON "FieldDefinitions" ("FieldKey");
|
||||
CREATE TABLE "ItemTags" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_ItemTags" PRIMARY KEY,
|
||||
"ItemId" TEXT NOT NULL,
|
||||
"TagId" TEXT NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL,
|
||||
CONSTRAINT "FK_ItemTags_Items_ItemId" FOREIGN KEY ("ItemId") REFERENCES "Items" ("Id") ON DELETE CASCADE,
|
||||
CONSTRAINT "FK_ItemTags_Tags_TagId" FOREIGN KEY ("TagId") REFERENCES "Tags" ("Id") ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE INDEX "IX_FieldHistories_FieldDefinitionId" ON "FieldHistories" ("FieldDefinitionId");
|
||||
|
||||
@@ -779,9 +797,13 @@ CREATE INDEX "IX_FieldHistories_ItemId" ON "FieldHistories" ("ItemId");
|
||||
|
||||
CREATE INDEX "IX_FieldValues_FieldDefinitionId" ON "FieldValues" ("FieldDefinitionId");
|
||||
|
||||
CREATE INDEX "IX_FieldValues_FieldKey" ON "FieldValues" ("FieldKey");
|
||||
|
||||
CREATE INDEX "IX_FieldValues_ItemId" ON "FieldValues" ("ItemId");
|
||||
|
||||
CREATE INDEX "IX_FieldValues_ItemId_FieldDefinitionId_ValueIndex" ON "FieldValues" ("ItemId", "FieldDefinitionId", "ValueIndex");
|
||||
CREATE INDEX "IX_FieldValues_ItemId_FieldDefinitionId_Weight" ON "FieldValues" ("ItemId", "FieldDefinitionId", "Weight");
|
||||
|
||||
CREATE INDEX "IX_FieldValues_ItemId_FieldKey" ON "FieldValues" ("ItemId", "FieldKey");
|
||||
|
||||
CREATE INDEX "IX_Folders_ParentFolderId" ON "Folders" ("ParentFolderId");
|
||||
|
||||
@@ -789,27 +811,15 @@ CREATE INDEX "IX_Items_FolderId" ON "Items" ("FolderId");
|
||||
|
||||
CREATE INDEX "IX_Items_LogoId" ON "Items" ("LogoId");
|
||||
|
||||
CREATE INDEX "IX_ItemTags_ItemId" ON "ItemTags" ("ItemId");
|
||||
|
||||
CREATE UNIQUE INDEX "IX_ItemTags_ItemId_TagId" ON "ItemTags" ("ItemId", "TagId");
|
||||
|
||||
CREATE INDEX "IX_ItemTags_TagId" ON "ItemTags" ("TagId");
|
||||
|
||||
CREATE UNIQUE INDEX "IX_Logos_Source" ON "Logos" ("Source");
|
||||
|
||||
|
||||
-- Login fields
|
||||
INSERT INTO FieldDefinitions (Id, FieldKey, EntityType, FieldType, Label, IsMultiValue, DefaultVisibility, EnableHistory, DisplayOrder, ApplicableToTypes, CreatedAt, UpdatedAt, IsDeleted)
|
||||
VALUES
|
||||
(lower(hex(randomblob(16))), 'login.username', 'Item', 'Text', 'Username', 0, 'Visible', 1, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'login.password', 'Item', 'Password', 'Password', 0, 'Hidden', 1, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'login.notes', 'Item', 'Text', 'Notes', 0, 'Collapsed', 0, 0, NULL, datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'login.url', 'Item', 'URL', 'Website URLs', 1, 'Visible', 0, 0, '["Login"]', datetime('now'), datetime('now'), 0);
|
||||
|
||||
-- Alias fields
|
||||
INSERT INTO FieldDefinitions (Id, FieldKey, EntityType, FieldType, Label, IsMultiValue, DefaultVisibility, EnableHistory, DisplayOrder, ApplicableToTypes, CreatedAt, UpdatedAt, IsDeleted)
|
||||
VALUES
|
||||
(lower(hex(randomblob(16))), 'alias.email', 'Item', 'Email', 'Alias Email', 0, 'Visible', 1, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'alias.first_name', 'Item', 'Text', 'First Name', 0, 'Visible', 0, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'alias.last_name', 'Item', 'Text', 'Last Name', 0, 'Visible', 0, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'alias.nickname', 'Item', 'Text', 'Nickname', 0, 'Visible', 0, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'alias.gender', 'Item', 'Text', 'Gender', 0, 'Visible', 0, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'alias.birthdate', 'Item', 'Date', 'Birth Date', 0, 'Visible', 0, 0, '["Login"]', datetime('now'), datetime('now'), 0);
|
||||
|
||||
CREATE INDEX "IX_Tags_Name" ON "Tags" ("Name");
|
||||
|
||||
|
||||
INSERT INTO Items (Id, Name, ItemType, LogoId, FolderId, CreatedAt, UpdatedAt, IsDeleted)
|
||||
@@ -859,13 +869,14 @@ CREATE UNIQUE INDEX "IX_Logos_Source" ON "Logos" ("Source");
|
||||
|
||||
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'login.url' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'login.url' AS FieldKey,
|
||||
s.Url AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
s.UpdatedAt AS CreatedAt,
|
||||
s.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
@@ -875,13 +886,14 @@ CREATE UNIQUE INDEX "IX_Logos_Source" ON "Logos" ("Source");
|
||||
|
||||
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'login.username' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'login.username' AS FieldKey,
|
||||
c.Username AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
c.UpdatedAt AS CreatedAt,
|
||||
c.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
@@ -890,13 +902,14 @@ CREATE UNIQUE INDEX "IX_Logos_Source" ON "Logos" ("Source");
|
||||
|
||||
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'login.notes' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'login.notes' AS FieldKey,
|
||||
c.Notes AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
c.UpdatedAt AS CreatedAt,
|
||||
c.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
@@ -905,130 +918,121 @@ CREATE UNIQUE INDEX "IX_Logos_Source" ON "Logos" ("Source");
|
||||
|
||||
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
p.CredentialId AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'login.password' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'login.password' AS FieldKey,
|
||||
p.Value AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
p.UpdatedAt AS CreatedAt,
|
||||
p.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Passwords p
|
||||
INNER JOIN (
|
||||
SELECT CredentialId, MAX(UpdatedAt) AS MaxUpdated
|
||||
SELECT CredentialId, MAX(UpdatedAt) AS MaxUpdated, MAX(Id) AS MaxId
|
||||
FROM Passwords
|
||||
WHERE IsDeleted = 0
|
||||
GROUP BY CredentialId
|
||||
) pm ON p.CredentialId = pm.CredentialId AND p.UpdatedAt = pm.MaxUpdated;
|
||||
) pm ON p.CredentialId = pm.CredentialId AND p.UpdatedAt = pm.MaxUpdated AND p.Id = pm.MaxId
|
||||
WHERE p.IsDeleted = 0;
|
||||
|
||||
|
||||
|
||||
INSERT INTO FieldHistories (Id, ItemId, FieldDefinitionId, ValueSnapshot, ChangedAt, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
p.CredentialId AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'login.password' LIMIT 1) AS FieldDefinitionId,
|
||||
'{"values":["' || p.Value || '"]}' AS ValueSnapshot,
|
||||
p.UpdatedAt AS ChangedAt,
|
||||
p.CreatedAt AS CreatedAt,
|
||||
p.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Passwords p
|
||||
WHERE p.Id NOT IN (
|
||||
SELECT p2.Id FROM Passwords p2
|
||||
INNER JOIN (
|
||||
SELECT CredentialId, MAX(UpdatedAt) AS MaxUpdated
|
||||
FROM Passwords
|
||||
GROUP BY CredentialId
|
||||
) pm ON p2.CredentialId = pm.CredentialId AND p2.UpdatedAt = pm.MaxUpdated
|
||||
);
|
||||
|
||||
|
||||
|
||||
-- Migrate Alias.Email
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'alias.email' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'alias.email' AS FieldKey,
|
||||
a.Email AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
a.UpdatedAt AS CreatedAt,
|
||||
a.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Credentials c
|
||||
INNER JOIN Aliases a ON a.Id = c.AliasId
|
||||
WHERE a.Email IS NOT NULL AND a.Email != '';
|
||||
|
||||
|
||||
-- Migrate Alias.FirstName
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'alias.first_name' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'alias.first_name' AS FieldKey,
|
||||
a.FirstName AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
a.UpdatedAt AS CreatedAt,
|
||||
a.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Credentials c
|
||||
INNER JOIN Aliases a ON a.Id = c.AliasId
|
||||
WHERE a.FirstName IS NOT NULL AND a.FirstName != '';
|
||||
|
||||
|
||||
-- Migrate Alias.LastName
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'alias.last_name' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'alias.last_name' AS FieldKey,
|
||||
a.LastName AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
a.UpdatedAt AS CreatedAt,
|
||||
a.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Credentials c
|
||||
INNER JOIN Aliases a ON a.Id = c.AliasId
|
||||
WHERE a.LastName IS NOT NULL AND a.LastName != '';
|
||||
|
||||
|
||||
-- Migrate Alias.NickName
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'alias.nickname' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'alias.nickname' AS FieldKey,
|
||||
a.NickName AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
a.UpdatedAt AS CreatedAt,
|
||||
a.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Credentials c
|
||||
INNER JOIN Aliases a ON a.Id = c.AliasId
|
||||
WHERE a.NickName IS NOT NULL AND a.NickName != '';
|
||||
|
||||
|
||||
-- Migrate Alias.Gender
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'alias.gender' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'alias.gender' AS FieldKey,
|
||||
a.Gender AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
a.UpdatedAt AS CreatedAt,
|
||||
a.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Credentials c
|
||||
INNER JOIN Aliases a ON a.Id = c.AliasId
|
||||
WHERE a.Gender IS NOT NULL AND a.Gender != '';
|
||||
|
||||
|
||||
-- Migrate Alias.BirthDate
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'alias.birthdate' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'alias.birthdate' AS FieldKey,
|
||||
a.BirthDate AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
a.UpdatedAt AS CreatedAt,
|
||||
a.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
@@ -1128,95 +1132,7 @@ CREATE INDEX "IX_TotpCodes_ItemId" ON "TotpCodes" ("ItemId");
|
||||
COMMIT;
|
||||
|
||||
INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion")
|
||||
VALUES ('20251126211441_1.7.0-FieldBasedDataModelUpdate', '9.0.4');
|
||||
|
||||
BEGIN TRANSACTION;
|
||||
ALTER TABLE "Folders" RENAME COLUMN "DisplayOrder" TO "Weight";
|
||||
|
||||
ALTER TABLE "FieldValues" RENAME COLUMN "ValueIndex" TO "Weight";
|
||||
|
||||
DROP INDEX "IX_FieldValues_ItemId_FieldDefinitionId_ValueIndex";
|
||||
|
||||
CREATE INDEX "IX_FieldValues_ItemId_FieldDefinitionId_Weight" ON "FieldValues" ("ItemId", "FieldDefinitionId", "Weight");
|
||||
|
||||
ALTER TABLE "FieldDefinitions" RENAME COLUMN "DisplayOrder" TO "Weight";
|
||||
|
||||
ALTER TABLE "FieldDefinitions" ADD "IsHidden" INTEGER NOT NULL DEFAULT 0;
|
||||
|
||||
CREATE TABLE "ef_temp_FieldDefinitions" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_FieldDefinitions" PRIMARY KEY,
|
||||
"ApplicableToTypes" TEXT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"EnableHistory" INTEGER NOT NULL,
|
||||
"FieldKey" TEXT NULL,
|
||||
"FieldType" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL,
|
||||
"IsHidden" INTEGER NOT NULL,
|
||||
"IsMultiValue" INTEGER NOT NULL,
|
||||
"Label" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"Weight" INTEGER NOT NULL
|
||||
);
|
||||
|
||||
INSERT INTO "ef_temp_FieldDefinitions" ("Id", "ApplicableToTypes", "CreatedAt", "EnableHistory", "FieldKey", "FieldType", "IsDeleted", "IsHidden", "IsMultiValue", "Label", "UpdatedAt", "Weight")
|
||||
SELECT "Id", "ApplicableToTypes", "CreatedAt", "EnableHistory", "FieldKey", "FieldType", "IsDeleted", "IsHidden", "IsMultiValue", "Label", "UpdatedAt", "Weight"
|
||||
FROM "FieldDefinitions";
|
||||
|
||||
COMMIT;
|
||||
|
||||
PRAGMA foreign_keys = 0;
|
||||
|
||||
BEGIN TRANSACTION;
|
||||
DROP TABLE "FieldDefinitions";
|
||||
|
||||
ALTER TABLE "ef_temp_FieldDefinitions" RENAME TO "FieldDefinitions";
|
||||
|
||||
COMMIT;
|
||||
|
||||
PRAGMA foreign_keys = 1;
|
||||
|
||||
BEGIN TRANSACTION;
|
||||
CREATE INDEX "IX_FieldDefinitions_FieldKey" ON "FieldDefinitions" ("FieldKey");
|
||||
|
||||
COMMIT;
|
||||
|
||||
INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion")
|
||||
VALUES ('20251126221717_1.7.1-RenameColumns', '9.0.4');
|
||||
|
||||
BEGIN TRANSACTION;
|
||||
CREATE TABLE "Tags" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_Tags" PRIMARY KEY,
|
||||
"Name" TEXT NOT NULL,
|
||||
"Color" TEXT NULL,
|
||||
"DisplayOrder" INTEGER NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE "ItemTags" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_ItemTags" PRIMARY KEY,
|
||||
"ItemId" TEXT NOT NULL,
|
||||
"TagId" TEXT NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL,
|
||||
CONSTRAINT "FK_ItemTags_Items_ItemId" FOREIGN KEY ("ItemId") REFERENCES "Items" ("Id") ON DELETE CASCADE,
|
||||
CONSTRAINT "FK_ItemTags_Tags_TagId" FOREIGN KEY ("TagId") REFERENCES "Tags" ("Id") ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE INDEX "IX_ItemTags_ItemId" ON "ItemTags" ("ItemId");
|
||||
|
||||
CREATE UNIQUE INDEX "IX_ItemTags_ItemId_TagId" ON "ItemTags" ("ItemId", "TagId");
|
||||
|
||||
CREATE INDEX "IX_ItemTags_TagId" ON "ItemTags" ("TagId");
|
||||
|
||||
CREATE INDEX "IX_Tags_Name" ON "Tags" ("Name");
|
||||
|
||||
INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion")
|
||||
VALUES ('20251202211204_1.7.2-AddTagTables', '9.0.4');
|
||||
|
||||
COMMIT;
|
||||
VALUES ('20251203162345_1.7.0-FieldBasedDataModelUpdate', '9.0.4');
|
||||
`;
|
||||
var MIGRATION_SCRIPTS = {
|
||||
1: `\uFEFFBEGIN TRANSACTION;
|
||||
@@ -1846,14 +1762,12 @@ CREATE INDEX IF NOT EXISTS "IX_Attachments_ItemId" ON "Attachments" ("ItemId");
|
||||
|
||||
CREATE TABLE "FieldDefinitions" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_FieldDefinitions" PRIMARY KEY,
|
||||
"FieldKey" TEXT NULL,
|
||||
"EntityType" TEXT NULL,
|
||||
"FieldType" TEXT NOT NULL,
|
||||
"Label" TEXT NOT NULL,
|
||||
"IsMultiValue" INTEGER NOT NULL,
|
||||
"DefaultVisibility" TEXT NULL,
|
||||
"IsHidden" INTEGER NOT NULL,
|
||||
"EnableHistory" INTEGER NOT NULL,
|
||||
"DisplayOrder" INTEGER NOT NULL,
|
||||
"Weight" INTEGER NOT NULL,
|
||||
"ApplicableToTypes" TEXT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
@@ -1864,7 +1778,7 @@ CREATE TABLE "Folders" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_Folders" PRIMARY KEY,
|
||||
"Name" TEXT NOT NULL,
|
||||
"ParentFolderId" TEXT NULL,
|
||||
"DisplayOrder" INTEGER NOT NULL,
|
||||
"Weight" INTEGER NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL,
|
||||
@@ -1882,6 +1796,16 @@ CREATE TABLE "Logos" (
|
||||
"IsDeleted" INTEGER NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE "Tags" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_Tags" PRIMARY KEY,
|
||||
"Name" TEXT NOT NULL,
|
||||
"Color" TEXT NULL,
|
||||
"DisplayOrder" INTEGER NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE "Items" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_Items" PRIMARY KEY,
|
||||
"Name" TEXT NULL,
|
||||
@@ -1911,9 +1835,10 @@ CREATE TABLE "FieldHistories" (
|
||||
CREATE TABLE "FieldValues" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_FieldValues" PRIMARY KEY,
|
||||
"ItemId" TEXT NOT NULL,
|
||||
"FieldDefinitionId" TEXT NOT NULL,
|
||||
"FieldDefinitionId" TEXT NULL,
|
||||
"FieldKey" TEXT NULL,
|
||||
"Value" TEXT NULL,
|
||||
"ValueIndex" INTEGER NOT NULL,
|
||||
"Weight" INTEGER NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL,
|
||||
@@ -1921,7 +1846,16 @@ CREATE TABLE "FieldValues" (
|
||||
CONSTRAINT "FK_FieldValues_Items_ItemId" FOREIGN KEY ("ItemId") REFERENCES "Items" ("Id") ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE INDEX "IX_FieldDefinitions_FieldKey" ON "FieldDefinitions" ("FieldKey");
|
||||
CREATE TABLE "ItemTags" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_ItemTags" PRIMARY KEY,
|
||||
"ItemId" TEXT NOT NULL,
|
||||
"TagId" TEXT NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL,
|
||||
CONSTRAINT "FK_ItemTags_Items_ItemId" FOREIGN KEY ("ItemId") REFERENCES "Items" ("Id") ON DELETE CASCADE,
|
||||
CONSTRAINT "FK_ItemTags_Tags_TagId" FOREIGN KEY ("TagId") REFERENCES "Tags" ("Id") ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE INDEX "IX_FieldHistories_FieldDefinitionId" ON "FieldHistories" ("FieldDefinitionId");
|
||||
|
||||
@@ -1929,9 +1863,13 @@ CREATE INDEX "IX_FieldHistories_ItemId" ON "FieldHistories" ("ItemId");
|
||||
|
||||
CREATE INDEX "IX_FieldValues_FieldDefinitionId" ON "FieldValues" ("FieldDefinitionId");
|
||||
|
||||
CREATE INDEX "IX_FieldValues_FieldKey" ON "FieldValues" ("FieldKey");
|
||||
|
||||
CREATE INDEX "IX_FieldValues_ItemId" ON "FieldValues" ("ItemId");
|
||||
|
||||
CREATE INDEX "IX_FieldValues_ItemId_FieldDefinitionId_ValueIndex" ON "FieldValues" ("ItemId", "FieldDefinitionId", "ValueIndex");
|
||||
CREATE INDEX "IX_FieldValues_ItemId_FieldDefinitionId_Weight" ON "FieldValues" ("ItemId", "FieldDefinitionId", "Weight");
|
||||
|
||||
CREATE INDEX "IX_FieldValues_ItemId_FieldKey" ON "FieldValues" ("ItemId", "FieldKey");
|
||||
|
||||
CREATE INDEX "IX_Folders_ParentFolderId" ON "Folders" ("ParentFolderId");
|
||||
|
||||
@@ -1939,27 +1877,15 @@ CREATE INDEX "IX_Items_FolderId" ON "Items" ("FolderId");
|
||||
|
||||
CREATE INDEX "IX_Items_LogoId" ON "Items" ("LogoId");
|
||||
|
||||
CREATE INDEX "IX_ItemTags_ItemId" ON "ItemTags" ("ItemId");
|
||||
|
||||
CREATE UNIQUE INDEX "IX_ItemTags_ItemId_TagId" ON "ItemTags" ("ItemId", "TagId");
|
||||
|
||||
CREATE INDEX "IX_ItemTags_TagId" ON "ItemTags" ("TagId");
|
||||
|
||||
CREATE UNIQUE INDEX "IX_Logos_Source" ON "Logos" ("Source");
|
||||
|
||||
|
||||
-- Login fields
|
||||
INSERT INTO FieldDefinitions (Id, FieldKey, EntityType, FieldType, Label, IsMultiValue, DefaultVisibility, EnableHistory, DisplayOrder, ApplicableToTypes, CreatedAt, UpdatedAt, IsDeleted)
|
||||
VALUES
|
||||
(lower(hex(randomblob(16))), 'login.username', 'Item', 'Text', 'Username', 0, 'Visible', 1, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'login.password', 'Item', 'Password', 'Password', 0, 'Hidden', 1, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'login.notes', 'Item', 'Text', 'Notes', 0, 'Collapsed', 0, 0, NULL, datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'login.url', 'Item', 'URL', 'Website URLs', 1, 'Visible', 0, 0, '["Login"]', datetime('now'), datetime('now'), 0);
|
||||
|
||||
-- Alias fields
|
||||
INSERT INTO FieldDefinitions (Id, FieldKey, EntityType, FieldType, Label, IsMultiValue, DefaultVisibility, EnableHistory, DisplayOrder, ApplicableToTypes, CreatedAt, UpdatedAt, IsDeleted)
|
||||
VALUES
|
||||
(lower(hex(randomblob(16))), 'alias.email', 'Item', 'Email', 'Alias Email', 0, 'Visible', 1, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'alias.first_name', 'Item', 'Text', 'First Name', 0, 'Visible', 0, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'alias.last_name', 'Item', 'Text', 'Last Name', 0, 'Visible', 0, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'alias.nickname', 'Item', 'Text', 'Nickname', 0, 'Visible', 0, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'alias.gender', 'Item', 'Text', 'Gender', 0, 'Visible', 0, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'alias.birthdate', 'Item', 'Date', 'Birth Date', 0, 'Visible', 0, 0, '["Login"]', datetime('now'), datetime('now'), 0);
|
||||
|
||||
CREATE INDEX "IX_Tags_Name" ON "Tags" ("Name");
|
||||
|
||||
|
||||
INSERT INTO Items (Id, Name, ItemType, LogoId, FolderId, CreatedAt, UpdatedAt, IsDeleted)
|
||||
@@ -2009,13 +1935,14 @@ CREATE UNIQUE INDEX "IX_Logos_Source" ON "Logos" ("Source");
|
||||
|
||||
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'login.url' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'login.url' AS FieldKey,
|
||||
s.Url AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
s.UpdatedAt AS CreatedAt,
|
||||
s.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
@@ -2025,13 +1952,14 @@ CREATE UNIQUE INDEX "IX_Logos_Source" ON "Logos" ("Source");
|
||||
|
||||
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'login.username' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'login.username' AS FieldKey,
|
||||
c.Username AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
c.UpdatedAt AS CreatedAt,
|
||||
c.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
@@ -2040,13 +1968,14 @@ CREATE UNIQUE INDEX "IX_Logos_Source" ON "Logos" ("Source");
|
||||
|
||||
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'login.notes' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'login.notes' AS FieldKey,
|
||||
c.Notes AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
c.UpdatedAt AS CreatedAt,
|
||||
c.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
@@ -2055,130 +1984,121 @@ CREATE UNIQUE INDEX "IX_Logos_Source" ON "Logos" ("Source");
|
||||
|
||||
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
p.CredentialId AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'login.password' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'login.password' AS FieldKey,
|
||||
p.Value AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
p.UpdatedAt AS CreatedAt,
|
||||
p.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Passwords p
|
||||
INNER JOIN (
|
||||
SELECT CredentialId, MAX(UpdatedAt) AS MaxUpdated
|
||||
SELECT CredentialId, MAX(UpdatedAt) AS MaxUpdated, MAX(Id) AS MaxId
|
||||
FROM Passwords
|
||||
WHERE IsDeleted = 0
|
||||
GROUP BY CredentialId
|
||||
) pm ON p.CredentialId = pm.CredentialId AND p.UpdatedAt = pm.MaxUpdated;
|
||||
) pm ON p.CredentialId = pm.CredentialId AND p.UpdatedAt = pm.MaxUpdated AND p.Id = pm.MaxId
|
||||
WHERE p.IsDeleted = 0;
|
||||
|
||||
|
||||
|
||||
INSERT INTO FieldHistories (Id, ItemId, FieldDefinitionId, ValueSnapshot, ChangedAt, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
p.CredentialId AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'login.password' LIMIT 1) AS FieldDefinitionId,
|
||||
'{"values":["' || p.Value || '"]}' AS ValueSnapshot,
|
||||
p.UpdatedAt AS ChangedAt,
|
||||
p.CreatedAt AS CreatedAt,
|
||||
p.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Passwords p
|
||||
WHERE p.Id NOT IN (
|
||||
SELECT p2.Id FROM Passwords p2
|
||||
INNER JOIN (
|
||||
SELECT CredentialId, MAX(UpdatedAt) AS MaxUpdated
|
||||
FROM Passwords
|
||||
GROUP BY CredentialId
|
||||
) pm ON p2.CredentialId = pm.CredentialId AND p2.UpdatedAt = pm.MaxUpdated
|
||||
);
|
||||
|
||||
|
||||
|
||||
-- Migrate Alias.Email
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'alias.email' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'alias.email' AS FieldKey,
|
||||
a.Email AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
a.UpdatedAt AS CreatedAt,
|
||||
a.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Credentials c
|
||||
INNER JOIN Aliases a ON a.Id = c.AliasId
|
||||
WHERE a.Email IS NOT NULL AND a.Email != '';
|
||||
|
||||
|
||||
-- Migrate Alias.FirstName
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'alias.first_name' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'alias.first_name' AS FieldKey,
|
||||
a.FirstName AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
a.UpdatedAt AS CreatedAt,
|
||||
a.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Credentials c
|
||||
INNER JOIN Aliases a ON a.Id = c.AliasId
|
||||
WHERE a.FirstName IS NOT NULL AND a.FirstName != '';
|
||||
|
||||
|
||||
-- Migrate Alias.LastName
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'alias.last_name' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'alias.last_name' AS FieldKey,
|
||||
a.LastName AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
a.UpdatedAt AS CreatedAt,
|
||||
a.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Credentials c
|
||||
INNER JOIN Aliases a ON a.Id = c.AliasId
|
||||
WHERE a.LastName IS NOT NULL AND a.LastName != '';
|
||||
|
||||
|
||||
-- Migrate Alias.NickName
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'alias.nickname' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'alias.nickname' AS FieldKey,
|
||||
a.NickName AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
a.UpdatedAt AS CreatedAt,
|
||||
a.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Credentials c
|
||||
INNER JOIN Aliases a ON a.Id = c.AliasId
|
||||
WHERE a.NickName IS NOT NULL AND a.NickName != '';
|
||||
|
||||
|
||||
-- Migrate Alias.Gender
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'alias.gender' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'alias.gender' AS FieldKey,
|
||||
a.Gender AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
a.UpdatedAt AS CreatedAt,
|
||||
a.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Credentials c
|
||||
INNER JOIN Aliases a ON a.Id = c.AliasId
|
||||
WHERE a.Gender IS NOT NULL AND a.Gender != '';
|
||||
|
||||
|
||||
-- Migrate Alias.BirthDate
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'alias.birthdate' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'alias.birthdate' AS FieldKey,
|
||||
a.BirthDate AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
a.UpdatedAt AS CreatedAt,
|
||||
a.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
@@ -2278,93 +2198,7 @@ CREATE INDEX "IX_TotpCodes_ItemId" ON "TotpCodes" ("ItemId");
|
||||
COMMIT;
|
||||
|
||||
INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion")
|
||||
VALUES ('20251126211441_1.7.0-FieldBasedDataModelUpdate', '9.0.4');`,
|
||||
12: `\uFEFFBEGIN TRANSACTION;
|
||||
ALTER TABLE "Folders" RENAME COLUMN "DisplayOrder" TO "Weight";
|
||||
|
||||
ALTER TABLE "FieldValues" RENAME COLUMN "ValueIndex" TO "Weight";
|
||||
|
||||
DROP INDEX "IX_FieldValues_ItemId_FieldDefinitionId_ValueIndex";
|
||||
|
||||
CREATE INDEX "IX_FieldValues_ItemId_FieldDefinitionId_Weight" ON "FieldValues" ("ItemId", "FieldDefinitionId", "Weight");
|
||||
|
||||
ALTER TABLE "FieldDefinitions" RENAME COLUMN "DisplayOrder" TO "Weight";
|
||||
|
||||
ALTER TABLE "FieldDefinitions" ADD "IsHidden" INTEGER NOT NULL DEFAULT 0;
|
||||
|
||||
CREATE TABLE "ef_temp_FieldDefinitions" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_FieldDefinitions" PRIMARY KEY,
|
||||
"ApplicableToTypes" TEXT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"EnableHistory" INTEGER NOT NULL,
|
||||
"FieldKey" TEXT NULL,
|
||||
"FieldType" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL,
|
||||
"IsHidden" INTEGER NOT NULL,
|
||||
"IsMultiValue" INTEGER NOT NULL,
|
||||
"Label" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"Weight" INTEGER NOT NULL
|
||||
);
|
||||
|
||||
INSERT INTO "ef_temp_FieldDefinitions" ("Id", "ApplicableToTypes", "CreatedAt", "EnableHistory", "FieldKey", "FieldType", "IsDeleted", "IsHidden", "IsMultiValue", "Label", "UpdatedAt", "Weight")
|
||||
SELECT "Id", "ApplicableToTypes", "CreatedAt", "EnableHistory", "FieldKey", "FieldType", "IsDeleted", "IsHidden", "IsMultiValue", "Label", "UpdatedAt", "Weight"
|
||||
FROM "FieldDefinitions";
|
||||
|
||||
COMMIT;
|
||||
|
||||
PRAGMA foreign_keys = 0;
|
||||
|
||||
BEGIN TRANSACTION;
|
||||
DROP TABLE "FieldDefinitions";
|
||||
|
||||
ALTER TABLE "ef_temp_FieldDefinitions" RENAME TO "FieldDefinitions";
|
||||
|
||||
COMMIT;
|
||||
|
||||
PRAGMA foreign_keys = 1;
|
||||
|
||||
BEGIN TRANSACTION;
|
||||
CREATE INDEX "IX_FieldDefinitions_FieldKey" ON "FieldDefinitions" ("FieldKey");
|
||||
|
||||
COMMIT;
|
||||
|
||||
INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion")
|
||||
VALUES ('20251126221717_1.7.1-RenameColumns', '9.0.4');`,
|
||||
13: `\uFEFFBEGIN TRANSACTION;
|
||||
CREATE TABLE "Tags" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_Tags" PRIMARY KEY,
|
||||
"Name" TEXT NOT NULL,
|
||||
"Color" TEXT NULL,
|
||||
"DisplayOrder" INTEGER NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE "ItemTags" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_ItemTags" PRIMARY KEY,
|
||||
"ItemId" TEXT NOT NULL,
|
||||
"TagId" TEXT NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL,
|
||||
CONSTRAINT "FK_ItemTags_Items_ItemId" FOREIGN KEY ("ItemId") REFERENCES "Items" ("Id") ON DELETE CASCADE,
|
||||
CONSTRAINT "FK_ItemTags_Tags_TagId" FOREIGN KEY ("TagId") REFERENCES "Tags" ("Id") ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE INDEX "IX_ItemTags_ItemId" ON "ItemTags" ("ItemId");
|
||||
|
||||
CREATE UNIQUE INDEX "IX_ItemTags_ItemId_TagId" ON "ItemTags" ("ItemId", "TagId");
|
||||
|
||||
CREATE INDEX "IX_ItemTags_TagId" ON "ItemTags" ("TagId");
|
||||
|
||||
CREATE INDEX "IX_Tags_Name" ON "Tags" ("Name");
|
||||
|
||||
INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion")
|
||||
VALUES ('20251202211204_1.7.2-AddTagTables', '9.0.4');
|
||||
|
||||
COMMIT;`
|
||||
VALUES ('20251203162345_1.7.0-FieldBasedDataModelUpdate', '9.0.4');`
|
||||
};
|
||||
|
||||
// src/sql/VaultVersions.ts
|
||||
@@ -2452,20 +2286,6 @@ var VAULT_VERSIONS = [
|
||||
description: "Update to Field-Based Data Model",
|
||||
releaseVersion: "0.26.0",
|
||||
compatibleUpToVersion: "0.26.0"
|
||||
},
|
||||
{
|
||||
revision: 13,
|
||||
version: "1.7.1",
|
||||
description: "Rename Columns",
|
||||
releaseVersion: "0.26.0",
|
||||
compatibleUpToVersion: "0.26.0"
|
||||
},
|
||||
{
|
||||
revision: 14,
|
||||
version: "1.8.0",
|
||||
description: "Add Tags Tables",
|
||||
releaseVersion: "0.27.0",
|
||||
compatibleUpToVersion: "0.27.0"
|
||||
}
|
||||
];
|
||||
|
||||
|
||||
@@ -321,4 +321,135 @@ type ItemTag = {
|
||||
IsDeleted: number;
|
||||
};
|
||||
|
||||
export { type Alias, type Attachment, type Credential, type EncryptionKey, FieldKey, type FieldKeyValue, type ItemTag, type Passkey, type PasswordSettings, type Tag, type TotpCode };
|
||||
/**
|
||||
* Item types supported by the vault
|
||||
*/
|
||||
type ItemType = 'Login' | 'CreditCard' | 'Identity' | 'Note';
|
||||
/**
|
||||
* Item type representing vault entries in the new field-based data model.
|
||||
* Replaces the old Credential type.
|
||||
*/
|
||||
type Item = {
|
||||
Id: string;
|
||||
Name: string | null;
|
||||
ItemType: ItemType;
|
||||
Logo?: Uint8Array | number[];
|
||||
FolderId?: string | null;
|
||||
FolderPath?: string | null;
|
||||
Tags?: ItemTagRef[];
|
||||
Fields: ItemField[];
|
||||
HasPasskey?: boolean;
|
||||
HasAttachment?: boolean;
|
||||
HasTotp?: boolean;
|
||||
CreatedAt: string;
|
||||
UpdatedAt: string;
|
||||
};
|
||||
/**
|
||||
* Field value within an item
|
||||
*/
|
||||
type ItemField = {
|
||||
FieldKey: string;
|
||||
Label: string;
|
||||
FieldType: FieldType;
|
||||
Value: string | string[];
|
||||
IsHidden: boolean;
|
||||
DisplayOrder: number;
|
||||
};
|
||||
/**
|
||||
* Field types for rendering and validation
|
||||
*/
|
||||
type FieldType = 'Text' | 'Password' | 'Email' | 'URL' | 'Date' | 'Number' | 'Phone' | 'TextArea';
|
||||
/**
|
||||
* Tag reference for display within an item
|
||||
*/
|
||||
type ItemTagRef = {
|
||||
Id: string;
|
||||
Name: string;
|
||||
Color?: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper functions for working with Item model
|
||||
*/
|
||||
/**
|
||||
* Get a single field value by FieldKey
|
||||
*/
|
||||
declare function getFieldValue(item: Item, fieldKey: string): string | undefined;
|
||||
/**
|
||||
* Get all values for a multi-value field
|
||||
*/
|
||||
declare function getFieldValues(item: Item, fieldKey: string): string[];
|
||||
/**
|
||||
* Check if a field exists and has a value
|
||||
*/
|
||||
declare function hasField(item: Item, fieldKey: string): boolean;
|
||||
/**
|
||||
* Group fields by a categorization function
|
||||
*/
|
||||
declare function groupFields(item: Item, grouper: (field: ItemField) => string): Record<string, ItemField[]>;
|
||||
/**
|
||||
* Group fields by standard categories (Login, Alias, Custom)
|
||||
*/
|
||||
declare function groupFieldsByCategory(item: Item): Record<string, ItemField[]>;
|
||||
/**
|
||||
* Convert new Item model to legacy Credential model for backward compatibility.
|
||||
* @deprecated Use Item model directly. This is a temporary compatibility layer.
|
||||
*/
|
||||
declare function itemToCredential(item: Item): Credential;
|
||||
|
||||
/**
|
||||
* System field definition with metadata.
|
||||
* System fields are predefined fields with immutable keys like 'login.username'.
|
||||
* Their metadata (label, type, etc.) is defined here in code, not in the database.
|
||||
*/
|
||||
type SystemFieldDefinition = {
|
||||
/** Unique system field key (e.g., 'login.username') */
|
||||
FieldKey: string;
|
||||
/** Display label for the field */
|
||||
Label: string;
|
||||
/** Field type for rendering/validation */
|
||||
FieldType: FieldType;
|
||||
/** Whether field is hidden/masked by default */
|
||||
IsHidden: boolean;
|
||||
/** Whether field supports multiple values */
|
||||
IsMultiValue: boolean;
|
||||
/** Item types this field applies to */
|
||||
ApplicableToTypes: ItemType[];
|
||||
/** Whether to track field value history */
|
||||
EnableHistory: boolean;
|
||||
/** Category for grouping in UI */
|
||||
Category: 'Login' | 'Alias' | 'Card' | 'Identity' | 'API' | 'Note';
|
||||
/** Default display order within category (lower = first) */
|
||||
DefaultDisplayOrder: number;
|
||||
};
|
||||
/**
|
||||
* Registry of all system-defined fields.
|
||||
* These fields are immutable and their metadata is defined in code.
|
||||
* DO NOT modify these definitions without careful consideration of backwards compatibility.
|
||||
*/
|
||||
declare const SystemFieldRegistry: Record<string, SystemFieldDefinition>;
|
||||
/**
|
||||
* Get system field definition by key.
|
||||
* Returns undefined if the field key is not a system field.
|
||||
*/
|
||||
declare function getSystemField(fieldKey: string): SystemFieldDefinition | undefined;
|
||||
/**
|
||||
* Check if a field key represents a system field.
|
||||
*/
|
||||
declare function isSystemField(fieldKey: string): boolean;
|
||||
/**
|
||||
* Get all system fields applicable to a specific item type.
|
||||
* Results are sorted by DefaultDisplayOrder.
|
||||
*/
|
||||
declare function getSystemFieldsForItemType(itemType: ItemType): SystemFieldDefinition[];
|
||||
/**
|
||||
* Get all system field keys.
|
||||
*/
|
||||
declare function getAllSystemFieldKeys(): string[];
|
||||
/**
|
||||
* Check if a field key matches a known system field prefix.
|
||||
* This is useful for validation even before a specific field is registered.
|
||||
*/
|
||||
declare function isSystemFieldPrefix(fieldKey: string): boolean;
|
||||
|
||||
export { type Alias, type Attachment, type Credential, type EncryptionKey, FieldKey, type FieldKeyValue, type FieldType, type Item, type ItemField, type ItemTag, type ItemTagRef, type ItemType, type Passkey, type PasswordSettings, type SystemFieldDefinition, SystemFieldRegistry, type Tag, type TotpCode, getAllSystemFieldKeys, getFieldValue, getFieldValues, getSystemField, getSystemFieldsForItemType, groupFields, groupFieldsByCategory, hasField, isSystemField, isSystemFieldPrefix, itemToCredential };
|
||||
|
||||
@@ -151,6 +151,219 @@ var FieldKey = {
|
||||
AliasBirthdate: "alias.birthdate"
|
||||
};
|
||||
|
||||
export { FieldKey };
|
||||
// src/vault/ItemMethods.ts
|
||||
function getFieldValue(item, fieldKey) {
|
||||
const field = item.Fields.find((f) => f.FieldKey === fieldKey);
|
||||
if (!field) {
|
||||
return void 0;
|
||||
}
|
||||
return Array.isArray(field.Value) ? field.Value[0] : field.Value;
|
||||
}
|
||||
function getFieldValues(item, fieldKey) {
|
||||
const field = item.Fields.find((f) => f.FieldKey === fieldKey);
|
||||
if (!field) {
|
||||
return [];
|
||||
}
|
||||
return Array.isArray(field.Value) ? field.Value : [field.Value];
|
||||
}
|
||||
function hasField(item, fieldKey) {
|
||||
const value = getFieldValue(item, fieldKey);
|
||||
return value !== void 0 && value !== "";
|
||||
}
|
||||
function groupFields(item, grouper) {
|
||||
const groups = {};
|
||||
item.Fields.forEach((field) => {
|
||||
const group = grouper(field);
|
||||
if (!groups[group]) {
|
||||
groups[group] = [];
|
||||
}
|
||||
groups[group].push(field);
|
||||
});
|
||||
return groups;
|
||||
}
|
||||
function groupFieldsByCategory(item) {
|
||||
return groupFields(item, (field) => {
|
||||
if (field.FieldKey === FieldKey.AliasEmail) {
|
||||
return "Login";
|
||||
}
|
||||
if (field.FieldKey.startsWith("login.")) {
|
||||
return "Login";
|
||||
}
|
||||
if (field.FieldKey.startsWith("alias.")) {
|
||||
return "Alias";
|
||||
}
|
||||
if (field.FieldKey.startsWith("card.")) {
|
||||
return "Card";
|
||||
}
|
||||
if (field.FieldKey.startsWith("identity.")) {
|
||||
return "Identity";
|
||||
}
|
||||
if (field.FieldKey.startsWith("api.")) {
|
||||
return "API";
|
||||
}
|
||||
return "Custom";
|
||||
});
|
||||
}
|
||||
function itemToCredential(item) {
|
||||
return {
|
||||
Id: item.Id,
|
||||
Username: getFieldValue(item, FieldKey.LoginUsername),
|
||||
Password: getFieldValue(item, FieldKey.LoginPassword) || "",
|
||||
ServiceName: item.Name || "",
|
||||
ServiceUrl: getFieldValue(item, FieldKey.LoginUrl),
|
||||
Logo: item.Logo,
|
||||
Notes: getFieldValue(item, FieldKey.LoginNotes),
|
||||
Alias: {
|
||||
FirstName: getFieldValue(item, FieldKey.AliasFirstName),
|
||||
LastName: getFieldValue(item, FieldKey.AliasLastName),
|
||||
NickName: getFieldValue(item, FieldKey.AliasNickname),
|
||||
BirthDate: getFieldValue(item, FieldKey.AliasBirthdate) || "",
|
||||
Gender: getFieldValue(item, FieldKey.AliasGender),
|
||||
Email: getFieldValue(item, FieldKey.AliasEmail)
|
||||
},
|
||||
HasPasskey: item.HasPasskey,
|
||||
HasAttachment: item.HasAttachment
|
||||
};
|
||||
}
|
||||
|
||||
// src/vault/SystemFieldRegistry.ts
|
||||
var SystemFieldRegistry = {
|
||||
// Login Fields
|
||||
"login.username": {
|
||||
FieldKey: "login.username",
|
||||
Label: "Username",
|
||||
FieldType: "Text",
|
||||
IsHidden: false,
|
||||
IsMultiValue: false,
|
||||
ApplicableToTypes: ["Login"],
|
||||
EnableHistory: true,
|
||||
Category: "Login",
|
||||
DefaultDisplayOrder: 10
|
||||
},
|
||||
"login.password": {
|
||||
FieldKey: "login.password",
|
||||
Label: "Password",
|
||||
FieldType: "Password",
|
||||
IsHidden: true,
|
||||
IsMultiValue: false,
|
||||
ApplicableToTypes: ["Login"],
|
||||
EnableHistory: true,
|
||||
Category: "Login",
|
||||
DefaultDisplayOrder: 20
|
||||
},
|
||||
"login.url": {
|
||||
FieldKey: "login.url",
|
||||
Label: "Website",
|
||||
FieldType: "URL",
|
||||
IsHidden: false,
|
||||
IsMultiValue: true,
|
||||
ApplicableToTypes: ["Login"],
|
||||
EnableHistory: false,
|
||||
Category: "Login",
|
||||
DefaultDisplayOrder: 30
|
||||
},
|
||||
"login.notes": {
|
||||
FieldKey: "login.notes",
|
||||
Label: "Notes",
|
||||
FieldType: "TextArea",
|
||||
IsHidden: false,
|
||||
IsMultiValue: false,
|
||||
ApplicableToTypes: ["Login", "CreditCard", "Identity", "Note"],
|
||||
EnableHistory: false,
|
||||
Category: "Login",
|
||||
DefaultDisplayOrder: 100
|
||||
},
|
||||
// Alias Fields
|
||||
"alias.email": {
|
||||
FieldKey: "alias.email",
|
||||
Label: "Email",
|
||||
FieldType: "Email",
|
||||
IsHidden: false,
|
||||
IsMultiValue: false,
|
||||
ApplicableToTypes: ["Login"],
|
||||
EnableHistory: true,
|
||||
Category: "Alias",
|
||||
DefaultDisplayOrder: 10
|
||||
},
|
||||
"alias.first_name": {
|
||||
FieldKey: "alias.first_name",
|
||||
Label: "First Name",
|
||||
FieldType: "Text",
|
||||
IsHidden: false,
|
||||
IsMultiValue: false,
|
||||
ApplicableToTypes: ["Login", "Identity"],
|
||||
EnableHistory: false,
|
||||
Category: "Alias",
|
||||
DefaultDisplayOrder: 20
|
||||
},
|
||||
"alias.last_name": {
|
||||
FieldKey: "alias.last_name",
|
||||
Label: "Last Name",
|
||||
FieldType: "Text",
|
||||
IsHidden: false,
|
||||
IsMultiValue: false,
|
||||
ApplicableToTypes: ["Login", "Identity"],
|
||||
EnableHistory: false,
|
||||
Category: "Alias",
|
||||
DefaultDisplayOrder: 30
|
||||
},
|
||||
"alias.nickname": {
|
||||
FieldKey: "alias.nickname",
|
||||
Label: "Nickname",
|
||||
FieldType: "Text",
|
||||
IsHidden: false,
|
||||
IsMultiValue: false,
|
||||
ApplicableToTypes: ["Login"],
|
||||
EnableHistory: false,
|
||||
Category: "Alias",
|
||||
DefaultDisplayOrder: 40
|
||||
},
|
||||
"alias.gender": {
|
||||
FieldKey: "alias.gender",
|
||||
Label: "Gender",
|
||||
FieldType: "Text",
|
||||
IsHidden: false,
|
||||
IsMultiValue: false,
|
||||
ApplicableToTypes: ["Login", "Identity"],
|
||||
EnableHistory: false,
|
||||
Category: "Alias",
|
||||
DefaultDisplayOrder: 50
|
||||
},
|
||||
"alias.birthdate": {
|
||||
FieldKey: "alias.birthdate",
|
||||
Label: "Birth Date",
|
||||
FieldType: "Date",
|
||||
IsHidden: false,
|
||||
IsMultiValue: false,
|
||||
ApplicableToTypes: ["Login", "Identity"],
|
||||
EnableHistory: false,
|
||||
Category: "Alias",
|
||||
DefaultDisplayOrder: 60
|
||||
}
|
||||
/*
|
||||
* Note: Card, Identity, and API fields can be added here when those item types are implemented
|
||||
* Example:
|
||||
* 'card.number': { ... },
|
||||
* 'card.cardholder_name': { ... },
|
||||
* 'identity.phone_number': { ... },
|
||||
*/
|
||||
};
|
||||
function getSystemField(fieldKey) {
|
||||
return SystemFieldRegistry[fieldKey];
|
||||
}
|
||||
function isSystemField(fieldKey) {
|
||||
return fieldKey in SystemFieldRegistry;
|
||||
}
|
||||
function getSystemFieldsForItemType(itemType) {
|
||||
return Object.values(SystemFieldRegistry).filter((field) => field.ApplicableToTypes.includes(itemType)).sort((a, b) => a.DefaultDisplayOrder - b.DefaultDisplayOrder);
|
||||
}
|
||||
function getAllSystemFieldKeys() {
|
||||
return Object.keys(SystemFieldRegistry);
|
||||
}
|
||||
function isSystemFieldPrefix(fieldKey) {
|
||||
return fieldKey.startsWith("login.") || fieldKey.startsWith("alias.") || fieldKey.startsWith("card.") || fieldKey.startsWith("identity.") || fieldKey.startsWith("api.") || fieldKey.startsWith("note.");
|
||||
}
|
||||
|
||||
export { FieldKey, SystemFieldRegistry, getAllSystemFieldKeys, getFieldValue, getFieldValues, getSystemField, getSystemFieldsForItemType, groupFields, groupFieldsByCategory, hasField, isSystemField, isSystemFieldPrefix, itemToCredential };
|
||||
//# sourceMappingURL=index.js.map
|
||||
//# sourceMappingURL=index.js.map
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
552
apps/mobile-app/utils/dist/shared/vault-sql/index.js
vendored
552
apps/mobile-app/utils/dist/shared/vault-sql/index.js
vendored
@@ -728,14 +728,12 @@ CREATE INDEX IF NOT EXISTS "IX_Attachments_ItemId" ON "Attachments" ("ItemId");
|
||||
|
||||
CREATE TABLE "FieldDefinitions" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_FieldDefinitions" PRIMARY KEY,
|
||||
"FieldKey" TEXT NULL,
|
||||
"EntityType" TEXT NULL,
|
||||
"FieldType" TEXT NOT NULL,
|
||||
"Label" TEXT NOT NULL,
|
||||
"IsMultiValue" INTEGER NOT NULL,
|
||||
"DefaultVisibility" TEXT NULL,
|
||||
"IsHidden" INTEGER NOT NULL,
|
||||
"EnableHistory" INTEGER NOT NULL,
|
||||
"DisplayOrder" INTEGER NOT NULL,
|
||||
"Weight" INTEGER NOT NULL,
|
||||
"ApplicableToTypes" TEXT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
@@ -746,7 +744,7 @@ CREATE TABLE "Folders" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_Folders" PRIMARY KEY,
|
||||
"Name" TEXT NOT NULL,
|
||||
"ParentFolderId" TEXT NULL,
|
||||
"DisplayOrder" INTEGER NOT NULL,
|
||||
"Weight" INTEGER NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL,
|
||||
@@ -764,6 +762,16 @@ CREATE TABLE "Logos" (
|
||||
"IsDeleted" INTEGER NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE "Tags" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_Tags" PRIMARY KEY,
|
||||
"Name" TEXT NOT NULL,
|
||||
"Color" TEXT NULL,
|
||||
"DisplayOrder" INTEGER NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE "Items" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_Items" PRIMARY KEY,
|
||||
"Name" TEXT NULL,
|
||||
@@ -793,9 +801,10 @@ CREATE TABLE "FieldHistories" (
|
||||
CREATE TABLE "FieldValues" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_FieldValues" PRIMARY KEY,
|
||||
"ItemId" TEXT NOT NULL,
|
||||
"FieldDefinitionId" TEXT NOT NULL,
|
||||
"FieldDefinitionId" TEXT NULL,
|
||||
"FieldKey" TEXT NULL,
|
||||
"Value" TEXT NULL,
|
||||
"ValueIndex" INTEGER NOT NULL,
|
||||
"Weight" INTEGER NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL,
|
||||
@@ -803,7 +812,16 @@ CREATE TABLE "FieldValues" (
|
||||
CONSTRAINT "FK_FieldValues_Items_ItemId" FOREIGN KEY ("ItemId") REFERENCES "Items" ("Id") ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE INDEX "IX_FieldDefinitions_FieldKey" ON "FieldDefinitions" ("FieldKey");
|
||||
CREATE TABLE "ItemTags" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_ItemTags" PRIMARY KEY,
|
||||
"ItemId" TEXT NOT NULL,
|
||||
"TagId" TEXT NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL,
|
||||
CONSTRAINT "FK_ItemTags_Items_ItemId" FOREIGN KEY ("ItemId") REFERENCES "Items" ("Id") ON DELETE CASCADE,
|
||||
CONSTRAINT "FK_ItemTags_Tags_TagId" FOREIGN KEY ("TagId") REFERENCES "Tags" ("Id") ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE INDEX "IX_FieldHistories_FieldDefinitionId" ON "FieldHistories" ("FieldDefinitionId");
|
||||
|
||||
@@ -811,9 +829,13 @@ CREATE INDEX "IX_FieldHistories_ItemId" ON "FieldHistories" ("ItemId");
|
||||
|
||||
CREATE INDEX "IX_FieldValues_FieldDefinitionId" ON "FieldValues" ("FieldDefinitionId");
|
||||
|
||||
CREATE INDEX "IX_FieldValues_FieldKey" ON "FieldValues" ("FieldKey");
|
||||
|
||||
CREATE INDEX "IX_FieldValues_ItemId" ON "FieldValues" ("ItemId");
|
||||
|
||||
CREATE INDEX "IX_FieldValues_ItemId_FieldDefinitionId_ValueIndex" ON "FieldValues" ("ItemId", "FieldDefinitionId", "ValueIndex");
|
||||
CREATE INDEX "IX_FieldValues_ItemId_FieldDefinitionId_Weight" ON "FieldValues" ("ItemId", "FieldDefinitionId", "Weight");
|
||||
|
||||
CREATE INDEX "IX_FieldValues_ItemId_FieldKey" ON "FieldValues" ("ItemId", "FieldKey");
|
||||
|
||||
CREATE INDEX "IX_Folders_ParentFolderId" ON "Folders" ("ParentFolderId");
|
||||
|
||||
@@ -821,27 +843,15 @@ CREATE INDEX "IX_Items_FolderId" ON "Items" ("FolderId");
|
||||
|
||||
CREATE INDEX "IX_Items_LogoId" ON "Items" ("LogoId");
|
||||
|
||||
CREATE INDEX "IX_ItemTags_ItemId" ON "ItemTags" ("ItemId");
|
||||
|
||||
CREATE UNIQUE INDEX "IX_ItemTags_ItemId_TagId" ON "ItemTags" ("ItemId", "TagId");
|
||||
|
||||
CREATE INDEX "IX_ItemTags_TagId" ON "ItemTags" ("TagId");
|
||||
|
||||
CREATE UNIQUE INDEX "IX_Logos_Source" ON "Logos" ("Source");
|
||||
|
||||
|
||||
-- Login fields
|
||||
INSERT INTO FieldDefinitions (Id, FieldKey, EntityType, FieldType, Label, IsMultiValue, DefaultVisibility, EnableHistory, DisplayOrder, ApplicableToTypes, CreatedAt, UpdatedAt, IsDeleted)
|
||||
VALUES
|
||||
(lower(hex(randomblob(16))), 'login.username', 'Item', 'Text', 'Username', 0, 'Visible', 1, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'login.password', 'Item', 'Password', 'Password', 0, 'Hidden', 1, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'login.notes', 'Item', 'Text', 'Notes', 0, 'Collapsed', 0, 0, NULL, datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'login.url', 'Item', 'URL', 'Website URLs', 1, 'Visible', 0, 0, '["Login"]', datetime('now'), datetime('now'), 0);
|
||||
|
||||
-- Alias fields
|
||||
INSERT INTO FieldDefinitions (Id, FieldKey, EntityType, FieldType, Label, IsMultiValue, DefaultVisibility, EnableHistory, DisplayOrder, ApplicableToTypes, CreatedAt, UpdatedAt, IsDeleted)
|
||||
VALUES
|
||||
(lower(hex(randomblob(16))), 'alias.email', 'Item', 'Email', 'Alias Email', 0, 'Visible', 1, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'alias.first_name', 'Item', 'Text', 'First Name', 0, 'Visible', 0, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'alias.last_name', 'Item', 'Text', 'Last Name', 0, 'Visible', 0, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'alias.nickname', 'Item', 'Text', 'Nickname', 0, 'Visible', 0, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'alias.gender', 'Item', 'Text', 'Gender', 0, 'Visible', 0, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'alias.birthdate', 'Item', 'Date', 'Birth Date', 0, 'Visible', 0, 0, '["Login"]', datetime('now'), datetime('now'), 0);
|
||||
|
||||
CREATE INDEX "IX_Tags_Name" ON "Tags" ("Name");
|
||||
|
||||
|
||||
INSERT INTO Items (Id, Name, ItemType, LogoId, FolderId, CreatedAt, UpdatedAt, IsDeleted)
|
||||
@@ -891,13 +901,14 @@ CREATE UNIQUE INDEX "IX_Logos_Source" ON "Logos" ("Source");
|
||||
|
||||
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'login.url' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'login.url' AS FieldKey,
|
||||
s.Url AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
s.UpdatedAt AS CreatedAt,
|
||||
s.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
@@ -907,13 +918,14 @@ CREATE UNIQUE INDEX "IX_Logos_Source" ON "Logos" ("Source");
|
||||
|
||||
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'login.username' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'login.username' AS FieldKey,
|
||||
c.Username AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
c.UpdatedAt AS CreatedAt,
|
||||
c.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
@@ -922,13 +934,14 @@ CREATE UNIQUE INDEX "IX_Logos_Source" ON "Logos" ("Source");
|
||||
|
||||
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'login.notes' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'login.notes' AS FieldKey,
|
||||
c.Notes AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
c.UpdatedAt AS CreatedAt,
|
||||
c.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
@@ -937,130 +950,121 @@ CREATE UNIQUE INDEX "IX_Logos_Source" ON "Logos" ("Source");
|
||||
|
||||
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
p.CredentialId AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'login.password' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'login.password' AS FieldKey,
|
||||
p.Value AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
p.UpdatedAt AS CreatedAt,
|
||||
p.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Passwords p
|
||||
INNER JOIN (
|
||||
SELECT CredentialId, MAX(UpdatedAt) AS MaxUpdated
|
||||
SELECT CredentialId, MAX(UpdatedAt) AS MaxUpdated, MAX(Id) AS MaxId
|
||||
FROM Passwords
|
||||
WHERE IsDeleted = 0
|
||||
GROUP BY CredentialId
|
||||
) pm ON p.CredentialId = pm.CredentialId AND p.UpdatedAt = pm.MaxUpdated;
|
||||
) pm ON p.CredentialId = pm.CredentialId AND p.UpdatedAt = pm.MaxUpdated AND p.Id = pm.MaxId
|
||||
WHERE p.IsDeleted = 0;
|
||||
|
||||
|
||||
|
||||
INSERT INTO FieldHistories (Id, ItemId, FieldDefinitionId, ValueSnapshot, ChangedAt, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
p.CredentialId AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'login.password' LIMIT 1) AS FieldDefinitionId,
|
||||
'{"values":["' || p.Value || '"]}' AS ValueSnapshot,
|
||||
p.UpdatedAt AS ChangedAt,
|
||||
p.CreatedAt AS CreatedAt,
|
||||
p.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Passwords p
|
||||
WHERE p.Id NOT IN (
|
||||
SELECT p2.Id FROM Passwords p2
|
||||
INNER JOIN (
|
||||
SELECT CredentialId, MAX(UpdatedAt) AS MaxUpdated
|
||||
FROM Passwords
|
||||
GROUP BY CredentialId
|
||||
) pm ON p2.CredentialId = pm.CredentialId AND p2.UpdatedAt = pm.MaxUpdated
|
||||
);
|
||||
|
||||
|
||||
|
||||
-- Migrate Alias.Email
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'alias.email' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'alias.email' AS FieldKey,
|
||||
a.Email AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
a.UpdatedAt AS CreatedAt,
|
||||
a.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Credentials c
|
||||
INNER JOIN Aliases a ON a.Id = c.AliasId
|
||||
WHERE a.Email IS NOT NULL AND a.Email != '';
|
||||
|
||||
|
||||
-- Migrate Alias.FirstName
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'alias.first_name' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'alias.first_name' AS FieldKey,
|
||||
a.FirstName AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
a.UpdatedAt AS CreatedAt,
|
||||
a.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Credentials c
|
||||
INNER JOIN Aliases a ON a.Id = c.AliasId
|
||||
WHERE a.FirstName IS NOT NULL AND a.FirstName != '';
|
||||
|
||||
|
||||
-- Migrate Alias.LastName
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'alias.last_name' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'alias.last_name' AS FieldKey,
|
||||
a.LastName AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
a.UpdatedAt AS CreatedAt,
|
||||
a.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Credentials c
|
||||
INNER JOIN Aliases a ON a.Id = c.AliasId
|
||||
WHERE a.LastName IS NOT NULL AND a.LastName != '';
|
||||
|
||||
|
||||
-- Migrate Alias.NickName
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'alias.nickname' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'alias.nickname' AS FieldKey,
|
||||
a.NickName AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
a.UpdatedAt AS CreatedAt,
|
||||
a.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Credentials c
|
||||
INNER JOIN Aliases a ON a.Id = c.AliasId
|
||||
WHERE a.NickName IS NOT NULL AND a.NickName != '';
|
||||
|
||||
|
||||
-- Migrate Alias.Gender
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'alias.gender' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'alias.gender' AS FieldKey,
|
||||
a.Gender AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
a.UpdatedAt AS CreatedAt,
|
||||
a.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Credentials c
|
||||
INNER JOIN Aliases a ON a.Id = c.AliasId
|
||||
WHERE a.Gender IS NOT NULL AND a.Gender != '';
|
||||
|
||||
|
||||
-- Migrate Alias.BirthDate
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'alias.birthdate' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'alias.birthdate' AS FieldKey,
|
||||
a.BirthDate AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
a.UpdatedAt AS CreatedAt,
|
||||
a.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
@@ -1160,95 +1164,7 @@ CREATE INDEX "IX_TotpCodes_ItemId" ON "TotpCodes" ("ItemId");
|
||||
COMMIT;
|
||||
|
||||
INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion")
|
||||
VALUES ('20251126211441_1.7.0-FieldBasedDataModelUpdate', '9.0.4');
|
||||
|
||||
BEGIN TRANSACTION;
|
||||
ALTER TABLE "Folders" RENAME COLUMN "DisplayOrder" TO "Weight";
|
||||
|
||||
ALTER TABLE "FieldValues" RENAME COLUMN "ValueIndex" TO "Weight";
|
||||
|
||||
DROP INDEX "IX_FieldValues_ItemId_FieldDefinitionId_ValueIndex";
|
||||
|
||||
CREATE INDEX "IX_FieldValues_ItemId_FieldDefinitionId_Weight" ON "FieldValues" ("ItemId", "FieldDefinitionId", "Weight");
|
||||
|
||||
ALTER TABLE "FieldDefinitions" RENAME COLUMN "DisplayOrder" TO "Weight";
|
||||
|
||||
ALTER TABLE "FieldDefinitions" ADD "IsHidden" INTEGER NOT NULL DEFAULT 0;
|
||||
|
||||
CREATE TABLE "ef_temp_FieldDefinitions" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_FieldDefinitions" PRIMARY KEY,
|
||||
"ApplicableToTypes" TEXT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"EnableHistory" INTEGER NOT NULL,
|
||||
"FieldKey" TEXT NULL,
|
||||
"FieldType" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL,
|
||||
"IsHidden" INTEGER NOT NULL,
|
||||
"IsMultiValue" INTEGER NOT NULL,
|
||||
"Label" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"Weight" INTEGER NOT NULL
|
||||
);
|
||||
|
||||
INSERT INTO "ef_temp_FieldDefinitions" ("Id", "ApplicableToTypes", "CreatedAt", "EnableHistory", "FieldKey", "FieldType", "IsDeleted", "IsHidden", "IsMultiValue", "Label", "UpdatedAt", "Weight")
|
||||
SELECT "Id", "ApplicableToTypes", "CreatedAt", "EnableHistory", "FieldKey", "FieldType", "IsDeleted", "IsHidden", "IsMultiValue", "Label", "UpdatedAt", "Weight"
|
||||
FROM "FieldDefinitions";
|
||||
|
||||
COMMIT;
|
||||
|
||||
PRAGMA foreign_keys = 0;
|
||||
|
||||
BEGIN TRANSACTION;
|
||||
DROP TABLE "FieldDefinitions";
|
||||
|
||||
ALTER TABLE "ef_temp_FieldDefinitions" RENAME TO "FieldDefinitions";
|
||||
|
||||
COMMIT;
|
||||
|
||||
PRAGMA foreign_keys = 1;
|
||||
|
||||
BEGIN TRANSACTION;
|
||||
CREATE INDEX "IX_FieldDefinitions_FieldKey" ON "FieldDefinitions" ("FieldKey");
|
||||
|
||||
COMMIT;
|
||||
|
||||
INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion")
|
||||
VALUES ('20251126221717_1.7.1-RenameColumns', '9.0.4');
|
||||
|
||||
BEGIN TRANSACTION;
|
||||
CREATE TABLE "Tags" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_Tags" PRIMARY KEY,
|
||||
"Name" TEXT NOT NULL,
|
||||
"Color" TEXT NULL,
|
||||
"DisplayOrder" INTEGER NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE "ItemTags" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_ItemTags" PRIMARY KEY,
|
||||
"ItemId" TEXT NOT NULL,
|
||||
"TagId" TEXT NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL,
|
||||
CONSTRAINT "FK_ItemTags_Items_ItemId" FOREIGN KEY ("ItemId") REFERENCES "Items" ("Id") ON DELETE CASCADE,
|
||||
CONSTRAINT "FK_ItemTags_Tags_TagId" FOREIGN KEY ("TagId") REFERENCES "Tags" ("Id") ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE INDEX "IX_ItemTags_ItemId" ON "ItemTags" ("ItemId");
|
||||
|
||||
CREATE UNIQUE INDEX "IX_ItemTags_ItemId_TagId" ON "ItemTags" ("ItemId", "TagId");
|
||||
|
||||
CREATE INDEX "IX_ItemTags_TagId" ON "ItemTags" ("TagId");
|
||||
|
||||
CREATE INDEX "IX_Tags_Name" ON "Tags" ("Name");
|
||||
|
||||
INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion")
|
||||
VALUES ('20251202211204_1.7.2-AddTagTables', '9.0.4');
|
||||
|
||||
COMMIT;
|
||||
VALUES ('20251203162345_1.7.0-FieldBasedDataModelUpdate', '9.0.4');
|
||||
`;
|
||||
var MIGRATION_SCRIPTS = {
|
||||
1: `\uFEFFBEGIN TRANSACTION;
|
||||
@@ -1878,14 +1794,12 @@ CREATE INDEX IF NOT EXISTS "IX_Attachments_ItemId" ON "Attachments" ("ItemId");
|
||||
|
||||
CREATE TABLE "FieldDefinitions" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_FieldDefinitions" PRIMARY KEY,
|
||||
"FieldKey" TEXT NULL,
|
||||
"EntityType" TEXT NULL,
|
||||
"FieldType" TEXT NOT NULL,
|
||||
"Label" TEXT NOT NULL,
|
||||
"IsMultiValue" INTEGER NOT NULL,
|
||||
"DefaultVisibility" TEXT NULL,
|
||||
"IsHidden" INTEGER NOT NULL,
|
||||
"EnableHistory" INTEGER NOT NULL,
|
||||
"DisplayOrder" INTEGER NOT NULL,
|
||||
"Weight" INTEGER NOT NULL,
|
||||
"ApplicableToTypes" TEXT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
@@ -1896,7 +1810,7 @@ CREATE TABLE "Folders" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_Folders" PRIMARY KEY,
|
||||
"Name" TEXT NOT NULL,
|
||||
"ParentFolderId" TEXT NULL,
|
||||
"DisplayOrder" INTEGER NOT NULL,
|
||||
"Weight" INTEGER NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL,
|
||||
@@ -1914,6 +1828,16 @@ CREATE TABLE "Logos" (
|
||||
"IsDeleted" INTEGER NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE "Tags" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_Tags" PRIMARY KEY,
|
||||
"Name" TEXT NOT NULL,
|
||||
"Color" TEXT NULL,
|
||||
"DisplayOrder" INTEGER NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE "Items" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_Items" PRIMARY KEY,
|
||||
"Name" TEXT NULL,
|
||||
@@ -1943,9 +1867,10 @@ CREATE TABLE "FieldHistories" (
|
||||
CREATE TABLE "FieldValues" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_FieldValues" PRIMARY KEY,
|
||||
"ItemId" TEXT NOT NULL,
|
||||
"FieldDefinitionId" TEXT NOT NULL,
|
||||
"FieldDefinitionId" TEXT NULL,
|
||||
"FieldKey" TEXT NULL,
|
||||
"Value" TEXT NULL,
|
||||
"ValueIndex" INTEGER NOT NULL,
|
||||
"Weight" INTEGER NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL,
|
||||
@@ -1953,7 +1878,16 @@ CREATE TABLE "FieldValues" (
|
||||
CONSTRAINT "FK_FieldValues_Items_ItemId" FOREIGN KEY ("ItemId") REFERENCES "Items" ("Id") ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE INDEX "IX_FieldDefinitions_FieldKey" ON "FieldDefinitions" ("FieldKey");
|
||||
CREATE TABLE "ItemTags" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_ItemTags" PRIMARY KEY,
|
||||
"ItemId" TEXT NOT NULL,
|
||||
"TagId" TEXT NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL,
|
||||
CONSTRAINT "FK_ItemTags_Items_ItemId" FOREIGN KEY ("ItemId") REFERENCES "Items" ("Id") ON DELETE CASCADE,
|
||||
CONSTRAINT "FK_ItemTags_Tags_TagId" FOREIGN KEY ("TagId") REFERENCES "Tags" ("Id") ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE INDEX "IX_FieldHistories_FieldDefinitionId" ON "FieldHistories" ("FieldDefinitionId");
|
||||
|
||||
@@ -1961,9 +1895,13 @@ CREATE INDEX "IX_FieldHistories_ItemId" ON "FieldHistories" ("ItemId");
|
||||
|
||||
CREATE INDEX "IX_FieldValues_FieldDefinitionId" ON "FieldValues" ("FieldDefinitionId");
|
||||
|
||||
CREATE INDEX "IX_FieldValues_FieldKey" ON "FieldValues" ("FieldKey");
|
||||
|
||||
CREATE INDEX "IX_FieldValues_ItemId" ON "FieldValues" ("ItemId");
|
||||
|
||||
CREATE INDEX "IX_FieldValues_ItemId_FieldDefinitionId_ValueIndex" ON "FieldValues" ("ItemId", "FieldDefinitionId", "ValueIndex");
|
||||
CREATE INDEX "IX_FieldValues_ItemId_FieldDefinitionId_Weight" ON "FieldValues" ("ItemId", "FieldDefinitionId", "Weight");
|
||||
|
||||
CREATE INDEX "IX_FieldValues_ItemId_FieldKey" ON "FieldValues" ("ItemId", "FieldKey");
|
||||
|
||||
CREATE INDEX "IX_Folders_ParentFolderId" ON "Folders" ("ParentFolderId");
|
||||
|
||||
@@ -1971,27 +1909,15 @@ CREATE INDEX "IX_Items_FolderId" ON "Items" ("FolderId");
|
||||
|
||||
CREATE INDEX "IX_Items_LogoId" ON "Items" ("LogoId");
|
||||
|
||||
CREATE INDEX "IX_ItemTags_ItemId" ON "ItemTags" ("ItemId");
|
||||
|
||||
CREATE UNIQUE INDEX "IX_ItemTags_ItemId_TagId" ON "ItemTags" ("ItemId", "TagId");
|
||||
|
||||
CREATE INDEX "IX_ItemTags_TagId" ON "ItemTags" ("TagId");
|
||||
|
||||
CREATE UNIQUE INDEX "IX_Logos_Source" ON "Logos" ("Source");
|
||||
|
||||
|
||||
-- Login fields
|
||||
INSERT INTO FieldDefinitions (Id, FieldKey, EntityType, FieldType, Label, IsMultiValue, DefaultVisibility, EnableHistory, DisplayOrder, ApplicableToTypes, CreatedAt, UpdatedAt, IsDeleted)
|
||||
VALUES
|
||||
(lower(hex(randomblob(16))), 'login.username', 'Item', 'Text', 'Username', 0, 'Visible', 1, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'login.password', 'Item', 'Password', 'Password', 0, 'Hidden', 1, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'login.notes', 'Item', 'Text', 'Notes', 0, 'Collapsed', 0, 0, NULL, datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'login.url', 'Item', 'URL', 'Website URLs', 1, 'Visible', 0, 0, '["Login"]', datetime('now'), datetime('now'), 0);
|
||||
|
||||
-- Alias fields
|
||||
INSERT INTO FieldDefinitions (Id, FieldKey, EntityType, FieldType, Label, IsMultiValue, DefaultVisibility, EnableHistory, DisplayOrder, ApplicableToTypes, CreatedAt, UpdatedAt, IsDeleted)
|
||||
VALUES
|
||||
(lower(hex(randomblob(16))), 'alias.email', 'Item', 'Email', 'Alias Email', 0, 'Visible', 1, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'alias.first_name', 'Item', 'Text', 'First Name', 0, 'Visible', 0, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'alias.last_name', 'Item', 'Text', 'Last Name', 0, 'Visible', 0, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'alias.nickname', 'Item', 'Text', 'Nickname', 0, 'Visible', 0, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'alias.gender', 'Item', 'Text', 'Gender', 0, 'Visible', 0, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'alias.birthdate', 'Item', 'Date', 'Birth Date', 0, 'Visible', 0, 0, '["Login"]', datetime('now'), datetime('now'), 0);
|
||||
|
||||
CREATE INDEX "IX_Tags_Name" ON "Tags" ("Name");
|
||||
|
||||
|
||||
INSERT INTO Items (Id, Name, ItemType, LogoId, FolderId, CreatedAt, UpdatedAt, IsDeleted)
|
||||
@@ -2041,13 +1967,14 @@ CREATE UNIQUE INDEX "IX_Logos_Source" ON "Logos" ("Source");
|
||||
|
||||
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'login.url' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'login.url' AS FieldKey,
|
||||
s.Url AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
s.UpdatedAt AS CreatedAt,
|
||||
s.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
@@ -2057,13 +1984,14 @@ CREATE UNIQUE INDEX "IX_Logos_Source" ON "Logos" ("Source");
|
||||
|
||||
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'login.username' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'login.username' AS FieldKey,
|
||||
c.Username AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
c.UpdatedAt AS CreatedAt,
|
||||
c.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
@@ -2072,13 +2000,14 @@ CREATE UNIQUE INDEX "IX_Logos_Source" ON "Logos" ("Source");
|
||||
|
||||
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'login.notes' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'login.notes' AS FieldKey,
|
||||
c.Notes AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
c.UpdatedAt AS CreatedAt,
|
||||
c.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
@@ -2087,130 +2016,121 @@ CREATE UNIQUE INDEX "IX_Logos_Source" ON "Logos" ("Source");
|
||||
|
||||
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
p.CredentialId AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'login.password' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'login.password' AS FieldKey,
|
||||
p.Value AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
p.UpdatedAt AS CreatedAt,
|
||||
p.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Passwords p
|
||||
INNER JOIN (
|
||||
SELECT CredentialId, MAX(UpdatedAt) AS MaxUpdated
|
||||
SELECT CredentialId, MAX(UpdatedAt) AS MaxUpdated, MAX(Id) AS MaxId
|
||||
FROM Passwords
|
||||
WHERE IsDeleted = 0
|
||||
GROUP BY CredentialId
|
||||
) pm ON p.CredentialId = pm.CredentialId AND p.UpdatedAt = pm.MaxUpdated;
|
||||
) pm ON p.CredentialId = pm.CredentialId AND p.UpdatedAt = pm.MaxUpdated AND p.Id = pm.MaxId
|
||||
WHERE p.IsDeleted = 0;
|
||||
|
||||
|
||||
|
||||
INSERT INTO FieldHistories (Id, ItemId, FieldDefinitionId, ValueSnapshot, ChangedAt, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
p.CredentialId AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'login.password' LIMIT 1) AS FieldDefinitionId,
|
||||
'{"values":["' || p.Value || '"]}' AS ValueSnapshot,
|
||||
p.UpdatedAt AS ChangedAt,
|
||||
p.CreatedAt AS CreatedAt,
|
||||
p.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Passwords p
|
||||
WHERE p.Id NOT IN (
|
||||
SELECT p2.Id FROM Passwords p2
|
||||
INNER JOIN (
|
||||
SELECT CredentialId, MAX(UpdatedAt) AS MaxUpdated
|
||||
FROM Passwords
|
||||
GROUP BY CredentialId
|
||||
) pm ON p2.CredentialId = pm.CredentialId AND p2.UpdatedAt = pm.MaxUpdated
|
||||
);
|
||||
|
||||
|
||||
|
||||
-- Migrate Alias.Email
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'alias.email' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'alias.email' AS FieldKey,
|
||||
a.Email AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
a.UpdatedAt AS CreatedAt,
|
||||
a.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Credentials c
|
||||
INNER JOIN Aliases a ON a.Id = c.AliasId
|
||||
WHERE a.Email IS NOT NULL AND a.Email != '';
|
||||
|
||||
|
||||
-- Migrate Alias.FirstName
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'alias.first_name' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'alias.first_name' AS FieldKey,
|
||||
a.FirstName AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
a.UpdatedAt AS CreatedAt,
|
||||
a.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Credentials c
|
||||
INNER JOIN Aliases a ON a.Id = c.AliasId
|
||||
WHERE a.FirstName IS NOT NULL AND a.FirstName != '';
|
||||
|
||||
|
||||
-- Migrate Alias.LastName
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'alias.last_name' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'alias.last_name' AS FieldKey,
|
||||
a.LastName AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
a.UpdatedAt AS CreatedAt,
|
||||
a.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Credentials c
|
||||
INNER JOIN Aliases a ON a.Id = c.AliasId
|
||||
WHERE a.LastName IS NOT NULL AND a.LastName != '';
|
||||
|
||||
|
||||
-- Migrate Alias.NickName
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'alias.nickname' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'alias.nickname' AS FieldKey,
|
||||
a.NickName AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
a.UpdatedAt AS CreatedAt,
|
||||
a.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Credentials c
|
||||
INNER JOIN Aliases a ON a.Id = c.AliasId
|
||||
WHERE a.NickName IS NOT NULL AND a.NickName != '';
|
||||
|
||||
|
||||
-- Migrate Alias.Gender
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'alias.gender' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'alias.gender' AS FieldKey,
|
||||
a.Gender AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
a.UpdatedAt AS CreatedAt,
|
||||
a.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Credentials c
|
||||
INNER JOIN Aliases a ON a.Id = c.AliasId
|
||||
WHERE a.Gender IS NOT NULL AND a.Gender != '';
|
||||
|
||||
|
||||
-- Migrate Alias.BirthDate
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'alias.birthdate' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'alias.birthdate' AS FieldKey,
|
||||
a.BirthDate AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
a.UpdatedAt AS CreatedAt,
|
||||
a.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
@@ -2310,93 +2230,7 @@ CREATE INDEX "IX_TotpCodes_ItemId" ON "TotpCodes" ("ItemId");
|
||||
COMMIT;
|
||||
|
||||
INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion")
|
||||
VALUES ('20251126211441_1.7.0-FieldBasedDataModelUpdate', '9.0.4');`,
|
||||
12: `\uFEFFBEGIN TRANSACTION;
|
||||
ALTER TABLE "Folders" RENAME COLUMN "DisplayOrder" TO "Weight";
|
||||
|
||||
ALTER TABLE "FieldValues" RENAME COLUMN "ValueIndex" TO "Weight";
|
||||
|
||||
DROP INDEX "IX_FieldValues_ItemId_FieldDefinitionId_ValueIndex";
|
||||
|
||||
CREATE INDEX "IX_FieldValues_ItemId_FieldDefinitionId_Weight" ON "FieldValues" ("ItemId", "FieldDefinitionId", "Weight");
|
||||
|
||||
ALTER TABLE "FieldDefinitions" RENAME COLUMN "DisplayOrder" TO "Weight";
|
||||
|
||||
ALTER TABLE "FieldDefinitions" ADD "IsHidden" INTEGER NOT NULL DEFAULT 0;
|
||||
|
||||
CREATE TABLE "ef_temp_FieldDefinitions" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_FieldDefinitions" PRIMARY KEY,
|
||||
"ApplicableToTypes" TEXT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"EnableHistory" INTEGER NOT NULL,
|
||||
"FieldKey" TEXT NULL,
|
||||
"FieldType" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL,
|
||||
"IsHidden" INTEGER NOT NULL,
|
||||
"IsMultiValue" INTEGER NOT NULL,
|
||||
"Label" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"Weight" INTEGER NOT NULL
|
||||
);
|
||||
|
||||
INSERT INTO "ef_temp_FieldDefinitions" ("Id", "ApplicableToTypes", "CreatedAt", "EnableHistory", "FieldKey", "FieldType", "IsDeleted", "IsHidden", "IsMultiValue", "Label", "UpdatedAt", "Weight")
|
||||
SELECT "Id", "ApplicableToTypes", "CreatedAt", "EnableHistory", "FieldKey", "FieldType", "IsDeleted", "IsHidden", "IsMultiValue", "Label", "UpdatedAt", "Weight"
|
||||
FROM "FieldDefinitions";
|
||||
|
||||
COMMIT;
|
||||
|
||||
PRAGMA foreign_keys = 0;
|
||||
|
||||
BEGIN TRANSACTION;
|
||||
DROP TABLE "FieldDefinitions";
|
||||
|
||||
ALTER TABLE "ef_temp_FieldDefinitions" RENAME TO "FieldDefinitions";
|
||||
|
||||
COMMIT;
|
||||
|
||||
PRAGMA foreign_keys = 1;
|
||||
|
||||
BEGIN TRANSACTION;
|
||||
CREATE INDEX "IX_FieldDefinitions_FieldKey" ON "FieldDefinitions" ("FieldKey");
|
||||
|
||||
COMMIT;
|
||||
|
||||
INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion")
|
||||
VALUES ('20251126221717_1.7.1-RenameColumns', '9.0.4');`,
|
||||
13: `\uFEFFBEGIN TRANSACTION;
|
||||
CREATE TABLE "Tags" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_Tags" PRIMARY KEY,
|
||||
"Name" TEXT NOT NULL,
|
||||
"Color" TEXT NULL,
|
||||
"DisplayOrder" INTEGER NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE "ItemTags" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_ItemTags" PRIMARY KEY,
|
||||
"ItemId" TEXT NOT NULL,
|
||||
"TagId" TEXT NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL,
|
||||
CONSTRAINT "FK_ItemTags_Items_ItemId" FOREIGN KEY ("ItemId") REFERENCES "Items" ("Id") ON DELETE CASCADE,
|
||||
CONSTRAINT "FK_ItemTags_Tags_TagId" FOREIGN KEY ("TagId") REFERENCES "Tags" ("Id") ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE INDEX "IX_ItemTags_ItemId" ON "ItemTags" ("ItemId");
|
||||
|
||||
CREATE UNIQUE INDEX "IX_ItemTags_ItemId_TagId" ON "ItemTags" ("ItemId", "TagId");
|
||||
|
||||
CREATE INDEX "IX_ItemTags_TagId" ON "ItemTags" ("TagId");
|
||||
|
||||
CREATE INDEX "IX_Tags_Name" ON "Tags" ("Name");
|
||||
|
||||
INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion")
|
||||
VALUES ('20251202211204_1.7.2-AddTagTables', '9.0.4');
|
||||
|
||||
COMMIT;`
|
||||
VALUES ('20251203162345_1.7.0-FieldBasedDataModelUpdate', '9.0.4');`
|
||||
};
|
||||
|
||||
// src/sql/VaultVersions.ts
|
||||
@@ -2484,20 +2318,6 @@ var VAULT_VERSIONS = [
|
||||
description: "Update to Field-Based Data Model",
|
||||
releaseVersion: "0.26.0",
|
||||
compatibleUpToVersion: "0.26.0"
|
||||
},
|
||||
{
|
||||
revision: 13,
|
||||
version: "1.7.1",
|
||||
description: "Rename Columns",
|
||||
releaseVersion: "0.26.0",
|
||||
compatibleUpToVersion: "0.26.0"
|
||||
},
|
||||
{
|
||||
revision: 14,
|
||||
version: "1.8.0",
|
||||
description: "Add Tags Tables",
|
||||
releaseVersion: "0.27.0",
|
||||
compatibleUpToVersion: "0.27.0"
|
||||
}
|
||||
];
|
||||
|
||||
|
||||
@@ -696,14 +696,12 @@ CREATE INDEX IF NOT EXISTS "IX_Attachments_ItemId" ON "Attachments" ("ItemId");
|
||||
|
||||
CREATE TABLE "FieldDefinitions" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_FieldDefinitions" PRIMARY KEY,
|
||||
"FieldKey" TEXT NULL,
|
||||
"EntityType" TEXT NULL,
|
||||
"FieldType" TEXT NOT NULL,
|
||||
"Label" TEXT NOT NULL,
|
||||
"IsMultiValue" INTEGER NOT NULL,
|
||||
"DefaultVisibility" TEXT NULL,
|
||||
"IsHidden" INTEGER NOT NULL,
|
||||
"EnableHistory" INTEGER NOT NULL,
|
||||
"DisplayOrder" INTEGER NOT NULL,
|
||||
"Weight" INTEGER NOT NULL,
|
||||
"ApplicableToTypes" TEXT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
@@ -714,7 +712,7 @@ CREATE TABLE "Folders" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_Folders" PRIMARY KEY,
|
||||
"Name" TEXT NOT NULL,
|
||||
"ParentFolderId" TEXT NULL,
|
||||
"DisplayOrder" INTEGER NOT NULL,
|
||||
"Weight" INTEGER NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL,
|
||||
@@ -732,6 +730,16 @@ CREATE TABLE "Logos" (
|
||||
"IsDeleted" INTEGER NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE "Tags" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_Tags" PRIMARY KEY,
|
||||
"Name" TEXT NOT NULL,
|
||||
"Color" TEXT NULL,
|
||||
"DisplayOrder" INTEGER NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE "Items" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_Items" PRIMARY KEY,
|
||||
"Name" TEXT NULL,
|
||||
@@ -761,9 +769,10 @@ CREATE TABLE "FieldHistories" (
|
||||
CREATE TABLE "FieldValues" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_FieldValues" PRIMARY KEY,
|
||||
"ItemId" TEXT NOT NULL,
|
||||
"FieldDefinitionId" TEXT NOT NULL,
|
||||
"FieldDefinitionId" TEXT NULL,
|
||||
"FieldKey" TEXT NULL,
|
||||
"Value" TEXT NULL,
|
||||
"ValueIndex" INTEGER NOT NULL,
|
||||
"Weight" INTEGER NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL,
|
||||
@@ -771,7 +780,16 @@ CREATE TABLE "FieldValues" (
|
||||
CONSTRAINT "FK_FieldValues_Items_ItemId" FOREIGN KEY ("ItemId") REFERENCES "Items" ("Id") ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE INDEX "IX_FieldDefinitions_FieldKey" ON "FieldDefinitions" ("FieldKey");
|
||||
CREATE TABLE "ItemTags" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_ItemTags" PRIMARY KEY,
|
||||
"ItemId" TEXT NOT NULL,
|
||||
"TagId" TEXT NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL,
|
||||
CONSTRAINT "FK_ItemTags_Items_ItemId" FOREIGN KEY ("ItemId") REFERENCES "Items" ("Id") ON DELETE CASCADE,
|
||||
CONSTRAINT "FK_ItemTags_Tags_TagId" FOREIGN KEY ("TagId") REFERENCES "Tags" ("Id") ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE INDEX "IX_FieldHistories_FieldDefinitionId" ON "FieldHistories" ("FieldDefinitionId");
|
||||
|
||||
@@ -779,9 +797,13 @@ CREATE INDEX "IX_FieldHistories_ItemId" ON "FieldHistories" ("ItemId");
|
||||
|
||||
CREATE INDEX "IX_FieldValues_FieldDefinitionId" ON "FieldValues" ("FieldDefinitionId");
|
||||
|
||||
CREATE INDEX "IX_FieldValues_FieldKey" ON "FieldValues" ("FieldKey");
|
||||
|
||||
CREATE INDEX "IX_FieldValues_ItemId" ON "FieldValues" ("ItemId");
|
||||
|
||||
CREATE INDEX "IX_FieldValues_ItemId_FieldDefinitionId_ValueIndex" ON "FieldValues" ("ItemId", "FieldDefinitionId", "ValueIndex");
|
||||
CREATE INDEX "IX_FieldValues_ItemId_FieldDefinitionId_Weight" ON "FieldValues" ("ItemId", "FieldDefinitionId", "Weight");
|
||||
|
||||
CREATE INDEX "IX_FieldValues_ItemId_FieldKey" ON "FieldValues" ("ItemId", "FieldKey");
|
||||
|
||||
CREATE INDEX "IX_Folders_ParentFolderId" ON "Folders" ("ParentFolderId");
|
||||
|
||||
@@ -789,27 +811,15 @@ CREATE INDEX "IX_Items_FolderId" ON "Items" ("FolderId");
|
||||
|
||||
CREATE INDEX "IX_Items_LogoId" ON "Items" ("LogoId");
|
||||
|
||||
CREATE INDEX "IX_ItemTags_ItemId" ON "ItemTags" ("ItemId");
|
||||
|
||||
CREATE UNIQUE INDEX "IX_ItemTags_ItemId_TagId" ON "ItemTags" ("ItemId", "TagId");
|
||||
|
||||
CREATE INDEX "IX_ItemTags_TagId" ON "ItemTags" ("TagId");
|
||||
|
||||
CREATE UNIQUE INDEX "IX_Logos_Source" ON "Logos" ("Source");
|
||||
|
||||
|
||||
-- Login fields
|
||||
INSERT INTO FieldDefinitions (Id, FieldKey, EntityType, FieldType, Label, IsMultiValue, DefaultVisibility, EnableHistory, DisplayOrder, ApplicableToTypes, CreatedAt, UpdatedAt, IsDeleted)
|
||||
VALUES
|
||||
(lower(hex(randomblob(16))), 'login.username', 'Item', 'Text', 'Username', 0, 'Visible', 1, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'login.password', 'Item', 'Password', 'Password', 0, 'Hidden', 1, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'login.notes', 'Item', 'Text', 'Notes', 0, 'Collapsed', 0, 0, NULL, datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'login.url', 'Item', 'URL', 'Website URLs', 1, 'Visible', 0, 0, '["Login"]', datetime('now'), datetime('now'), 0);
|
||||
|
||||
-- Alias fields
|
||||
INSERT INTO FieldDefinitions (Id, FieldKey, EntityType, FieldType, Label, IsMultiValue, DefaultVisibility, EnableHistory, DisplayOrder, ApplicableToTypes, CreatedAt, UpdatedAt, IsDeleted)
|
||||
VALUES
|
||||
(lower(hex(randomblob(16))), 'alias.email', 'Item', 'Email', 'Alias Email', 0, 'Visible', 1, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'alias.first_name', 'Item', 'Text', 'First Name', 0, 'Visible', 0, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'alias.last_name', 'Item', 'Text', 'Last Name', 0, 'Visible', 0, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'alias.nickname', 'Item', 'Text', 'Nickname', 0, 'Visible', 0, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'alias.gender', 'Item', 'Text', 'Gender', 0, 'Visible', 0, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'alias.birthdate', 'Item', 'Date', 'Birth Date', 0, 'Visible', 0, 0, '["Login"]', datetime('now'), datetime('now'), 0);
|
||||
|
||||
CREATE INDEX "IX_Tags_Name" ON "Tags" ("Name");
|
||||
|
||||
|
||||
INSERT INTO Items (Id, Name, ItemType, LogoId, FolderId, CreatedAt, UpdatedAt, IsDeleted)
|
||||
@@ -859,13 +869,14 @@ CREATE UNIQUE INDEX "IX_Logos_Source" ON "Logos" ("Source");
|
||||
|
||||
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'login.url' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'login.url' AS FieldKey,
|
||||
s.Url AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
s.UpdatedAt AS CreatedAt,
|
||||
s.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
@@ -875,13 +886,14 @@ CREATE UNIQUE INDEX "IX_Logos_Source" ON "Logos" ("Source");
|
||||
|
||||
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'login.username' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'login.username' AS FieldKey,
|
||||
c.Username AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
c.UpdatedAt AS CreatedAt,
|
||||
c.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
@@ -890,13 +902,14 @@ CREATE UNIQUE INDEX "IX_Logos_Source" ON "Logos" ("Source");
|
||||
|
||||
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'login.notes' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'login.notes' AS FieldKey,
|
||||
c.Notes AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
c.UpdatedAt AS CreatedAt,
|
||||
c.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
@@ -905,130 +918,121 @@ CREATE UNIQUE INDEX "IX_Logos_Source" ON "Logos" ("Source");
|
||||
|
||||
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
p.CredentialId AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'login.password' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'login.password' AS FieldKey,
|
||||
p.Value AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
p.UpdatedAt AS CreatedAt,
|
||||
p.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Passwords p
|
||||
INNER JOIN (
|
||||
SELECT CredentialId, MAX(UpdatedAt) AS MaxUpdated
|
||||
SELECT CredentialId, MAX(UpdatedAt) AS MaxUpdated, MAX(Id) AS MaxId
|
||||
FROM Passwords
|
||||
WHERE IsDeleted = 0
|
||||
GROUP BY CredentialId
|
||||
) pm ON p.CredentialId = pm.CredentialId AND p.UpdatedAt = pm.MaxUpdated;
|
||||
) pm ON p.CredentialId = pm.CredentialId AND p.UpdatedAt = pm.MaxUpdated AND p.Id = pm.MaxId
|
||||
WHERE p.IsDeleted = 0;
|
||||
|
||||
|
||||
|
||||
INSERT INTO FieldHistories (Id, ItemId, FieldDefinitionId, ValueSnapshot, ChangedAt, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
p.CredentialId AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'login.password' LIMIT 1) AS FieldDefinitionId,
|
||||
'{"values":["' || p.Value || '"]}' AS ValueSnapshot,
|
||||
p.UpdatedAt AS ChangedAt,
|
||||
p.CreatedAt AS CreatedAt,
|
||||
p.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Passwords p
|
||||
WHERE p.Id NOT IN (
|
||||
SELECT p2.Id FROM Passwords p2
|
||||
INNER JOIN (
|
||||
SELECT CredentialId, MAX(UpdatedAt) AS MaxUpdated
|
||||
FROM Passwords
|
||||
GROUP BY CredentialId
|
||||
) pm ON p2.CredentialId = pm.CredentialId AND p2.UpdatedAt = pm.MaxUpdated
|
||||
);
|
||||
|
||||
|
||||
|
||||
-- Migrate Alias.Email
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'alias.email' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'alias.email' AS FieldKey,
|
||||
a.Email AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
a.UpdatedAt AS CreatedAt,
|
||||
a.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Credentials c
|
||||
INNER JOIN Aliases a ON a.Id = c.AliasId
|
||||
WHERE a.Email IS NOT NULL AND a.Email != '';
|
||||
|
||||
|
||||
-- Migrate Alias.FirstName
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'alias.first_name' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'alias.first_name' AS FieldKey,
|
||||
a.FirstName AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
a.UpdatedAt AS CreatedAt,
|
||||
a.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Credentials c
|
||||
INNER JOIN Aliases a ON a.Id = c.AliasId
|
||||
WHERE a.FirstName IS NOT NULL AND a.FirstName != '';
|
||||
|
||||
|
||||
-- Migrate Alias.LastName
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'alias.last_name' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'alias.last_name' AS FieldKey,
|
||||
a.LastName AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
a.UpdatedAt AS CreatedAt,
|
||||
a.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Credentials c
|
||||
INNER JOIN Aliases a ON a.Id = c.AliasId
|
||||
WHERE a.LastName IS NOT NULL AND a.LastName != '';
|
||||
|
||||
|
||||
-- Migrate Alias.NickName
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'alias.nickname' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'alias.nickname' AS FieldKey,
|
||||
a.NickName AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
a.UpdatedAt AS CreatedAt,
|
||||
a.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Credentials c
|
||||
INNER JOIN Aliases a ON a.Id = c.AliasId
|
||||
WHERE a.NickName IS NOT NULL AND a.NickName != '';
|
||||
|
||||
|
||||
-- Migrate Alias.Gender
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'alias.gender' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'alias.gender' AS FieldKey,
|
||||
a.Gender AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
a.UpdatedAt AS CreatedAt,
|
||||
a.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Credentials c
|
||||
INNER JOIN Aliases a ON a.Id = c.AliasId
|
||||
WHERE a.Gender IS NOT NULL AND a.Gender != '';
|
||||
|
||||
|
||||
-- Migrate Alias.BirthDate
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'alias.birthdate' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'alias.birthdate' AS FieldKey,
|
||||
a.BirthDate AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
a.UpdatedAt AS CreatedAt,
|
||||
a.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
@@ -1128,95 +1132,7 @@ CREATE INDEX "IX_TotpCodes_ItemId" ON "TotpCodes" ("ItemId");
|
||||
COMMIT;
|
||||
|
||||
INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion")
|
||||
VALUES ('20251126211441_1.7.0-FieldBasedDataModelUpdate', '9.0.4');
|
||||
|
||||
BEGIN TRANSACTION;
|
||||
ALTER TABLE "Folders" RENAME COLUMN "DisplayOrder" TO "Weight";
|
||||
|
||||
ALTER TABLE "FieldValues" RENAME COLUMN "ValueIndex" TO "Weight";
|
||||
|
||||
DROP INDEX "IX_FieldValues_ItemId_FieldDefinitionId_ValueIndex";
|
||||
|
||||
CREATE INDEX "IX_FieldValues_ItemId_FieldDefinitionId_Weight" ON "FieldValues" ("ItemId", "FieldDefinitionId", "Weight");
|
||||
|
||||
ALTER TABLE "FieldDefinitions" RENAME COLUMN "DisplayOrder" TO "Weight";
|
||||
|
||||
ALTER TABLE "FieldDefinitions" ADD "IsHidden" INTEGER NOT NULL DEFAULT 0;
|
||||
|
||||
CREATE TABLE "ef_temp_FieldDefinitions" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_FieldDefinitions" PRIMARY KEY,
|
||||
"ApplicableToTypes" TEXT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"EnableHistory" INTEGER NOT NULL,
|
||||
"FieldKey" TEXT NULL,
|
||||
"FieldType" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL,
|
||||
"IsHidden" INTEGER NOT NULL,
|
||||
"IsMultiValue" INTEGER NOT NULL,
|
||||
"Label" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"Weight" INTEGER NOT NULL
|
||||
);
|
||||
|
||||
INSERT INTO "ef_temp_FieldDefinitions" ("Id", "ApplicableToTypes", "CreatedAt", "EnableHistory", "FieldKey", "FieldType", "IsDeleted", "IsHidden", "IsMultiValue", "Label", "UpdatedAt", "Weight")
|
||||
SELECT "Id", "ApplicableToTypes", "CreatedAt", "EnableHistory", "FieldKey", "FieldType", "IsDeleted", "IsHidden", "IsMultiValue", "Label", "UpdatedAt", "Weight"
|
||||
FROM "FieldDefinitions";
|
||||
|
||||
COMMIT;
|
||||
|
||||
PRAGMA foreign_keys = 0;
|
||||
|
||||
BEGIN TRANSACTION;
|
||||
DROP TABLE "FieldDefinitions";
|
||||
|
||||
ALTER TABLE "ef_temp_FieldDefinitions" RENAME TO "FieldDefinitions";
|
||||
|
||||
COMMIT;
|
||||
|
||||
PRAGMA foreign_keys = 1;
|
||||
|
||||
BEGIN TRANSACTION;
|
||||
CREATE INDEX "IX_FieldDefinitions_FieldKey" ON "FieldDefinitions" ("FieldKey");
|
||||
|
||||
COMMIT;
|
||||
|
||||
INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion")
|
||||
VALUES ('20251126221717_1.7.1-RenameColumns', '9.0.4');
|
||||
|
||||
BEGIN TRANSACTION;
|
||||
CREATE TABLE "Tags" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_Tags" PRIMARY KEY,
|
||||
"Name" TEXT NOT NULL,
|
||||
"Color" TEXT NULL,
|
||||
"DisplayOrder" INTEGER NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE "ItemTags" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_ItemTags" PRIMARY KEY,
|
||||
"ItemId" TEXT NOT NULL,
|
||||
"TagId" TEXT NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL,
|
||||
CONSTRAINT "FK_ItemTags_Items_ItemId" FOREIGN KEY ("ItemId") REFERENCES "Items" ("Id") ON DELETE CASCADE,
|
||||
CONSTRAINT "FK_ItemTags_Tags_TagId" FOREIGN KEY ("TagId") REFERENCES "Tags" ("Id") ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE INDEX "IX_ItemTags_ItemId" ON "ItemTags" ("ItemId");
|
||||
|
||||
CREATE UNIQUE INDEX "IX_ItemTags_ItemId_TagId" ON "ItemTags" ("ItemId", "TagId");
|
||||
|
||||
CREATE INDEX "IX_ItemTags_TagId" ON "ItemTags" ("TagId");
|
||||
|
||||
CREATE INDEX "IX_Tags_Name" ON "Tags" ("Name");
|
||||
|
||||
INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion")
|
||||
VALUES ('20251202211204_1.7.2-AddTagTables', '9.0.4');
|
||||
|
||||
COMMIT;
|
||||
VALUES ('20251203162345_1.7.0-FieldBasedDataModelUpdate', '9.0.4');
|
||||
`;
|
||||
var MIGRATION_SCRIPTS = {
|
||||
1: `\uFEFFBEGIN TRANSACTION;
|
||||
@@ -1846,14 +1762,12 @@ CREATE INDEX IF NOT EXISTS "IX_Attachments_ItemId" ON "Attachments" ("ItemId");
|
||||
|
||||
CREATE TABLE "FieldDefinitions" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_FieldDefinitions" PRIMARY KEY,
|
||||
"FieldKey" TEXT NULL,
|
||||
"EntityType" TEXT NULL,
|
||||
"FieldType" TEXT NOT NULL,
|
||||
"Label" TEXT NOT NULL,
|
||||
"IsMultiValue" INTEGER NOT NULL,
|
||||
"DefaultVisibility" TEXT NULL,
|
||||
"IsHidden" INTEGER NOT NULL,
|
||||
"EnableHistory" INTEGER NOT NULL,
|
||||
"DisplayOrder" INTEGER NOT NULL,
|
||||
"Weight" INTEGER NOT NULL,
|
||||
"ApplicableToTypes" TEXT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
@@ -1864,7 +1778,7 @@ CREATE TABLE "Folders" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_Folders" PRIMARY KEY,
|
||||
"Name" TEXT NOT NULL,
|
||||
"ParentFolderId" TEXT NULL,
|
||||
"DisplayOrder" INTEGER NOT NULL,
|
||||
"Weight" INTEGER NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL,
|
||||
@@ -1882,6 +1796,16 @@ CREATE TABLE "Logos" (
|
||||
"IsDeleted" INTEGER NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE "Tags" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_Tags" PRIMARY KEY,
|
||||
"Name" TEXT NOT NULL,
|
||||
"Color" TEXT NULL,
|
||||
"DisplayOrder" INTEGER NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE "Items" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_Items" PRIMARY KEY,
|
||||
"Name" TEXT NULL,
|
||||
@@ -1911,9 +1835,10 @@ CREATE TABLE "FieldHistories" (
|
||||
CREATE TABLE "FieldValues" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_FieldValues" PRIMARY KEY,
|
||||
"ItemId" TEXT NOT NULL,
|
||||
"FieldDefinitionId" TEXT NOT NULL,
|
||||
"FieldDefinitionId" TEXT NULL,
|
||||
"FieldKey" TEXT NULL,
|
||||
"Value" TEXT NULL,
|
||||
"ValueIndex" INTEGER NOT NULL,
|
||||
"Weight" INTEGER NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL,
|
||||
@@ -1921,7 +1846,16 @@ CREATE TABLE "FieldValues" (
|
||||
CONSTRAINT "FK_FieldValues_Items_ItemId" FOREIGN KEY ("ItemId") REFERENCES "Items" ("Id") ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE INDEX "IX_FieldDefinitions_FieldKey" ON "FieldDefinitions" ("FieldKey");
|
||||
CREATE TABLE "ItemTags" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_ItemTags" PRIMARY KEY,
|
||||
"ItemId" TEXT NOT NULL,
|
||||
"TagId" TEXT NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL,
|
||||
CONSTRAINT "FK_ItemTags_Items_ItemId" FOREIGN KEY ("ItemId") REFERENCES "Items" ("Id") ON DELETE CASCADE,
|
||||
CONSTRAINT "FK_ItemTags_Tags_TagId" FOREIGN KEY ("TagId") REFERENCES "Tags" ("Id") ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE INDEX "IX_FieldHistories_FieldDefinitionId" ON "FieldHistories" ("FieldDefinitionId");
|
||||
|
||||
@@ -1929,9 +1863,13 @@ CREATE INDEX "IX_FieldHistories_ItemId" ON "FieldHistories" ("ItemId");
|
||||
|
||||
CREATE INDEX "IX_FieldValues_FieldDefinitionId" ON "FieldValues" ("FieldDefinitionId");
|
||||
|
||||
CREATE INDEX "IX_FieldValues_FieldKey" ON "FieldValues" ("FieldKey");
|
||||
|
||||
CREATE INDEX "IX_FieldValues_ItemId" ON "FieldValues" ("ItemId");
|
||||
|
||||
CREATE INDEX "IX_FieldValues_ItemId_FieldDefinitionId_ValueIndex" ON "FieldValues" ("ItemId", "FieldDefinitionId", "ValueIndex");
|
||||
CREATE INDEX "IX_FieldValues_ItemId_FieldDefinitionId_Weight" ON "FieldValues" ("ItemId", "FieldDefinitionId", "Weight");
|
||||
|
||||
CREATE INDEX "IX_FieldValues_ItemId_FieldKey" ON "FieldValues" ("ItemId", "FieldKey");
|
||||
|
||||
CREATE INDEX "IX_Folders_ParentFolderId" ON "Folders" ("ParentFolderId");
|
||||
|
||||
@@ -1939,27 +1877,15 @@ CREATE INDEX "IX_Items_FolderId" ON "Items" ("FolderId");
|
||||
|
||||
CREATE INDEX "IX_Items_LogoId" ON "Items" ("LogoId");
|
||||
|
||||
CREATE INDEX "IX_ItemTags_ItemId" ON "ItemTags" ("ItemId");
|
||||
|
||||
CREATE UNIQUE INDEX "IX_ItemTags_ItemId_TagId" ON "ItemTags" ("ItemId", "TagId");
|
||||
|
||||
CREATE INDEX "IX_ItemTags_TagId" ON "ItemTags" ("TagId");
|
||||
|
||||
CREATE UNIQUE INDEX "IX_Logos_Source" ON "Logos" ("Source");
|
||||
|
||||
|
||||
-- Login fields
|
||||
INSERT INTO FieldDefinitions (Id, FieldKey, EntityType, FieldType, Label, IsMultiValue, DefaultVisibility, EnableHistory, DisplayOrder, ApplicableToTypes, CreatedAt, UpdatedAt, IsDeleted)
|
||||
VALUES
|
||||
(lower(hex(randomblob(16))), 'login.username', 'Item', 'Text', 'Username', 0, 'Visible', 1, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'login.password', 'Item', 'Password', 'Password', 0, 'Hidden', 1, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'login.notes', 'Item', 'Text', 'Notes', 0, 'Collapsed', 0, 0, NULL, datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'login.url', 'Item', 'URL', 'Website URLs', 1, 'Visible', 0, 0, '["Login"]', datetime('now'), datetime('now'), 0);
|
||||
|
||||
-- Alias fields
|
||||
INSERT INTO FieldDefinitions (Id, FieldKey, EntityType, FieldType, Label, IsMultiValue, DefaultVisibility, EnableHistory, DisplayOrder, ApplicableToTypes, CreatedAt, UpdatedAt, IsDeleted)
|
||||
VALUES
|
||||
(lower(hex(randomblob(16))), 'alias.email', 'Item', 'Email', 'Alias Email', 0, 'Visible', 1, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'alias.first_name', 'Item', 'Text', 'First Name', 0, 'Visible', 0, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'alias.last_name', 'Item', 'Text', 'Last Name', 0, 'Visible', 0, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'alias.nickname', 'Item', 'Text', 'Nickname', 0, 'Visible', 0, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'alias.gender', 'Item', 'Text', 'Gender', 0, 'Visible', 0, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'alias.birthdate', 'Item', 'Date', 'Birth Date', 0, 'Visible', 0, 0, '["Login"]', datetime('now'), datetime('now'), 0);
|
||||
|
||||
CREATE INDEX "IX_Tags_Name" ON "Tags" ("Name");
|
||||
|
||||
|
||||
INSERT INTO Items (Id, Name, ItemType, LogoId, FolderId, CreatedAt, UpdatedAt, IsDeleted)
|
||||
@@ -2009,13 +1935,14 @@ CREATE UNIQUE INDEX "IX_Logos_Source" ON "Logos" ("Source");
|
||||
|
||||
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'login.url' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'login.url' AS FieldKey,
|
||||
s.Url AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
s.UpdatedAt AS CreatedAt,
|
||||
s.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
@@ -2025,13 +1952,14 @@ CREATE UNIQUE INDEX "IX_Logos_Source" ON "Logos" ("Source");
|
||||
|
||||
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'login.username' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'login.username' AS FieldKey,
|
||||
c.Username AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
c.UpdatedAt AS CreatedAt,
|
||||
c.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
@@ -2040,13 +1968,14 @@ CREATE UNIQUE INDEX "IX_Logos_Source" ON "Logos" ("Source");
|
||||
|
||||
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'login.notes' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'login.notes' AS FieldKey,
|
||||
c.Notes AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
c.UpdatedAt AS CreatedAt,
|
||||
c.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
@@ -2055,130 +1984,121 @@ CREATE UNIQUE INDEX "IX_Logos_Source" ON "Logos" ("Source");
|
||||
|
||||
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
p.CredentialId AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'login.password' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'login.password' AS FieldKey,
|
||||
p.Value AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
p.UpdatedAt AS CreatedAt,
|
||||
p.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Passwords p
|
||||
INNER JOIN (
|
||||
SELECT CredentialId, MAX(UpdatedAt) AS MaxUpdated
|
||||
SELECT CredentialId, MAX(UpdatedAt) AS MaxUpdated, MAX(Id) AS MaxId
|
||||
FROM Passwords
|
||||
WHERE IsDeleted = 0
|
||||
GROUP BY CredentialId
|
||||
) pm ON p.CredentialId = pm.CredentialId AND p.UpdatedAt = pm.MaxUpdated;
|
||||
) pm ON p.CredentialId = pm.CredentialId AND p.UpdatedAt = pm.MaxUpdated AND p.Id = pm.MaxId
|
||||
WHERE p.IsDeleted = 0;
|
||||
|
||||
|
||||
|
||||
INSERT INTO FieldHistories (Id, ItemId, FieldDefinitionId, ValueSnapshot, ChangedAt, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
p.CredentialId AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'login.password' LIMIT 1) AS FieldDefinitionId,
|
||||
'{"values":["' || p.Value || '"]}' AS ValueSnapshot,
|
||||
p.UpdatedAt AS ChangedAt,
|
||||
p.CreatedAt AS CreatedAt,
|
||||
p.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Passwords p
|
||||
WHERE p.Id NOT IN (
|
||||
SELECT p2.Id FROM Passwords p2
|
||||
INNER JOIN (
|
||||
SELECT CredentialId, MAX(UpdatedAt) AS MaxUpdated
|
||||
FROM Passwords
|
||||
GROUP BY CredentialId
|
||||
) pm ON p2.CredentialId = pm.CredentialId AND p2.UpdatedAt = pm.MaxUpdated
|
||||
);
|
||||
|
||||
|
||||
|
||||
-- Migrate Alias.Email
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'alias.email' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'alias.email' AS FieldKey,
|
||||
a.Email AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
a.UpdatedAt AS CreatedAt,
|
||||
a.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Credentials c
|
||||
INNER JOIN Aliases a ON a.Id = c.AliasId
|
||||
WHERE a.Email IS NOT NULL AND a.Email != '';
|
||||
|
||||
|
||||
-- Migrate Alias.FirstName
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'alias.first_name' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'alias.first_name' AS FieldKey,
|
||||
a.FirstName AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
a.UpdatedAt AS CreatedAt,
|
||||
a.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Credentials c
|
||||
INNER JOIN Aliases a ON a.Id = c.AliasId
|
||||
WHERE a.FirstName IS NOT NULL AND a.FirstName != '';
|
||||
|
||||
|
||||
-- Migrate Alias.LastName
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'alias.last_name' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'alias.last_name' AS FieldKey,
|
||||
a.LastName AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
a.UpdatedAt AS CreatedAt,
|
||||
a.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Credentials c
|
||||
INNER JOIN Aliases a ON a.Id = c.AliasId
|
||||
WHERE a.LastName IS NOT NULL AND a.LastName != '';
|
||||
|
||||
|
||||
-- Migrate Alias.NickName
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'alias.nickname' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'alias.nickname' AS FieldKey,
|
||||
a.NickName AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
a.UpdatedAt AS CreatedAt,
|
||||
a.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Credentials c
|
||||
INNER JOIN Aliases a ON a.Id = c.AliasId
|
||||
WHERE a.NickName IS NOT NULL AND a.NickName != '';
|
||||
|
||||
|
||||
-- Migrate Alias.Gender
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'alias.gender' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'alias.gender' AS FieldKey,
|
||||
a.Gender AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
a.UpdatedAt AS CreatedAt,
|
||||
a.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Credentials c
|
||||
INNER JOIN Aliases a ON a.Id = c.AliasId
|
||||
WHERE a.Gender IS NOT NULL AND a.Gender != '';
|
||||
|
||||
|
||||
-- Migrate Alias.BirthDate
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'alias.birthdate' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'alias.birthdate' AS FieldKey,
|
||||
a.BirthDate AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
a.UpdatedAt AS CreatedAt,
|
||||
a.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
@@ -2278,93 +2198,7 @@ CREATE INDEX "IX_TotpCodes_ItemId" ON "TotpCodes" ("ItemId");
|
||||
COMMIT;
|
||||
|
||||
INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion")
|
||||
VALUES ('20251126211441_1.7.0-FieldBasedDataModelUpdate', '9.0.4');`,
|
||||
12: `\uFEFFBEGIN TRANSACTION;
|
||||
ALTER TABLE "Folders" RENAME COLUMN "DisplayOrder" TO "Weight";
|
||||
|
||||
ALTER TABLE "FieldValues" RENAME COLUMN "ValueIndex" TO "Weight";
|
||||
|
||||
DROP INDEX "IX_FieldValues_ItemId_FieldDefinitionId_ValueIndex";
|
||||
|
||||
CREATE INDEX "IX_FieldValues_ItemId_FieldDefinitionId_Weight" ON "FieldValues" ("ItemId", "FieldDefinitionId", "Weight");
|
||||
|
||||
ALTER TABLE "FieldDefinitions" RENAME COLUMN "DisplayOrder" TO "Weight";
|
||||
|
||||
ALTER TABLE "FieldDefinitions" ADD "IsHidden" INTEGER NOT NULL DEFAULT 0;
|
||||
|
||||
CREATE TABLE "ef_temp_FieldDefinitions" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_FieldDefinitions" PRIMARY KEY,
|
||||
"ApplicableToTypes" TEXT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"EnableHistory" INTEGER NOT NULL,
|
||||
"FieldKey" TEXT NULL,
|
||||
"FieldType" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL,
|
||||
"IsHidden" INTEGER NOT NULL,
|
||||
"IsMultiValue" INTEGER NOT NULL,
|
||||
"Label" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"Weight" INTEGER NOT NULL
|
||||
);
|
||||
|
||||
INSERT INTO "ef_temp_FieldDefinitions" ("Id", "ApplicableToTypes", "CreatedAt", "EnableHistory", "FieldKey", "FieldType", "IsDeleted", "IsHidden", "IsMultiValue", "Label", "UpdatedAt", "Weight")
|
||||
SELECT "Id", "ApplicableToTypes", "CreatedAt", "EnableHistory", "FieldKey", "FieldType", "IsDeleted", "IsHidden", "IsMultiValue", "Label", "UpdatedAt", "Weight"
|
||||
FROM "FieldDefinitions";
|
||||
|
||||
COMMIT;
|
||||
|
||||
PRAGMA foreign_keys = 0;
|
||||
|
||||
BEGIN TRANSACTION;
|
||||
DROP TABLE "FieldDefinitions";
|
||||
|
||||
ALTER TABLE "ef_temp_FieldDefinitions" RENAME TO "FieldDefinitions";
|
||||
|
||||
COMMIT;
|
||||
|
||||
PRAGMA foreign_keys = 1;
|
||||
|
||||
BEGIN TRANSACTION;
|
||||
CREATE INDEX "IX_FieldDefinitions_FieldKey" ON "FieldDefinitions" ("FieldKey");
|
||||
|
||||
COMMIT;
|
||||
|
||||
INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion")
|
||||
VALUES ('20251126221717_1.7.1-RenameColumns', '9.0.4');`,
|
||||
13: `\uFEFFBEGIN TRANSACTION;
|
||||
CREATE TABLE "Tags" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_Tags" PRIMARY KEY,
|
||||
"Name" TEXT NOT NULL,
|
||||
"Color" TEXT NULL,
|
||||
"DisplayOrder" INTEGER NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE "ItemTags" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_ItemTags" PRIMARY KEY,
|
||||
"ItemId" TEXT NOT NULL,
|
||||
"TagId" TEXT NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL,
|
||||
CONSTRAINT "FK_ItemTags_Items_ItemId" FOREIGN KEY ("ItemId") REFERENCES "Items" ("Id") ON DELETE CASCADE,
|
||||
CONSTRAINT "FK_ItemTags_Tags_TagId" FOREIGN KEY ("TagId") REFERENCES "Tags" ("Id") ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE INDEX "IX_ItemTags_ItemId" ON "ItemTags" ("ItemId");
|
||||
|
||||
CREATE UNIQUE INDEX "IX_ItemTags_ItemId_TagId" ON "ItemTags" ("ItemId", "TagId");
|
||||
|
||||
CREATE INDEX "IX_ItemTags_TagId" ON "ItemTags" ("TagId");
|
||||
|
||||
CREATE INDEX "IX_Tags_Name" ON "Tags" ("Name");
|
||||
|
||||
INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion")
|
||||
VALUES ('20251202211204_1.7.2-AddTagTables', '9.0.4');
|
||||
|
||||
COMMIT;`
|
||||
VALUES ('20251203162345_1.7.0-FieldBasedDataModelUpdate', '9.0.4');`
|
||||
};
|
||||
|
||||
// src/sql/VaultVersions.ts
|
||||
@@ -2452,20 +2286,6 @@ var VAULT_VERSIONS = [
|
||||
description: "Update to Field-Based Data Model",
|
||||
releaseVersion: "0.26.0",
|
||||
compatibleUpToVersion: "0.26.0"
|
||||
},
|
||||
{
|
||||
revision: 13,
|
||||
version: "1.7.1",
|
||||
description: "Rename Columns",
|
||||
releaseVersion: "0.26.0",
|
||||
compatibleUpToVersion: "0.26.0"
|
||||
},
|
||||
{
|
||||
revision: 14,
|
||||
version: "1.8.0",
|
||||
description: "Add Tags Tables",
|
||||
releaseVersion: "0.27.0",
|
||||
compatibleUpToVersion: "0.27.0"
|
||||
}
|
||||
];
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -728,14 +728,12 @@ CREATE INDEX IF NOT EXISTS "IX_Attachments_ItemId" ON "Attachments" ("ItemId");
|
||||
|
||||
CREATE TABLE "FieldDefinitions" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_FieldDefinitions" PRIMARY KEY,
|
||||
"FieldKey" TEXT NULL,
|
||||
"EntityType" TEXT NULL,
|
||||
"FieldType" TEXT NOT NULL,
|
||||
"Label" TEXT NOT NULL,
|
||||
"IsMultiValue" INTEGER NOT NULL,
|
||||
"DefaultVisibility" TEXT NULL,
|
||||
"IsHidden" INTEGER NOT NULL,
|
||||
"EnableHistory" INTEGER NOT NULL,
|
||||
"DisplayOrder" INTEGER NOT NULL,
|
||||
"Weight" INTEGER NOT NULL,
|
||||
"ApplicableToTypes" TEXT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
@@ -746,7 +744,7 @@ CREATE TABLE "Folders" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_Folders" PRIMARY KEY,
|
||||
"Name" TEXT NOT NULL,
|
||||
"ParentFolderId" TEXT NULL,
|
||||
"DisplayOrder" INTEGER NOT NULL,
|
||||
"Weight" INTEGER NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL,
|
||||
@@ -764,6 +762,16 @@ CREATE TABLE "Logos" (
|
||||
"IsDeleted" INTEGER NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE "Tags" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_Tags" PRIMARY KEY,
|
||||
"Name" TEXT NOT NULL,
|
||||
"Color" TEXT NULL,
|
||||
"DisplayOrder" INTEGER NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE "Items" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_Items" PRIMARY KEY,
|
||||
"Name" TEXT NULL,
|
||||
@@ -793,9 +801,10 @@ CREATE TABLE "FieldHistories" (
|
||||
CREATE TABLE "FieldValues" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_FieldValues" PRIMARY KEY,
|
||||
"ItemId" TEXT NOT NULL,
|
||||
"FieldDefinitionId" TEXT NOT NULL,
|
||||
"FieldDefinitionId" TEXT NULL,
|
||||
"FieldKey" TEXT NULL,
|
||||
"Value" TEXT NULL,
|
||||
"ValueIndex" INTEGER NOT NULL,
|
||||
"Weight" INTEGER NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL,
|
||||
@@ -803,7 +812,16 @@ CREATE TABLE "FieldValues" (
|
||||
CONSTRAINT "FK_FieldValues_Items_ItemId" FOREIGN KEY ("ItemId") REFERENCES "Items" ("Id") ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE INDEX "IX_FieldDefinitions_FieldKey" ON "FieldDefinitions" ("FieldKey");
|
||||
CREATE TABLE "ItemTags" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_ItemTags" PRIMARY KEY,
|
||||
"ItemId" TEXT NOT NULL,
|
||||
"TagId" TEXT NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL,
|
||||
CONSTRAINT "FK_ItemTags_Items_ItemId" FOREIGN KEY ("ItemId") REFERENCES "Items" ("Id") ON DELETE CASCADE,
|
||||
CONSTRAINT "FK_ItemTags_Tags_TagId" FOREIGN KEY ("TagId") REFERENCES "Tags" ("Id") ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE INDEX "IX_FieldHistories_FieldDefinitionId" ON "FieldHistories" ("FieldDefinitionId");
|
||||
|
||||
@@ -811,9 +829,13 @@ CREATE INDEX "IX_FieldHistories_ItemId" ON "FieldHistories" ("ItemId");
|
||||
|
||||
CREATE INDEX "IX_FieldValues_FieldDefinitionId" ON "FieldValues" ("FieldDefinitionId");
|
||||
|
||||
CREATE INDEX "IX_FieldValues_FieldKey" ON "FieldValues" ("FieldKey");
|
||||
|
||||
CREATE INDEX "IX_FieldValues_ItemId" ON "FieldValues" ("ItemId");
|
||||
|
||||
CREATE INDEX "IX_FieldValues_ItemId_FieldDefinitionId_ValueIndex" ON "FieldValues" ("ItemId", "FieldDefinitionId", "ValueIndex");
|
||||
CREATE INDEX "IX_FieldValues_ItemId_FieldDefinitionId_Weight" ON "FieldValues" ("ItemId", "FieldDefinitionId", "Weight");
|
||||
|
||||
CREATE INDEX "IX_FieldValues_ItemId_FieldKey" ON "FieldValues" ("ItemId", "FieldKey");
|
||||
|
||||
CREATE INDEX "IX_Folders_ParentFolderId" ON "Folders" ("ParentFolderId");
|
||||
|
||||
@@ -821,27 +843,15 @@ CREATE INDEX "IX_Items_FolderId" ON "Items" ("FolderId");
|
||||
|
||||
CREATE INDEX "IX_Items_LogoId" ON "Items" ("LogoId");
|
||||
|
||||
CREATE INDEX "IX_ItemTags_ItemId" ON "ItemTags" ("ItemId");
|
||||
|
||||
CREATE UNIQUE INDEX "IX_ItemTags_ItemId_TagId" ON "ItemTags" ("ItemId", "TagId");
|
||||
|
||||
CREATE INDEX "IX_ItemTags_TagId" ON "ItemTags" ("TagId");
|
||||
|
||||
CREATE UNIQUE INDEX "IX_Logos_Source" ON "Logos" ("Source");
|
||||
|
||||
|
||||
-- Login fields
|
||||
INSERT INTO FieldDefinitions (Id, FieldKey, EntityType, FieldType, Label, IsMultiValue, DefaultVisibility, EnableHistory, DisplayOrder, ApplicableToTypes, CreatedAt, UpdatedAt, IsDeleted)
|
||||
VALUES
|
||||
(lower(hex(randomblob(16))), 'login.username', 'Item', 'Text', 'Username', 0, 'Visible', 1, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'login.password', 'Item', 'Password', 'Password', 0, 'Hidden', 1, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'login.notes', 'Item', 'Text', 'Notes', 0, 'Collapsed', 0, 0, NULL, datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'login.url', 'Item', 'URL', 'Website URLs', 1, 'Visible', 0, 0, '["Login"]', datetime('now'), datetime('now'), 0);
|
||||
|
||||
-- Alias fields
|
||||
INSERT INTO FieldDefinitions (Id, FieldKey, EntityType, FieldType, Label, IsMultiValue, DefaultVisibility, EnableHistory, DisplayOrder, ApplicableToTypes, CreatedAt, UpdatedAt, IsDeleted)
|
||||
VALUES
|
||||
(lower(hex(randomblob(16))), 'alias.email', 'Item', 'Email', 'Alias Email', 0, 'Visible', 1, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'alias.first_name', 'Item', 'Text', 'First Name', 0, 'Visible', 0, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'alias.last_name', 'Item', 'Text', 'Last Name', 0, 'Visible', 0, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'alias.nickname', 'Item', 'Text', 'Nickname', 0, 'Visible', 0, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'alias.gender', 'Item', 'Text', 'Gender', 0, 'Visible', 0, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'alias.birthdate', 'Item', 'Date', 'Birth Date', 0, 'Visible', 0, 0, '["Login"]', datetime('now'), datetime('now'), 0);
|
||||
|
||||
CREATE INDEX "IX_Tags_Name" ON "Tags" ("Name");
|
||||
|
||||
|
||||
INSERT INTO Items (Id, Name, ItemType, LogoId, FolderId, CreatedAt, UpdatedAt, IsDeleted)
|
||||
@@ -891,13 +901,14 @@ CREATE UNIQUE INDEX "IX_Logos_Source" ON "Logos" ("Source");
|
||||
|
||||
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'login.url' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'login.url' AS FieldKey,
|
||||
s.Url AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
s.UpdatedAt AS CreatedAt,
|
||||
s.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
@@ -907,13 +918,14 @@ CREATE UNIQUE INDEX "IX_Logos_Source" ON "Logos" ("Source");
|
||||
|
||||
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'login.username' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'login.username' AS FieldKey,
|
||||
c.Username AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
c.UpdatedAt AS CreatedAt,
|
||||
c.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
@@ -922,13 +934,14 @@ CREATE UNIQUE INDEX "IX_Logos_Source" ON "Logos" ("Source");
|
||||
|
||||
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'login.notes' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'login.notes' AS FieldKey,
|
||||
c.Notes AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
c.UpdatedAt AS CreatedAt,
|
||||
c.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
@@ -937,130 +950,121 @@ CREATE UNIQUE INDEX "IX_Logos_Source" ON "Logos" ("Source");
|
||||
|
||||
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
p.CredentialId AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'login.password' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'login.password' AS FieldKey,
|
||||
p.Value AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
p.UpdatedAt AS CreatedAt,
|
||||
p.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Passwords p
|
||||
INNER JOIN (
|
||||
SELECT CredentialId, MAX(UpdatedAt) AS MaxUpdated
|
||||
SELECT CredentialId, MAX(UpdatedAt) AS MaxUpdated, MAX(Id) AS MaxId
|
||||
FROM Passwords
|
||||
WHERE IsDeleted = 0
|
||||
GROUP BY CredentialId
|
||||
) pm ON p.CredentialId = pm.CredentialId AND p.UpdatedAt = pm.MaxUpdated;
|
||||
) pm ON p.CredentialId = pm.CredentialId AND p.UpdatedAt = pm.MaxUpdated AND p.Id = pm.MaxId
|
||||
WHERE p.IsDeleted = 0;
|
||||
|
||||
|
||||
|
||||
INSERT INTO FieldHistories (Id, ItemId, FieldDefinitionId, ValueSnapshot, ChangedAt, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
p.CredentialId AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'login.password' LIMIT 1) AS FieldDefinitionId,
|
||||
'{"values":["' || p.Value || '"]}' AS ValueSnapshot,
|
||||
p.UpdatedAt AS ChangedAt,
|
||||
p.CreatedAt AS CreatedAt,
|
||||
p.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Passwords p
|
||||
WHERE p.Id NOT IN (
|
||||
SELECT p2.Id FROM Passwords p2
|
||||
INNER JOIN (
|
||||
SELECT CredentialId, MAX(UpdatedAt) AS MaxUpdated
|
||||
FROM Passwords
|
||||
GROUP BY CredentialId
|
||||
) pm ON p2.CredentialId = pm.CredentialId AND p2.UpdatedAt = pm.MaxUpdated
|
||||
);
|
||||
|
||||
|
||||
|
||||
-- Migrate Alias.Email
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'alias.email' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'alias.email' AS FieldKey,
|
||||
a.Email AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
a.UpdatedAt AS CreatedAt,
|
||||
a.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Credentials c
|
||||
INNER JOIN Aliases a ON a.Id = c.AliasId
|
||||
WHERE a.Email IS NOT NULL AND a.Email != '';
|
||||
|
||||
|
||||
-- Migrate Alias.FirstName
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'alias.first_name' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'alias.first_name' AS FieldKey,
|
||||
a.FirstName AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
a.UpdatedAt AS CreatedAt,
|
||||
a.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Credentials c
|
||||
INNER JOIN Aliases a ON a.Id = c.AliasId
|
||||
WHERE a.FirstName IS NOT NULL AND a.FirstName != '';
|
||||
|
||||
|
||||
-- Migrate Alias.LastName
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'alias.last_name' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'alias.last_name' AS FieldKey,
|
||||
a.LastName AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
a.UpdatedAt AS CreatedAt,
|
||||
a.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Credentials c
|
||||
INNER JOIN Aliases a ON a.Id = c.AliasId
|
||||
WHERE a.LastName IS NOT NULL AND a.LastName != '';
|
||||
|
||||
|
||||
-- Migrate Alias.NickName
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'alias.nickname' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'alias.nickname' AS FieldKey,
|
||||
a.NickName AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
a.UpdatedAt AS CreatedAt,
|
||||
a.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Credentials c
|
||||
INNER JOIN Aliases a ON a.Id = c.AliasId
|
||||
WHERE a.NickName IS NOT NULL AND a.NickName != '';
|
||||
|
||||
|
||||
-- Migrate Alias.Gender
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'alias.gender' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'alias.gender' AS FieldKey,
|
||||
a.Gender AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
a.UpdatedAt AS CreatedAt,
|
||||
a.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Credentials c
|
||||
INNER JOIN Aliases a ON a.Id = c.AliasId
|
||||
WHERE a.Gender IS NOT NULL AND a.Gender != '';
|
||||
|
||||
|
||||
-- Migrate Alias.BirthDate
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'alias.birthdate' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'alias.birthdate' AS FieldKey,
|
||||
a.BirthDate AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
a.UpdatedAt AS CreatedAt,
|
||||
a.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
@@ -1160,95 +1164,7 @@ CREATE INDEX "IX_TotpCodes_ItemId" ON "TotpCodes" ("ItemId");
|
||||
COMMIT;
|
||||
|
||||
INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion")
|
||||
VALUES ('20251126211441_1.7.0-FieldBasedDataModelUpdate', '9.0.4');
|
||||
|
||||
BEGIN TRANSACTION;
|
||||
ALTER TABLE "Folders" RENAME COLUMN "DisplayOrder" TO "Weight";
|
||||
|
||||
ALTER TABLE "FieldValues" RENAME COLUMN "ValueIndex" TO "Weight";
|
||||
|
||||
DROP INDEX "IX_FieldValues_ItemId_FieldDefinitionId_ValueIndex";
|
||||
|
||||
CREATE INDEX "IX_FieldValues_ItemId_FieldDefinitionId_Weight" ON "FieldValues" ("ItemId", "FieldDefinitionId", "Weight");
|
||||
|
||||
ALTER TABLE "FieldDefinitions" RENAME COLUMN "DisplayOrder" TO "Weight";
|
||||
|
||||
ALTER TABLE "FieldDefinitions" ADD "IsHidden" INTEGER NOT NULL DEFAULT 0;
|
||||
|
||||
CREATE TABLE "ef_temp_FieldDefinitions" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_FieldDefinitions" PRIMARY KEY,
|
||||
"ApplicableToTypes" TEXT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"EnableHistory" INTEGER NOT NULL,
|
||||
"FieldKey" TEXT NULL,
|
||||
"FieldType" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL,
|
||||
"IsHidden" INTEGER NOT NULL,
|
||||
"IsMultiValue" INTEGER NOT NULL,
|
||||
"Label" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"Weight" INTEGER NOT NULL
|
||||
);
|
||||
|
||||
INSERT INTO "ef_temp_FieldDefinitions" ("Id", "ApplicableToTypes", "CreatedAt", "EnableHistory", "FieldKey", "FieldType", "IsDeleted", "IsHidden", "IsMultiValue", "Label", "UpdatedAt", "Weight")
|
||||
SELECT "Id", "ApplicableToTypes", "CreatedAt", "EnableHistory", "FieldKey", "FieldType", "IsDeleted", "IsHidden", "IsMultiValue", "Label", "UpdatedAt", "Weight"
|
||||
FROM "FieldDefinitions";
|
||||
|
||||
COMMIT;
|
||||
|
||||
PRAGMA foreign_keys = 0;
|
||||
|
||||
BEGIN TRANSACTION;
|
||||
DROP TABLE "FieldDefinitions";
|
||||
|
||||
ALTER TABLE "ef_temp_FieldDefinitions" RENAME TO "FieldDefinitions";
|
||||
|
||||
COMMIT;
|
||||
|
||||
PRAGMA foreign_keys = 1;
|
||||
|
||||
BEGIN TRANSACTION;
|
||||
CREATE INDEX "IX_FieldDefinitions_FieldKey" ON "FieldDefinitions" ("FieldKey");
|
||||
|
||||
COMMIT;
|
||||
|
||||
INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion")
|
||||
VALUES ('20251126221717_1.7.1-RenameColumns', '9.0.4');
|
||||
|
||||
BEGIN TRANSACTION;
|
||||
CREATE TABLE "Tags" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_Tags" PRIMARY KEY,
|
||||
"Name" TEXT NOT NULL,
|
||||
"Color" TEXT NULL,
|
||||
"DisplayOrder" INTEGER NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE "ItemTags" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_ItemTags" PRIMARY KEY,
|
||||
"ItemId" TEXT NOT NULL,
|
||||
"TagId" TEXT NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL,
|
||||
CONSTRAINT "FK_ItemTags_Items_ItemId" FOREIGN KEY ("ItemId") REFERENCES "Items" ("Id") ON DELETE CASCADE,
|
||||
CONSTRAINT "FK_ItemTags_Tags_TagId" FOREIGN KEY ("TagId") REFERENCES "Tags" ("Id") ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE INDEX "IX_ItemTags_ItemId" ON "ItemTags" ("ItemId");
|
||||
|
||||
CREATE UNIQUE INDEX "IX_ItemTags_ItemId_TagId" ON "ItemTags" ("ItemId", "TagId");
|
||||
|
||||
CREATE INDEX "IX_ItemTags_TagId" ON "ItemTags" ("TagId");
|
||||
|
||||
CREATE INDEX "IX_Tags_Name" ON "Tags" ("Name");
|
||||
|
||||
INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion")
|
||||
VALUES ('20251202211204_1.7.2-AddTagTables', '9.0.4');
|
||||
|
||||
COMMIT;
|
||||
VALUES ('20251203162345_1.7.0-FieldBasedDataModelUpdate', '9.0.4');
|
||||
`;
|
||||
var MIGRATION_SCRIPTS = {
|
||||
1: `\uFEFFBEGIN TRANSACTION;
|
||||
@@ -1878,14 +1794,12 @@ CREATE INDEX IF NOT EXISTS "IX_Attachments_ItemId" ON "Attachments" ("ItemId");
|
||||
|
||||
CREATE TABLE "FieldDefinitions" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_FieldDefinitions" PRIMARY KEY,
|
||||
"FieldKey" TEXT NULL,
|
||||
"EntityType" TEXT NULL,
|
||||
"FieldType" TEXT NOT NULL,
|
||||
"Label" TEXT NOT NULL,
|
||||
"IsMultiValue" INTEGER NOT NULL,
|
||||
"DefaultVisibility" TEXT NULL,
|
||||
"IsHidden" INTEGER NOT NULL,
|
||||
"EnableHistory" INTEGER NOT NULL,
|
||||
"DisplayOrder" INTEGER NOT NULL,
|
||||
"Weight" INTEGER NOT NULL,
|
||||
"ApplicableToTypes" TEXT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
@@ -1896,7 +1810,7 @@ CREATE TABLE "Folders" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_Folders" PRIMARY KEY,
|
||||
"Name" TEXT NOT NULL,
|
||||
"ParentFolderId" TEXT NULL,
|
||||
"DisplayOrder" INTEGER NOT NULL,
|
||||
"Weight" INTEGER NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL,
|
||||
@@ -1914,6 +1828,16 @@ CREATE TABLE "Logos" (
|
||||
"IsDeleted" INTEGER NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE "Tags" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_Tags" PRIMARY KEY,
|
||||
"Name" TEXT NOT NULL,
|
||||
"Color" TEXT NULL,
|
||||
"DisplayOrder" INTEGER NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE "Items" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_Items" PRIMARY KEY,
|
||||
"Name" TEXT NULL,
|
||||
@@ -1943,9 +1867,10 @@ CREATE TABLE "FieldHistories" (
|
||||
CREATE TABLE "FieldValues" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_FieldValues" PRIMARY KEY,
|
||||
"ItemId" TEXT NOT NULL,
|
||||
"FieldDefinitionId" TEXT NOT NULL,
|
||||
"FieldDefinitionId" TEXT NULL,
|
||||
"FieldKey" TEXT NULL,
|
||||
"Value" TEXT NULL,
|
||||
"ValueIndex" INTEGER NOT NULL,
|
||||
"Weight" INTEGER NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL,
|
||||
@@ -1953,7 +1878,16 @@ CREATE TABLE "FieldValues" (
|
||||
CONSTRAINT "FK_FieldValues_Items_ItemId" FOREIGN KEY ("ItemId") REFERENCES "Items" ("Id") ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE INDEX "IX_FieldDefinitions_FieldKey" ON "FieldDefinitions" ("FieldKey");
|
||||
CREATE TABLE "ItemTags" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_ItemTags" PRIMARY KEY,
|
||||
"ItemId" TEXT NOT NULL,
|
||||
"TagId" TEXT NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL,
|
||||
CONSTRAINT "FK_ItemTags_Items_ItemId" FOREIGN KEY ("ItemId") REFERENCES "Items" ("Id") ON DELETE CASCADE,
|
||||
CONSTRAINT "FK_ItemTags_Tags_TagId" FOREIGN KEY ("TagId") REFERENCES "Tags" ("Id") ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE INDEX "IX_FieldHistories_FieldDefinitionId" ON "FieldHistories" ("FieldDefinitionId");
|
||||
|
||||
@@ -1961,9 +1895,13 @@ CREATE INDEX "IX_FieldHistories_ItemId" ON "FieldHistories" ("ItemId");
|
||||
|
||||
CREATE INDEX "IX_FieldValues_FieldDefinitionId" ON "FieldValues" ("FieldDefinitionId");
|
||||
|
||||
CREATE INDEX "IX_FieldValues_FieldKey" ON "FieldValues" ("FieldKey");
|
||||
|
||||
CREATE INDEX "IX_FieldValues_ItemId" ON "FieldValues" ("ItemId");
|
||||
|
||||
CREATE INDEX "IX_FieldValues_ItemId_FieldDefinitionId_ValueIndex" ON "FieldValues" ("ItemId", "FieldDefinitionId", "ValueIndex");
|
||||
CREATE INDEX "IX_FieldValues_ItemId_FieldDefinitionId_Weight" ON "FieldValues" ("ItemId", "FieldDefinitionId", "Weight");
|
||||
|
||||
CREATE INDEX "IX_FieldValues_ItemId_FieldKey" ON "FieldValues" ("ItemId", "FieldKey");
|
||||
|
||||
CREATE INDEX "IX_Folders_ParentFolderId" ON "Folders" ("ParentFolderId");
|
||||
|
||||
@@ -1971,27 +1909,15 @@ CREATE INDEX "IX_Items_FolderId" ON "Items" ("FolderId");
|
||||
|
||||
CREATE INDEX "IX_Items_LogoId" ON "Items" ("LogoId");
|
||||
|
||||
CREATE INDEX "IX_ItemTags_ItemId" ON "ItemTags" ("ItemId");
|
||||
|
||||
CREATE UNIQUE INDEX "IX_ItemTags_ItemId_TagId" ON "ItemTags" ("ItemId", "TagId");
|
||||
|
||||
CREATE INDEX "IX_ItemTags_TagId" ON "ItemTags" ("TagId");
|
||||
|
||||
CREATE UNIQUE INDEX "IX_Logos_Source" ON "Logos" ("Source");
|
||||
|
||||
|
||||
-- Login fields
|
||||
INSERT INTO FieldDefinitions (Id, FieldKey, EntityType, FieldType, Label, IsMultiValue, DefaultVisibility, EnableHistory, DisplayOrder, ApplicableToTypes, CreatedAt, UpdatedAt, IsDeleted)
|
||||
VALUES
|
||||
(lower(hex(randomblob(16))), 'login.username', 'Item', 'Text', 'Username', 0, 'Visible', 1, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'login.password', 'Item', 'Password', 'Password', 0, 'Hidden', 1, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'login.notes', 'Item', 'Text', 'Notes', 0, 'Collapsed', 0, 0, NULL, datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'login.url', 'Item', 'URL', 'Website URLs', 1, 'Visible', 0, 0, '["Login"]', datetime('now'), datetime('now'), 0);
|
||||
|
||||
-- Alias fields
|
||||
INSERT INTO FieldDefinitions (Id, FieldKey, EntityType, FieldType, Label, IsMultiValue, DefaultVisibility, EnableHistory, DisplayOrder, ApplicableToTypes, CreatedAt, UpdatedAt, IsDeleted)
|
||||
VALUES
|
||||
(lower(hex(randomblob(16))), 'alias.email', 'Item', 'Email', 'Alias Email', 0, 'Visible', 1, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'alias.first_name', 'Item', 'Text', 'First Name', 0, 'Visible', 0, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'alias.last_name', 'Item', 'Text', 'Last Name', 0, 'Visible', 0, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'alias.nickname', 'Item', 'Text', 'Nickname', 0, 'Visible', 0, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'alias.gender', 'Item', 'Text', 'Gender', 0, 'Visible', 0, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'alias.birthdate', 'Item', 'Date', 'Birth Date', 0, 'Visible', 0, 0, '["Login"]', datetime('now'), datetime('now'), 0);
|
||||
|
||||
CREATE INDEX "IX_Tags_Name" ON "Tags" ("Name");
|
||||
|
||||
|
||||
INSERT INTO Items (Id, Name, ItemType, LogoId, FolderId, CreatedAt, UpdatedAt, IsDeleted)
|
||||
@@ -2041,13 +1967,14 @@ CREATE UNIQUE INDEX "IX_Logos_Source" ON "Logos" ("Source");
|
||||
|
||||
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'login.url' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'login.url' AS FieldKey,
|
||||
s.Url AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
s.UpdatedAt AS CreatedAt,
|
||||
s.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
@@ -2057,13 +1984,14 @@ CREATE UNIQUE INDEX "IX_Logos_Source" ON "Logos" ("Source");
|
||||
|
||||
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'login.username' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'login.username' AS FieldKey,
|
||||
c.Username AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
c.UpdatedAt AS CreatedAt,
|
||||
c.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
@@ -2072,13 +2000,14 @@ CREATE UNIQUE INDEX "IX_Logos_Source" ON "Logos" ("Source");
|
||||
|
||||
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'login.notes' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'login.notes' AS FieldKey,
|
||||
c.Notes AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
c.UpdatedAt AS CreatedAt,
|
||||
c.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
@@ -2087,130 +2016,121 @@ CREATE UNIQUE INDEX "IX_Logos_Source" ON "Logos" ("Source");
|
||||
|
||||
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
p.CredentialId AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'login.password' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'login.password' AS FieldKey,
|
||||
p.Value AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
p.UpdatedAt AS CreatedAt,
|
||||
p.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Passwords p
|
||||
INNER JOIN (
|
||||
SELECT CredentialId, MAX(UpdatedAt) AS MaxUpdated
|
||||
SELECT CredentialId, MAX(UpdatedAt) AS MaxUpdated, MAX(Id) AS MaxId
|
||||
FROM Passwords
|
||||
WHERE IsDeleted = 0
|
||||
GROUP BY CredentialId
|
||||
) pm ON p.CredentialId = pm.CredentialId AND p.UpdatedAt = pm.MaxUpdated;
|
||||
) pm ON p.CredentialId = pm.CredentialId AND p.UpdatedAt = pm.MaxUpdated AND p.Id = pm.MaxId
|
||||
WHERE p.IsDeleted = 0;
|
||||
|
||||
|
||||
|
||||
INSERT INTO FieldHistories (Id, ItemId, FieldDefinitionId, ValueSnapshot, ChangedAt, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
p.CredentialId AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'login.password' LIMIT 1) AS FieldDefinitionId,
|
||||
'{"values":["' || p.Value || '"]}' AS ValueSnapshot,
|
||||
p.UpdatedAt AS ChangedAt,
|
||||
p.CreatedAt AS CreatedAt,
|
||||
p.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Passwords p
|
||||
WHERE p.Id NOT IN (
|
||||
SELECT p2.Id FROM Passwords p2
|
||||
INNER JOIN (
|
||||
SELECT CredentialId, MAX(UpdatedAt) AS MaxUpdated
|
||||
FROM Passwords
|
||||
GROUP BY CredentialId
|
||||
) pm ON p2.CredentialId = pm.CredentialId AND p2.UpdatedAt = pm.MaxUpdated
|
||||
);
|
||||
|
||||
|
||||
|
||||
-- Migrate Alias.Email
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'alias.email' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'alias.email' AS FieldKey,
|
||||
a.Email AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
a.UpdatedAt AS CreatedAt,
|
||||
a.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Credentials c
|
||||
INNER JOIN Aliases a ON a.Id = c.AliasId
|
||||
WHERE a.Email IS NOT NULL AND a.Email != '';
|
||||
|
||||
|
||||
-- Migrate Alias.FirstName
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'alias.first_name' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'alias.first_name' AS FieldKey,
|
||||
a.FirstName AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
a.UpdatedAt AS CreatedAt,
|
||||
a.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Credentials c
|
||||
INNER JOIN Aliases a ON a.Id = c.AliasId
|
||||
WHERE a.FirstName IS NOT NULL AND a.FirstName != '';
|
||||
|
||||
|
||||
-- Migrate Alias.LastName
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'alias.last_name' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'alias.last_name' AS FieldKey,
|
||||
a.LastName AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
a.UpdatedAt AS CreatedAt,
|
||||
a.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Credentials c
|
||||
INNER JOIN Aliases a ON a.Id = c.AliasId
|
||||
WHERE a.LastName IS NOT NULL AND a.LastName != '';
|
||||
|
||||
|
||||
-- Migrate Alias.NickName
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'alias.nickname' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'alias.nickname' AS FieldKey,
|
||||
a.NickName AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
a.UpdatedAt AS CreatedAt,
|
||||
a.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Credentials c
|
||||
INNER JOIN Aliases a ON a.Id = c.AliasId
|
||||
WHERE a.NickName IS NOT NULL AND a.NickName != '';
|
||||
|
||||
|
||||
-- Migrate Alias.Gender
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'alias.gender' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'alias.gender' AS FieldKey,
|
||||
a.Gender AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
a.UpdatedAt AS CreatedAt,
|
||||
a.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Credentials c
|
||||
INNER JOIN Aliases a ON a.Id = c.AliasId
|
||||
WHERE a.Gender IS NOT NULL AND a.Gender != '';
|
||||
|
||||
|
||||
-- Migrate Alias.BirthDate
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'alias.birthdate' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'alias.birthdate' AS FieldKey,
|
||||
a.BirthDate AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
a.UpdatedAt AS CreatedAt,
|
||||
a.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
@@ -2310,93 +2230,7 @@ CREATE INDEX "IX_TotpCodes_ItemId" ON "TotpCodes" ("ItemId");
|
||||
COMMIT;
|
||||
|
||||
INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion")
|
||||
VALUES ('20251126211441_1.7.0-FieldBasedDataModelUpdate', '9.0.4');`,
|
||||
12: `\uFEFFBEGIN TRANSACTION;
|
||||
ALTER TABLE "Folders" RENAME COLUMN "DisplayOrder" TO "Weight";
|
||||
|
||||
ALTER TABLE "FieldValues" RENAME COLUMN "ValueIndex" TO "Weight";
|
||||
|
||||
DROP INDEX "IX_FieldValues_ItemId_FieldDefinitionId_ValueIndex";
|
||||
|
||||
CREATE INDEX "IX_FieldValues_ItemId_FieldDefinitionId_Weight" ON "FieldValues" ("ItemId", "FieldDefinitionId", "Weight");
|
||||
|
||||
ALTER TABLE "FieldDefinitions" RENAME COLUMN "DisplayOrder" TO "Weight";
|
||||
|
||||
ALTER TABLE "FieldDefinitions" ADD "IsHidden" INTEGER NOT NULL DEFAULT 0;
|
||||
|
||||
CREATE TABLE "ef_temp_FieldDefinitions" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_FieldDefinitions" PRIMARY KEY,
|
||||
"ApplicableToTypes" TEXT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"EnableHistory" INTEGER NOT NULL,
|
||||
"FieldKey" TEXT NULL,
|
||||
"FieldType" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL,
|
||||
"IsHidden" INTEGER NOT NULL,
|
||||
"IsMultiValue" INTEGER NOT NULL,
|
||||
"Label" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"Weight" INTEGER NOT NULL
|
||||
);
|
||||
|
||||
INSERT INTO "ef_temp_FieldDefinitions" ("Id", "ApplicableToTypes", "CreatedAt", "EnableHistory", "FieldKey", "FieldType", "IsDeleted", "IsHidden", "IsMultiValue", "Label", "UpdatedAt", "Weight")
|
||||
SELECT "Id", "ApplicableToTypes", "CreatedAt", "EnableHistory", "FieldKey", "FieldType", "IsDeleted", "IsHidden", "IsMultiValue", "Label", "UpdatedAt", "Weight"
|
||||
FROM "FieldDefinitions";
|
||||
|
||||
COMMIT;
|
||||
|
||||
PRAGMA foreign_keys = 0;
|
||||
|
||||
BEGIN TRANSACTION;
|
||||
DROP TABLE "FieldDefinitions";
|
||||
|
||||
ALTER TABLE "ef_temp_FieldDefinitions" RENAME TO "FieldDefinitions";
|
||||
|
||||
COMMIT;
|
||||
|
||||
PRAGMA foreign_keys = 1;
|
||||
|
||||
BEGIN TRANSACTION;
|
||||
CREATE INDEX "IX_FieldDefinitions_FieldKey" ON "FieldDefinitions" ("FieldKey");
|
||||
|
||||
COMMIT;
|
||||
|
||||
INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion")
|
||||
VALUES ('20251126221717_1.7.1-RenameColumns', '9.0.4');`,
|
||||
13: `\uFEFFBEGIN TRANSACTION;
|
||||
CREATE TABLE "Tags" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_Tags" PRIMARY KEY,
|
||||
"Name" TEXT NOT NULL,
|
||||
"Color" TEXT NULL,
|
||||
"DisplayOrder" INTEGER NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE "ItemTags" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_ItemTags" PRIMARY KEY,
|
||||
"ItemId" TEXT NOT NULL,
|
||||
"TagId" TEXT NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL,
|
||||
CONSTRAINT "FK_ItemTags_Items_ItemId" FOREIGN KEY ("ItemId") REFERENCES "Items" ("Id") ON DELETE CASCADE,
|
||||
CONSTRAINT "FK_ItemTags_Tags_TagId" FOREIGN KEY ("TagId") REFERENCES "Tags" ("Id") ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE INDEX "IX_ItemTags_ItemId" ON "ItemTags" ("ItemId");
|
||||
|
||||
CREATE UNIQUE INDEX "IX_ItemTags_ItemId_TagId" ON "ItemTags" ("ItemId", "TagId");
|
||||
|
||||
CREATE INDEX "IX_ItemTags_TagId" ON "ItemTags" ("TagId");
|
||||
|
||||
CREATE INDEX "IX_Tags_Name" ON "Tags" ("Name");
|
||||
|
||||
INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion")
|
||||
VALUES ('20251202211204_1.7.2-AddTagTables', '9.0.4');
|
||||
|
||||
COMMIT;`
|
||||
VALUES ('20251203162345_1.7.0-FieldBasedDataModelUpdate', '9.0.4');`
|
||||
};
|
||||
|
||||
// src/sql/VaultVersions.ts
|
||||
@@ -2484,20 +2318,6 @@ var VAULT_VERSIONS = [
|
||||
description: "Update to Field-Based Data Model",
|
||||
releaseVersion: "0.26.0",
|
||||
compatibleUpToVersion: "0.26.0"
|
||||
},
|
||||
{
|
||||
revision: 13,
|
||||
version: "1.7.1",
|
||||
description: "Rename Columns",
|
||||
releaseVersion: "0.26.0",
|
||||
compatibleUpToVersion: "0.26.0"
|
||||
},
|
||||
{
|
||||
revision: 14,
|
||||
version: "1.8.0",
|
||||
description: "Add Tags Tables",
|
||||
releaseVersion: "0.27.0",
|
||||
compatibleUpToVersion: "0.27.0"
|
||||
}
|
||||
];
|
||||
|
||||
|
||||
@@ -696,14 +696,12 @@ CREATE INDEX IF NOT EXISTS "IX_Attachments_ItemId" ON "Attachments" ("ItemId");
|
||||
|
||||
CREATE TABLE "FieldDefinitions" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_FieldDefinitions" PRIMARY KEY,
|
||||
"FieldKey" TEXT NULL,
|
||||
"EntityType" TEXT NULL,
|
||||
"FieldType" TEXT NOT NULL,
|
||||
"Label" TEXT NOT NULL,
|
||||
"IsMultiValue" INTEGER NOT NULL,
|
||||
"DefaultVisibility" TEXT NULL,
|
||||
"IsHidden" INTEGER NOT NULL,
|
||||
"EnableHistory" INTEGER NOT NULL,
|
||||
"DisplayOrder" INTEGER NOT NULL,
|
||||
"Weight" INTEGER NOT NULL,
|
||||
"ApplicableToTypes" TEXT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
@@ -714,7 +712,7 @@ CREATE TABLE "Folders" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_Folders" PRIMARY KEY,
|
||||
"Name" TEXT NOT NULL,
|
||||
"ParentFolderId" TEXT NULL,
|
||||
"DisplayOrder" INTEGER NOT NULL,
|
||||
"Weight" INTEGER NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL,
|
||||
@@ -732,6 +730,16 @@ CREATE TABLE "Logos" (
|
||||
"IsDeleted" INTEGER NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE "Tags" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_Tags" PRIMARY KEY,
|
||||
"Name" TEXT NOT NULL,
|
||||
"Color" TEXT NULL,
|
||||
"DisplayOrder" INTEGER NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE "Items" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_Items" PRIMARY KEY,
|
||||
"Name" TEXT NULL,
|
||||
@@ -761,9 +769,10 @@ CREATE TABLE "FieldHistories" (
|
||||
CREATE TABLE "FieldValues" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_FieldValues" PRIMARY KEY,
|
||||
"ItemId" TEXT NOT NULL,
|
||||
"FieldDefinitionId" TEXT NOT NULL,
|
||||
"FieldDefinitionId" TEXT NULL,
|
||||
"FieldKey" TEXT NULL,
|
||||
"Value" TEXT NULL,
|
||||
"ValueIndex" INTEGER NOT NULL,
|
||||
"Weight" INTEGER NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL,
|
||||
@@ -771,7 +780,16 @@ CREATE TABLE "FieldValues" (
|
||||
CONSTRAINT "FK_FieldValues_Items_ItemId" FOREIGN KEY ("ItemId") REFERENCES "Items" ("Id") ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE INDEX "IX_FieldDefinitions_FieldKey" ON "FieldDefinitions" ("FieldKey");
|
||||
CREATE TABLE "ItemTags" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_ItemTags" PRIMARY KEY,
|
||||
"ItemId" TEXT NOT NULL,
|
||||
"TagId" TEXT NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL,
|
||||
CONSTRAINT "FK_ItemTags_Items_ItemId" FOREIGN KEY ("ItemId") REFERENCES "Items" ("Id") ON DELETE CASCADE,
|
||||
CONSTRAINT "FK_ItemTags_Tags_TagId" FOREIGN KEY ("TagId") REFERENCES "Tags" ("Id") ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE INDEX "IX_FieldHistories_FieldDefinitionId" ON "FieldHistories" ("FieldDefinitionId");
|
||||
|
||||
@@ -779,9 +797,13 @@ CREATE INDEX "IX_FieldHistories_ItemId" ON "FieldHistories" ("ItemId");
|
||||
|
||||
CREATE INDEX "IX_FieldValues_FieldDefinitionId" ON "FieldValues" ("FieldDefinitionId");
|
||||
|
||||
CREATE INDEX "IX_FieldValues_FieldKey" ON "FieldValues" ("FieldKey");
|
||||
|
||||
CREATE INDEX "IX_FieldValues_ItemId" ON "FieldValues" ("ItemId");
|
||||
|
||||
CREATE INDEX "IX_FieldValues_ItemId_FieldDefinitionId_ValueIndex" ON "FieldValues" ("ItemId", "FieldDefinitionId", "ValueIndex");
|
||||
CREATE INDEX "IX_FieldValues_ItemId_FieldDefinitionId_Weight" ON "FieldValues" ("ItemId", "FieldDefinitionId", "Weight");
|
||||
|
||||
CREATE INDEX "IX_FieldValues_ItemId_FieldKey" ON "FieldValues" ("ItemId", "FieldKey");
|
||||
|
||||
CREATE INDEX "IX_Folders_ParentFolderId" ON "Folders" ("ParentFolderId");
|
||||
|
||||
@@ -789,27 +811,15 @@ CREATE INDEX "IX_Items_FolderId" ON "Items" ("FolderId");
|
||||
|
||||
CREATE INDEX "IX_Items_LogoId" ON "Items" ("LogoId");
|
||||
|
||||
CREATE INDEX "IX_ItemTags_ItemId" ON "ItemTags" ("ItemId");
|
||||
|
||||
CREATE UNIQUE INDEX "IX_ItemTags_ItemId_TagId" ON "ItemTags" ("ItemId", "TagId");
|
||||
|
||||
CREATE INDEX "IX_ItemTags_TagId" ON "ItemTags" ("TagId");
|
||||
|
||||
CREATE UNIQUE INDEX "IX_Logos_Source" ON "Logos" ("Source");
|
||||
|
||||
|
||||
-- Login fields
|
||||
INSERT INTO FieldDefinitions (Id, FieldKey, EntityType, FieldType, Label, IsMultiValue, DefaultVisibility, EnableHistory, DisplayOrder, ApplicableToTypes, CreatedAt, UpdatedAt, IsDeleted)
|
||||
VALUES
|
||||
(lower(hex(randomblob(16))), 'login.username', 'Item', 'Text', 'Username', 0, 'Visible', 1, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'login.password', 'Item', 'Password', 'Password', 0, 'Hidden', 1, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'login.notes', 'Item', 'Text', 'Notes', 0, 'Collapsed', 0, 0, NULL, datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'login.url', 'Item', 'URL', 'Website URLs', 1, 'Visible', 0, 0, '["Login"]', datetime('now'), datetime('now'), 0);
|
||||
|
||||
-- Alias fields
|
||||
INSERT INTO FieldDefinitions (Id, FieldKey, EntityType, FieldType, Label, IsMultiValue, DefaultVisibility, EnableHistory, DisplayOrder, ApplicableToTypes, CreatedAt, UpdatedAt, IsDeleted)
|
||||
VALUES
|
||||
(lower(hex(randomblob(16))), 'alias.email', 'Item', 'Email', 'Alias Email', 0, 'Visible', 1, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'alias.first_name', 'Item', 'Text', 'First Name', 0, 'Visible', 0, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'alias.last_name', 'Item', 'Text', 'Last Name', 0, 'Visible', 0, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'alias.nickname', 'Item', 'Text', 'Nickname', 0, 'Visible', 0, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'alias.gender', 'Item', 'Text', 'Gender', 0, 'Visible', 0, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'alias.birthdate', 'Item', 'Date', 'Birth Date', 0, 'Visible', 0, 0, '["Login"]', datetime('now'), datetime('now'), 0);
|
||||
|
||||
CREATE INDEX "IX_Tags_Name" ON "Tags" ("Name");
|
||||
|
||||
|
||||
INSERT INTO Items (Id, Name, ItemType, LogoId, FolderId, CreatedAt, UpdatedAt, IsDeleted)
|
||||
@@ -859,13 +869,14 @@ CREATE UNIQUE INDEX "IX_Logos_Source" ON "Logos" ("Source");
|
||||
|
||||
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'login.url' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'login.url' AS FieldKey,
|
||||
s.Url AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
s.UpdatedAt AS CreatedAt,
|
||||
s.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
@@ -875,13 +886,14 @@ CREATE UNIQUE INDEX "IX_Logos_Source" ON "Logos" ("Source");
|
||||
|
||||
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'login.username' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'login.username' AS FieldKey,
|
||||
c.Username AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
c.UpdatedAt AS CreatedAt,
|
||||
c.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
@@ -890,13 +902,14 @@ CREATE UNIQUE INDEX "IX_Logos_Source" ON "Logos" ("Source");
|
||||
|
||||
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'login.notes' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'login.notes' AS FieldKey,
|
||||
c.Notes AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
c.UpdatedAt AS CreatedAt,
|
||||
c.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
@@ -905,130 +918,121 @@ CREATE UNIQUE INDEX "IX_Logos_Source" ON "Logos" ("Source");
|
||||
|
||||
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
p.CredentialId AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'login.password' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'login.password' AS FieldKey,
|
||||
p.Value AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
p.UpdatedAt AS CreatedAt,
|
||||
p.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Passwords p
|
||||
INNER JOIN (
|
||||
SELECT CredentialId, MAX(UpdatedAt) AS MaxUpdated
|
||||
SELECT CredentialId, MAX(UpdatedAt) AS MaxUpdated, MAX(Id) AS MaxId
|
||||
FROM Passwords
|
||||
WHERE IsDeleted = 0
|
||||
GROUP BY CredentialId
|
||||
) pm ON p.CredentialId = pm.CredentialId AND p.UpdatedAt = pm.MaxUpdated;
|
||||
) pm ON p.CredentialId = pm.CredentialId AND p.UpdatedAt = pm.MaxUpdated AND p.Id = pm.MaxId
|
||||
WHERE p.IsDeleted = 0;
|
||||
|
||||
|
||||
|
||||
INSERT INTO FieldHistories (Id, ItemId, FieldDefinitionId, ValueSnapshot, ChangedAt, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
p.CredentialId AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'login.password' LIMIT 1) AS FieldDefinitionId,
|
||||
'{"values":["' || p.Value || '"]}' AS ValueSnapshot,
|
||||
p.UpdatedAt AS ChangedAt,
|
||||
p.CreatedAt AS CreatedAt,
|
||||
p.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Passwords p
|
||||
WHERE p.Id NOT IN (
|
||||
SELECT p2.Id FROM Passwords p2
|
||||
INNER JOIN (
|
||||
SELECT CredentialId, MAX(UpdatedAt) AS MaxUpdated
|
||||
FROM Passwords
|
||||
GROUP BY CredentialId
|
||||
) pm ON p2.CredentialId = pm.CredentialId AND p2.UpdatedAt = pm.MaxUpdated
|
||||
);
|
||||
|
||||
|
||||
|
||||
-- Migrate Alias.Email
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'alias.email' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'alias.email' AS FieldKey,
|
||||
a.Email AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
a.UpdatedAt AS CreatedAt,
|
||||
a.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Credentials c
|
||||
INNER JOIN Aliases a ON a.Id = c.AliasId
|
||||
WHERE a.Email IS NOT NULL AND a.Email != '';
|
||||
|
||||
|
||||
-- Migrate Alias.FirstName
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'alias.first_name' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'alias.first_name' AS FieldKey,
|
||||
a.FirstName AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
a.UpdatedAt AS CreatedAt,
|
||||
a.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Credentials c
|
||||
INNER JOIN Aliases a ON a.Id = c.AliasId
|
||||
WHERE a.FirstName IS NOT NULL AND a.FirstName != '';
|
||||
|
||||
|
||||
-- Migrate Alias.LastName
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'alias.last_name' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'alias.last_name' AS FieldKey,
|
||||
a.LastName AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
a.UpdatedAt AS CreatedAt,
|
||||
a.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Credentials c
|
||||
INNER JOIN Aliases a ON a.Id = c.AliasId
|
||||
WHERE a.LastName IS NOT NULL AND a.LastName != '';
|
||||
|
||||
|
||||
-- Migrate Alias.NickName
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'alias.nickname' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'alias.nickname' AS FieldKey,
|
||||
a.NickName AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
a.UpdatedAt AS CreatedAt,
|
||||
a.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Credentials c
|
||||
INNER JOIN Aliases a ON a.Id = c.AliasId
|
||||
WHERE a.NickName IS NOT NULL AND a.NickName != '';
|
||||
|
||||
|
||||
-- Migrate Alias.Gender
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'alias.gender' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'alias.gender' AS FieldKey,
|
||||
a.Gender AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
a.UpdatedAt AS CreatedAt,
|
||||
a.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Credentials c
|
||||
INNER JOIN Aliases a ON a.Id = c.AliasId
|
||||
WHERE a.Gender IS NOT NULL AND a.Gender != '';
|
||||
|
||||
|
||||
-- Migrate Alias.BirthDate
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'alias.birthdate' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'alias.birthdate' AS FieldKey,
|
||||
a.BirthDate AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
a.UpdatedAt AS CreatedAt,
|
||||
a.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
@@ -1128,95 +1132,7 @@ CREATE INDEX "IX_TotpCodes_ItemId" ON "TotpCodes" ("ItemId");
|
||||
COMMIT;
|
||||
|
||||
INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion")
|
||||
VALUES ('20251126211441_1.7.0-FieldBasedDataModelUpdate', '9.0.4');
|
||||
|
||||
BEGIN TRANSACTION;
|
||||
ALTER TABLE "Folders" RENAME COLUMN "DisplayOrder" TO "Weight";
|
||||
|
||||
ALTER TABLE "FieldValues" RENAME COLUMN "ValueIndex" TO "Weight";
|
||||
|
||||
DROP INDEX "IX_FieldValues_ItemId_FieldDefinitionId_ValueIndex";
|
||||
|
||||
CREATE INDEX "IX_FieldValues_ItemId_FieldDefinitionId_Weight" ON "FieldValues" ("ItemId", "FieldDefinitionId", "Weight");
|
||||
|
||||
ALTER TABLE "FieldDefinitions" RENAME COLUMN "DisplayOrder" TO "Weight";
|
||||
|
||||
ALTER TABLE "FieldDefinitions" ADD "IsHidden" INTEGER NOT NULL DEFAULT 0;
|
||||
|
||||
CREATE TABLE "ef_temp_FieldDefinitions" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_FieldDefinitions" PRIMARY KEY,
|
||||
"ApplicableToTypes" TEXT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"EnableHistory" INTEGER NOT NULL,
|
||||
"FieldKey" TEXT NULL,
|
||||
"FieldType" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL,
|
||||
"IsHidden" INTEGER NOT NULL,
|
||||
"IsMultiValue" INTEGER NOT NULL,
|
||||
"Label" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"Weight" INTEGER NOT NULL
|
||||
);
|
||||
|
||||
INSERT INTO "ef_temp_FieldDefinitions" ("Id", "ApplicableToTypes", "CreatedAt", "EnableHistory", "FieldKey", "FieldType", "IsDeleted", "IsHidden", "IsMultiValue", "Label", "UpdatedAt", "Weight")
|
||||
SELECT "Id", "ApplicableToTypes", "CreatedAt", "EnableHistory", "FieldKey", "FieldType", "IsDeleted", "IsHidden", "IsMultiValue", "Label", "UpdatedAt", "Weight"
|
||||
FROM "FieldDefinitions";
|
||||
|
||||
COMMIT;
|
||||
|
||||
PRAGMA foreign_keys = 0;
|
||||
|
||||
BEGIN TRANSACTION;
|
||||
DROP TABLE "FieldDefinitions";
|
||||
|
||||
ALTER TABLE "ef_temp_FieldDefinitions" RENAME TO "FieldDefinitions";
|
||||
|
||||
COMMIT;
|
||||
|
||||
PRAGMA foreign_keys = 1;
|
||||
|
||||
BEGIN TRANSACTION;
|
||||
CREATE INDEX "IX_FieldDefinitions_FieldKey" ON "FieldDefinitions" ("FieldKey");
|
||||
|
||||
COMMIT;
|
||||
|
||||
INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion")
|
||||
VALUES ('20251126221717_1.7.1-RenameColumns', '9.0.4');
|
||||
|
||||
BEGIN TRANSACTION;
|
||||
CREATE TABLE "Tags" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_Tags" PRIMARY KEY,
|
||||
"Name" TEXT NOT NULL,
|
||||
"Color" TEXT NULL,
|
||||
"DisplayOrder" INTEGER NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE "ItemTags" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_ItemTags" PRIMARY KEY,
|
||||
"ItemId" TEXT NOT NULL,
|
||||
"TagId" TEXT NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL,
|
||||
CONSTRAINT "FK_ItemTags_Items_ItemId" FOREIGN KEY ("ItemId") REFERENCES "Items" ("Id") ON DELETE CASCADE,
|
||||
CONSTRAINT "FK_ItemTags_Tags_TagId" FOREIGN KEY ("TagId") REFERENCES "Tags" ("Id") ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE INDEX "IX_ItemTags_ItemId" ON "ItemTags" ("ItemId");
|
||||
|
||||
CREATE UNIQUE INDEX "IX_ItemTags_ItemId_TagId" ON "ItemTags" ("ItemId", "TagId");
|
||||
|
||||
CREATE INDEX "IX_ItemTags_TagId" ON "ItemTags" ("TagId");
|
||||
|
||||
CREATE INDEX "IX_Tags_Name" ON "Tags" ("Name");
|
||||
|
||||
INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion")
|
||||
VALUES ('20251202211204_1.7.2-AddTagTables', '9.0.4');
|
||||
|
||||
COMMIT;
|
||||
VALUES ('20251203162345_1.7.0-FieldBasedDataModelUpdate', '9.0.4');
|
||||
`;
|
||||
var MIGRATION_SCRIPTS = {
|
||||
1: `\uFEFFBEGIN TRANSACTION;
|
||||
@@ -1846,14 +1762,12 @@ CREATE INDEX IF NOT EXISTS "IX_Attachments_ItemId" ON "Attachments" ("ItemId");
|
||||
|
||||
CREATE TABLE "FieldDefinitions" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_FieldDefinitions" PRIMARY KEY,
|
||||
"FieldKey" TEXT NULL,
|
||||
"EntityType" TEXT NULL,
|
||||
"FieldType" TEXT NOT NULL,
|
||||
"Label" TEXT NOT NULL,
|
||||
"IsMultiValue" INTEGER NOT NULL,
|
||||
"DefaultVisibility" TEXT NULL,
|
||||
"IsHidden" INTEGER NOT NULL,
|
||||
"EnableHistory" INTEGER NOT NULL,
|
||||
"DisplayOrder" INTEGER NOT NULL,
|
||||
"Weight" INTEGER NOT NULL,
|
||||
"ApplicableToTypes" TEXT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
@@ -1864,7 +1778,7 @@ CREATE TABLE "Folders" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_Folders" PRIMARY KEY,
|
||||
"Name" TEXT NOT NULL,
|
||||
"ParentFolderId" TEXT NULL,
|
||||
"DisplayOrder" INTEGER NOT NULL,
|
||||
"Weight" INTEGER NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL,
|
||||
@@ -1882,6 +1796,16 @@ CREATE TABLE "Logos" (
|
||||
"IsDeleted" INTEGER NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE "Tags" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_Tags" PRIMARY KEY,
|
||||
"Name" TEXT NOT NULL,
|
||||
"Color" TEXT NULL,
|
||||
"DisplayOrder" INTEGER NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE "Items" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_Items" PRIMARY KEY,
|
||||
"Name" TEXT NULL,
|
||||
@@ -1911,9 +1835,10 @@ CREATE TABLE "FieldHistories" (
|
||||
CREATE TABLE "FieldValues" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_FieldValues" PRIMARY KEY,
|
||||
"ItemId" TEXT NOT NULL,
|
||||
"FieldDefinitionId" TEXT NOT NULL,
|
||||
"FieldDefinitionId" TEXT NULL,
|
||||
"FieldKey" TEXT NULL,
|
||||
"Value" TEXT NULL,
|
||||
"ValueIndex" INTEGER NOT NULL,
|
||||
"Weight" INTEGER NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL,
|
||||
@@ -1921,7 +1846,16 @@ CREATE TABLE "FieldValues" (
|
||||
CONSTRAINT "FK_FieldValues_Items_ItemId" FOREIGN KEY ("ItemId") REFERENCES "Items" ("Id") ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE INDEX "IX_FieldDefinitions_FieldKey" ON "FieldDefinitions" ("FieldKey");
|
||||
CREATE TABLE "ItemTags" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_ItemTags" PRIMARY KEY,
|
||||
"ItemId" TEXT NOT NULL,
|
||||
"TagId" TEXT NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL,
|
||||
CONSTRAINT "FK_ItemTags_Items_ItemId" FOREIGN KEY ("ItemId") REFERENCES "Items" ("Id") ON DELETE CASCADE,
|
||||
CONSTRAINT "FK_ItemTags_Tags_TagId" FOREIGN KEY ("TagId") REFERENCES "Tags" ("Id") ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE INDEX "IX_FieldHistories_FieldDefinitionId" ON "FieldHistories" ("FieldDefinitionId");
|
||||
|
||||
@@ -1929,9 +1863,13 @@ CREATE INDEX "IX_FieldHistories_ItemId" ON "FieldHistories" ("ItemId");
|
||||
|
||||
CREATE INDEX "IX_FieldValues_FieldDefinitionId" ON "FieldValues" ("FieldDefinitionId");
|
||||
|
||||
CREATE INDEX "IX_FieldValues_FieldKey" ON "FieldValues" ("FieldKey");
|
||||
|
||||
CREATE INDEX "IX_FieldValues_ItemId" ON "FieldValues" ("ItemId");
|
||||
|
||||
CREATE INDEX "IX_FieldValues_ItemId_FieldDefinitionId_ValueIndex" ON "FieldValues" ("ItemId", "FieldDefinitionId", "ValueIndex");
|
||||
CREATE INDEX "IX_FieldValues_ItemId_FieldDefinitionId_Weight" ON "FieldValues" ("ItemId", "FieldDefinitionId", "Weight");
|
||||
|
||||
CREATE INDEX "IX_FieldValues_ItemId_FieldKey" ON "FieldValues" ("ItemId", "FieldKey");
|
||||
|
||||
CREATE INDEX "IX_Folders_ParentFolderId" ON "Folders" ("ParentFolderId");
|
||||
|
||||
@@ -1939,27 +1877,15 @@ CREATE INDEX "IX_Items_FolderId" ON "Items" ("FolderId");
|
||||
|
||||
CREATE INDEX "IX_Items_LogoId" ON "Items" ("LogoId");
|
||||
|
||||
CREATE INDEX "IX_ItemTags_ItemId" ON "ItemTags" ("ItemId");
|
||||
|
||||
CREATE UNIQUE INDEX "IX_ItemTags_ItemId_TagId" ON "ItemTags" ("ItemId", "TagId");
|
||||
|
||||
CREATE INDEX "IX_ItemTags_TagId" ON "ItemTags" ("TagId");
|
||||
|
||||
CREATE UNIQUE INDEX "IX_Logos_Source" ON "Logos" ("Source");
|
||||
|
||||
|
||||
-- Login fields
|
||||
INSERT INTO FieldDefinitions (Id, FieldKey, EntityType, FieldType, Label, IsMultiValue, DefaultVisibility, EnableHistory, DisplayOrder, ApplicableToTypes, CreatedAt, UpdatedAt, IsDeleted)
|
||||
VALUES
|
||||
(lower(hex(randomblob(16))), 'login.username', 'Item', 'Text', 'Username', 0, 'Visible', 1, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'login.password', 'Item', 'Password', 'Password', 0, 'Hidden', 1, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'login.notes', 'Item', 'Text', 'Notes', 0, 'Collapsed', 0, 0, NULL, datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'login.url', 'Item', 'URL', 'Website URLs', 1, 'Visible', 0, 0, '["Login"]', datetime('now'), datetime('now'), 0);
|
||||
|
||||
-- Alias fields
|
||||
INSERT INTO FieldDefinitions (Id, FieldKey, EntityType, FieldType, Label, IsMultiValue, DefaultVisibility, EnableHistory, DisplayOrder, ApplicableToTypes, CreatedAt, UpdatedAt, IsDeleted)
|
||||
VALUES
|
||||
(lower(hex(randomblob(16))), 'alias.email', 'Item', 'Email', 'Alias Email', 0, 'Visible', 1, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'alias.first_name', 'Item', 'Text', 'First Name', 0, 'Visible', 0, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'alias.last_name', 'Item', 'Text', 'Last Name', 0, 'Visible', 0, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'alias.nickname', 'Item', 'Text', 'Nickname', 0, 'Visible', 0, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'alias.gender', 'Item', 'Text', 'Gender', 0, 'Visible', 0, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'alias.birthdate', 'Item', 'Date', 'Birth Date', 0, 'Visible', 0, 0, '["Login"]', datetime('now'), datetime('now'), 0);
|
||||
|
||||
CREATE INDEX "IX_Tags_Name" ON "Tags" ("Name");
|
||||
|
||||
|
||||
INSERT INTO Items (Id, Name, ItemType, LogoId, FolderId, CreatedAt, UpdatedAt, IsDeleted)
|
||||
@@ -2009,13 +1935,14 @@ CREATE UNIQUE INDEX "IX_Logos_Source" ON "Logos" ("Source");
|
||||
|
||||
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'login.url' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'login.url' AS FieldKey,
|
||||
s.Url AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
s.UpdatedAt AS CreatedAt,
|
||||
s.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
@@ -2025,13 +1952,14 @@ CREATE UNIQUE INDEX "IX_Logos_Source" ON "Logos" ("Source");
|
||||
|
||||
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'login.username' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'login.username' AS FieldKey,
|
||||
c.Username AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
c.UpdatedAt AS CreatedAt,
|
||||
c.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
@@ -2040,13 +1968,14 @@ CREATE UNIQUE INDEX "IX_Logos_Source" ON "Logos" ("Source");
|
||||
|
||||
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'login.notes' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'login.notes' AS FieldKey,
|
||||
c.Notes AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
c.UpdatedAt AS CreatedAt,
|
||||
c.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
@@ -2055,130 +1984,121 @@ CREATE UNIQUE INDEX "IX_Logos_Source" ON "Logos" ("Source");
|
||||
|
||||
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
p.CredentialId AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'login.password' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'login.password' AS FieldKey,
|
||||
p.Value AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
p.UpdatedAt AS CreatedAt,
|
||||
p.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Passwords p
|
||||
INNER JOIN (
|
||||
SELECT CredentialId, MAX(UpdatedAt) AS MaxUpdated
|
||||
SELECT CredentialId, MAX(UpdatedAt) AS MaxUpdated, MAX(Id) AS MaxId
|
||||
FROM Passwords
|
||||
WHERE IsDeleted = 0
|
||||
GROUP BY CredentialId
|
||||
) pm ON p.CredentialId = pm.CredentialId AND p.UpdatedAt = pm.MaxUpdated;
|
||||
) pm ON p.CredentialId = pm.CredentialId AND p.UpdatedAt = pm.MaxUpdated AND p.Id = pm.MaxId
|
||||
WHERE p.IsDeleted = 0;
|
||||
|
||||
|
||||
|
||||
INSERT INTO FieldHistories (Id, ItemId, FieldDefinitionId, ValueSnapshot, ChangedAt, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
p.CredentialId AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'login.password' LIMIT 1) AS FieldDefinitionId,
|
||||
'{"values":["' || p.Value || '"]}' AS ValueSnapshot,
|
||||
p.UpdatedAt AS ChangedAt,
|
||||
p.CreatedAt AS CreatedAt,
|
||||
p.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Passwords p
|
||||
WHERE p.Id NOT IN (
|
||||
SELECT p2.Id FROM Passwords p2
|
||||
INNER JOIN (
|
||||
SELECT CredentialId, MAX(UpdatedAt) AS MaxUpdated
|
||||
FROM Passwords
|
||||
GROUP BY CredentialId
|
||||
) pm ON p2.CredentialId = pm.CredentialId AND p2.UpdatedAt = pm.MaxUpdated
|
||||
);
|
||||
|
||||
|
||||
|
||||
-- Migrate Alias.Email
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'alias.email' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'alias.email' AS FieldKey,
|
||||
a.Email AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
a.UpdatedAt AS CreatedAt,
|
||||
a.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Credentials c
|
||||
INNER JOIN Aliases a ON a.Id = c.AliasId
|
||||
WHERE a.Email IS NOT NULL AND a.Email != '';
|
||||
|
||||
|
||||
-- Migrate Alias.FirstName
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'alias.first_name' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'alias.first_name' AS FieldKey,
|
||||
a.FirstName AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
a.UpdatedAt AS CreatedAt,
|
||||
a.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Credentials c
|
||||
INNER JOIN Aliases a ON a.Id = c.AliasId
|
||||
WHERE a.FirstName IS NOT NULL AND a.FirstName != '';
|
||||
|
||||
|
||||
-- Migrate Alias.LastName
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'alias.last_name' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'alias.last_name' AS FieldKey,
|
||||
a.LastName AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
a.UpdatedAt AS CreatedAt,
|
||||
a.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Credentials c
|
||||
INNER JOIN Aliases a ON a.Id = c.AliasId
|
||||
WHERE a.LastName IS NOT NULL AND a.LastName != '';
|
||||
|
||||
|
||||
-- Migrate Alias.NickName
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'alias.nickname' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'alias.nickname' AS FieldKey,
|
||||
a.NickName AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
a.UpdatedAt AS CreatedAt,
|
||||
a.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Credentials c
|
||||
INNER JOIN Aliases a ON a.Id = c.AliasId
|
||||
WHERE a.NickName IS NOT NULL AND a.NickName != '';
|
||||
|
||||
|
||||
-- Migrate Alias.Gender
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'alias.gender' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'alias.gender' AS FieldKey,
|
||||
a.Gender AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
a.UpdatedAt AS CreatedAt,
|
||||
a.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Credentials c
|
||||
INNER JOIN Aliases a ON a.Id = c.AliasId
|
||||
WHERE a.Gender IS NOT NULL AND a.Gender != '';
|
||||
|
||||
|
||||
-- Migrate Alias.BirthDate
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'alias.birthdate' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'alias.birthdate' AS FieldKey,
|
||||
a.BirthDate AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
a.UpdatedAt AS CreatedAt,
|
||||
a.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
@@ -2278,93 +2198,7 @@ CREATE INDEX "IX_TotpCodes_ItemId" ON "TotpCodes" ("ItemId");
|
||||
COMMIT;
|
||||
|
||||
INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion")
|
||||
VALUES ('20251126211441_1.7.0-FieldBasedDataModelUpdate', '9.0.4');`,
|
||||
12: `\uFEFFBEGIN TRANSACTION;
|
||||
ALTER TABLE "Folders" RENAME COLUMN "DisplayOrder" TO "Weight";
|
||||
|
||||
ALTER TABLE "FieldValues" RENAME COLUMN "ValueIndex" TO "Weight";
|
||||
|
||||
DROP INDEX "IX_FieldValues_ItemId_FieldDefinitionId_ValueIndex";
|
||||
|
||||
CREATE INDEX "IX_FieldValues_ItemId_FieldDefinitionId_Weight" ON "FieldValues" ("ItemId", "FieldDefinitionId", "Weight");
|
||||
|
||||
ALTER TABLE "FieldDefinitions" RENAME COLUMN "DisplayOrder" TO "Weight";
|
||||
|
||||
ALTER TABLE "FieldDefinitions" ADD "IsHidden" INTEGER NOT NULL DEFAULT 0;
|
||||
|
||||
CREATE TABLE "ef_temp_FieldDefinitions" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_FieldDefinitions" PRIMARY KEY,
|
||||
"ApplicableToTypes" TEXT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"EnableHistory" INTEGER NOT NULL,
|
||||
"FieldKey" TEXT NULL,
|
||||
"FieldType" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL,
|
||||
"IsHidden" INTEGER NOT NULL,
|
||||
"IsMultiValue" INTEGER NOT NULL,
|
||||
"Label" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"Weight" INTEGER NOT NULL
|
||||
);
|
||||
|
||||
INSERT INTO "ef_temp_FieldDefinitions" ("Id", "ApplicableToTypes", "CreatedAt", "EnableHistory", "FieldKey", "FieldType", "IsDeleted", "IsHidden", "IsMultiValue", "Label", "UpdatedAt", "Weight")
|
||||
SELECT "Id", "ApplicableToTypes", "CreatedAt", "EnableHistory", "FieldKey", "FieldType", "IsDeleted", "IsHidden", "IsMultiValue", "Label", "UpdatedAt", "Weight"
|
||||
FROM "FieldDefinitions";
|
||||
|
||||
COMMIT;
|
||||
|
||||
PRAGMA foreign_keys = 0;
|
||||
|
||||
BEGIN TRANSACTION;
|
||||
DROP TABLE "FieldDefinitions";
|
||||
|
||||
ALTER TABLE "ef_temp_FieldDefinitions" RENAME TO "FieldDefinitions";
|
||||
|
||||
COMMIT;
|
||||
|
||||
PRAGMA foreign_keys = 1;
|
||||
|
||||
BEGIN TRANSACTION;
|
||||
CREATE INDEX "IX_FieldDefinitions_FieldKey" ON "FieldDefinitions" ("FieldKey");
|
||||
|
||||
COMMIT;
|
||||
|
||||
INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion")
|
||||
VALUES ('20251126221717_1.7.1-RenameColumns', '9.0.4');`,
|
||||
13: `\uFEFFBEGIN TRANSACTION;
|
||||
CREATE TABLE "Tags" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_Tags" PRIMARY KEY,
|
||||
"Name" TEXT NOT NULL,
|
||||
"Color" TEXT NULL,
|
||||
"DisplayOrder" INTEGER NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE "ItemTags" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_ItemTags" PRIMARY KEY,
|
||||
"ItemId" TEXT NOT NULL,
|
||||
"TagId" TEXT NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL,
|
||||
CONSTRAINT "FK_ItemTags_Items_ItemId" FOREIGN KEY ("ItemId") REFERENCES "Items" ("Id") ON DELETE CASCADE,
|
||||
CONSTRAINT "FK_ItemTags_Tags_TagId" FOREIGN KEY ("TagId") REFERENCES "Tags" ("Id") ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE INDEX "IX_ItemTags_ItemId" ON "ItemTags" ("ItemId");
|
||||
|
||||
CREATE UNIQUE INDEX "IX_ItemTags_ItemId_TagId" ON "ItemTags" ("ItemId", "TagId");
|
||||
|
||||
CREATE INDEX "IX_ItemTags_TagId" ON "ItemTags" ("TagId");
|
||||
|
||||
CREATE INDEX "IX_Tags_Name" ON "Tags" ("Name");
|
||||
|
||||
INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion")
|
||||
VALUES ('20251202211204_1.7.2-AddTagTables', '9.0.4');
|
||||
|
||||
COMMIT;`
|
||||
VALUES ('20251203162345_1.7.0-FieldBasedDataModelUpdate', '9.0.4');`
|
||||
};
|
||||
|
||||
// src/sql/VaultVersions.ts
|
||||
@@ -2452,20 +2286,6 @@ var VAULT_VERSIONS = [
|
||||
description: "Update to Field-Based Data Model",
|
||||
releaseVersion: "0.26.0",
|
||||
compatibleUpToVersion: "0.26.0"
|
||||
},
|
||||
{
|
||||
revision: 13,
|
||||
version: "1.7.1",
|
||||
description: "Rename Columns",
|
||||
releaseVersion: "0.26.0",
|
||||
compatibleUpToVersion: "0.26.0"
|
||||
},
|
||||
{
|
||||
revision: 14,
|
||||
version: "1.8.0",
|
||||
description: "Add Tags Tables",
|
||||
releaseVersion: "0.27.0",
|
||||
compatibleUpToVersion: "0.27.0"
|
||||
}
|
||||
];
|
||||
|
||||
|
||||
@@ -191,12 +191,13 @@ public class AliasClientDbContext : DbContext
|
||||
.HasForeignKey(fv => fv.ItemId)
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
// Configure FieldValue - FieldDefinition relationship
|
||||
// Configure FieldValue - FieldDefinition relationship (nullable for system fields)
|
||||
modelBuilder.Entity<FieldValue>()
|
||||
.HasOne(fv => fv.FieldDefinition)
|
||||
.WithMany(fd => fd.FieldValues)
|
||||
.HasForeignKey(fv => fv.FieldDefinitionId)
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired(false); // Nullable for system fields
|
||||
|
||||
// Configure FieldHistory - FieldDefinition relationship
|
||||
modelBuilder.Entity<FieldHistory>()
|
||||
@@ -212,9 +213,15 @@ public class AliasClientDbContext : DbContext
|
||||
modelBuilder.Entity<FieldValue>()
|
||||
.HasIndex(fv => fv.FieldDefinitionId);
|
||||
|
||||
modelBuilder.Entity<FieldValue>()
|
||||
.HasIndex(fv => fv.FieldKey); // Index for system field lookups
|
||||
|
||||
modelBuilder.Entity<FieldValue>()
|
||||
.HasIndex(fv => new { fv.ItemId, fv.FieldDefinitionId, fv.Weight });
|
||||
|
||||
modelBuilder.Entity<FieldValue>()
|
||||
.HasIndex(fv => new { fv.ItemId, fv.FieldKey }); // Composite index for system field queries
|
||||
|
||||
// Configure indexes for FieldHistory
|
||||
modelBuilder.Entity<FieldHistory>()
|
||||
.HasIndex(fh => fh.ItemId);
|
||||
@@ -222,9 +229,7 @@ public class AliasClientDbContext : DbContext
|
||||
modelBuilder.Entity<FieldHistory>()
|
||||
.HasIndex(fh => fh.FieldDefinitionId);
|
||||
|
||||
// Configure indexes for FieldDefinition
|
||||
modelBuilder.Entity<FieldDefinition>()
|
||||
.HasIndex(fd => fd.FieldKey);
|
||||
// FieldDefinition indexes (FieldKey removed - custom fields use GUID only)
|
||||
|
||||
// Configure indexes for Folder
|
||||
modelBuilder.Entity<Folder>()
|
||||
|
||||
@@ -11,7 +11,11 @@ using System.ComponentModel.DataAnnotations;
|
||||
using AliasClientDb.Abstracts;
|
||||
|
||||
/// <summary>
|
||||
/// FieldDefinition entity that defines the schema for fields.
|
||||
/// FieldDefinition entity that defines the schema for custom (user-defined) fields.
|
||||
/// NOTE: System fields (login.username, alias.email, etc.) do NOT have FieldDefinition rows.
|
||||
/// System field metadata is defined in code (SystemFieldRegistry) and is immutable.
|
||||
/// This table is ONLY for custom fields that users create themselves.
|
||||
/// Custom fields are always referenced by their GUID (Id), never by FieldKey.
|
||||
/// </summary>
|
||||
public class FieldDefinition : SyncableEntity
|
||||
{
|
||||
@@ -21,19 +25,6 @@ public class FieldDefinition : SyncableEntity
|
||||
[Key]
|
||||
public Guid Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the field key for system fields (e.g., 'login.username', 'card.number').
|
||||
/// NULL for custom (user-defined) fields.
|
||||
/// System fields use predefined keys like:
|
||||
/// - login.username, login.password, login.notes, login.url
|
||||
/// - card.number, card.cardholder_name, card.cvv
|
||||
/// - identity.first_name, identity.email, identity.phone_numbers
|
||||
/// - alias.email, alias.first_name (legacy)
|
||||
/// Custom fields have FieldKey = NULL and are identified by their GUID and Label.
|
||||
/// </summary>
|
||||
[StringLength(100)]
|
||||
public string? FieldKey { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the field type (Text, Password, Email, URL, Date, etc.).
|
||||
/// </summary>
|
||||
|
||||
@@ -13,6 +13,7 @@ using AliasClientDb.Abstracts;
|
||||
|
||||
/// <summary>
|
||||
/// FieldValue entity that stores encrypted field values.
|
||||
/// Supports both system fields (with FieldKey) and custom fields (with FieldDefinitionId).
|
||||
/// </summary>
|
||||
public class FieldValue : SyncableEntity
|
||||
{
|
||||
@@ -35,16 +36,27 @@ public class FieldValue : SyncableEntity
|
||||
public virtual Item Item { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the field definition ID.
|
||||
/// Gets or sets the field definition ID for custom (user-defined) fields.
|
||||
/// NULL for system fields (which use FieldKey instead).
|
||||
/// </summary>
|
||||
[Required]
|
||||
public Guid FieldDefinitionId { get; set; }
|
||||
public Guid? FieldDefinitionId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the field definition object.
|
||||
/// Gets or sets the field definition object for custom fields.
|
||||
/// NULL for system fields.
|
||||
/// </summary>
|
||||
[ForeignKey("FieldDefinitionId")]
|
||||
public virtual FieldDefinition FieldDefinition { get; set; } = null!;
|
||||
public virtual FieldDefinition? FieldDefinition { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the system field key for predefined fields (e.g., 'login.username').
|
||||
/// NULL for custom (user-defined) fields (which use FieldDefinitionId instead).
|
||||
/// System field metadata (label, type, etc.) is defined in code (SystemFieldRegistry),
|
||||
/// not in the database.
|
||||
/// Note: Exactly one of FieldKey or FieldDefinitionId must be non-null.
|
||||
/// </summary>
|
||||
[StringLength(100)]
|
||||
public string? FieldKey { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the encrypted value.
|
||||
|
||||
@@ -1,580 +0,0 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using AliasClientDb;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace AliasClientDb.Migrations
|
||||
{
|
||||
[DbContext(typeof(AliasClientDbContext))]
|
||||
[Migration("20251126211441_1.7.0-FieldBasedDataModelUpdate")]
|
||||
partial class _170FieldBasedDataModelUpdate
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "9.0.4")
|
||||
.HasAnnotation("Proxies:ChangeTracking", false)
|
||||
.HasAnnotation("Proxies:CheckEquality", false)
|
||||
.HasAnnotation("Proxies:LazyLoading", true);
|
||||
|
||||
modelBuilder.Entity("AliasClientDb.Attachment", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<byte[]>("Blob")
|
||||
.IsRequired()
|
||||
.HasColumnType("BLOB");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Filename")
|
||||
.IsRequired()
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("IsDeleted")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<Guid>("ItemId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("UpdatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("ItemId");
|
||||
|
||||
b.ToTable("Attachments");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("AliasClientDb.EncryptionKey", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("IsDeleted")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("IsPrimary")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("PrivateKey")
|
||||
.IsRequired()
|
||||
.HasMaxLength(2000)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("PublicKey")
|
||||
.IsRequired()
|
||||
.HasMaxLength(2000)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("UpdatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("EncryptionKeys");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("AliasClientDb.FieldDefinition", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("ApplicableToTypes")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("DefaultVisibility")
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("DisplayOrder")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("EnableHistory")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("EntityType")
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("FieldKey")
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("FieldType")
|
||||
.IsRequired()
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("IsDeleted")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("IsMultiValue")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Label")
|
||||
.IsRequired()
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("UpdatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("FieldKey");
|
||||
|
||||
b.ToTable("FieldDefinitions");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("AliasClientDb.FieldHistory", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("ChangedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<Guid>("FieldDefinitionId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("IsDeleted")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<Guid>("ItemId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("UpdatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("ValueSnapshot")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("FieldDefinitionId");
|
||||
|
||||
b.HasIndex("ItemId");
|
||||
|
||||
b.ToTable("FieldHistories");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("AliasClientDb.FieldValue", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<Guid>("FieldDefinitionId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("IsDeleted")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<Guid>("ItemId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("UpdatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Value")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("ValueIndex")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("FieldDefinitionId");
|
||||
|
||||
b.HasIndex("ItemId");
|
||||
|
||||
b.HasIndex("ItemId", "FieldDefinitionId", "ValueIndex");
|
||||
|
||||
b.ToTable("FieldValues");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("AliasClientDb.Folder", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("DisplayOrder")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("IsDeleted")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<Guid?>("ParentFolderId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("UpdatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("ParentFolderId");
|
||||
|
||||
b.ToTable("Folders");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("AliasClientDb.Item", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<Guid?>("FolderId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("IsDeleted")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("ItemType")
|
||||
.IsRequired()
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<Guid?>("LogoId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("UpdatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("FolderId");
|
||||
|
||||
b.HasIndex("LogoId");
|
||||
|
||||
b.ToTable("Items");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("AliasClientDb.Logo", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime?>("FetchedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<byte[]>("FileData")
|
||||
.HasColumnType("BLOB");
|
||||
|
||||
b.Property<bool>("IsDeleted")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("MimeType")
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Source")
|
||||
.IsRequired()
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("UpdatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("Source")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("Logos");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("AliasClientDb.Passkey", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<byte[]>("AdditionalData")
|
||||
.HasColumnType("BLOB");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("DisplayName")
|
||||
.IsRequired()
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("IsDeleted")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<Guid>("ItemId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<byte[]>("PrfKey")
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("BLOB");
|
||||
|
||||
b.Property<string>("PrivateKey")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("PublicKey")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("RpId")
|
||||
.IsRequired()
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("TEXT")
|
||||
.UseCollation("NOCASE");
|
||||
|
||||
b.Property<DateTime>("UpdatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<byte[]>("UserHandle")
|
||||
.IsRequired()
|
||||
.HasColumnType("BLOB");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("ItemId");
|
||||
|
||||
b.HasIndex("RpId");
|
||||
|
||||
b.ToTable("Passkeys");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("AliasClientDb.Setting", b =>
|
||||
{
|
||||
b.Property<string>("Key")
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("IsDeleted")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTime>("UpdatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Value")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Key");
|
||||
|
||||
b.ToTable("Settings");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("AliasClientDb.TotpCode", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("IsDeleted")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<Guid>("ItemId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("SecretKey")
|
||||
.IsRequired()
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("UpdatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("ItemId");
|
||||
|
||||
b.ToTable("TotpCodes");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("AliasClientDb.Attachment", b =>
|
||||
{
|
||||
b.HasOne("AliasClientDb.Item", "Item")
|
||||
.WithMany("Attachments")
|
||||
.HasForeignKey("ItemId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Item");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("AliasClientDb.FieldHistory", b =>
|
||||
{
|
||||
b.HasOne("AliasClientDb.FieldDefinition", "FieldDefinition")
|
||||
.WithMany("FieldHistories")
|
||||
.HasForeignKey("FieldDefinitionId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("AliasClientDb.Item", "Item")
|
||||
.WithMany()
|
||||
.HasForeignKey("ItemId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("FieldDefinition");
|
||||
|
||||
b.Navigation("Item");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("AliasClientDb.FieldValue", b =>
|
||||
{
|
||||
b.HasOne("AliasClientDb.FieldDefinition", "FieldDefinition")
|
||||
.WithMany("FieldValues")
|
||||
.HasForeignKey("FieldDefinitionId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("AliasClientDb.Item", "Item")
|
||||
.WithMany("FieldValues")
|
||||
.HasForeignKey("ItemId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("FieldDefinition");
|
||||
|
||||
b.Navigation("Item");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("AliasClientDb.Folder", b =>
|
||||
{
|
||||
b.HasOne("AliasClientDb.Folder", "ParentFolder")
|
||||
.WithMany("ChildFolders")
|
||||
.HasForeignKey("ParentFolderId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
b.Navigation("ParentFolder");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("AliasClientDb.Item", b =>
|
||||
{
|
||||
b.HasOne("AliasClientDb.Folder", "Folder")
|
||||
.WithMany("Items")
|
||||
.HasForeignKey("FolderId")
|
||||
.OnDelete(DeleteBehavior.SetNull);
|
||||
|
||||
b.HasOne("AliasClientDb.Logo", "Logo")
|
||||
.WithMany("Items")
|
||||
.HasForeignKey("LogoId")
|
||||
.OnDelete(DeleteBehavior.SetNull);
|
||||
|
||||
b.Navigation("Folder");
|
||||
|
||||
b.Navigation("Logo");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("AliasClientDb.Passkey", b =>
|
||||
{
|
||||
b.HasOne("AliasClientDb.Item", "Item")
|
||||
.WithMany("Passkeys")
|
||||
.HasForeignKey("ItemId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Item");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("AliasClientDb.TotpCode", b =>
|
||||
{
|
||||
b.HasOne("AliasClientDb.Item", "Item")
|
||||
.WithMany("TotpCodes")
|
||||
.HasForeignKey("ItemId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Item");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("AliasClientDb.FieldDefinition", b =>
|
||||
{
|
||||
b.Navigation("FieldHistories");
|
||||
|
||||
b.Navigation("FieldValues");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("AliasClientDb.Folder", b =>
|
||||
{
|
||||
b.Navigation("ChildFolders");
|
||||
|
||||
b.Navigation("Items");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("AliasClientDb.Item", b =>
|
||||
{
|
||||
b.Navigation("Attachments");
|
||||
|
||||
b.Navigation("FieldValues");
|
||||
|
||||
b.Navigation("Passkeys");
|
||||
|
||||
b.Navigation("TotpCodes");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("AliasClientDb.Logo", b =>
|
||||
{
|
||||
b.Navigation("Items");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,575 +0,0 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using AliasClientDb;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace AliasClientDb.Migrations
|
||||
{
|
||||
[DbContext(typeof(AliasClientDbContext))]
|
||||
[Migration("20251126221717_1.7.1-RenameColumns")]
|
||||
partial class _171RenameColumns
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "9.0.4")
|
||||
.HasAnnotation("Proxies:ChangeTracking", false)
|
||||
.HasAnnotation("Proxies:CheckEquality", false)
|
||||
.HasAnnotation("Proxies:LazyLoading", true);
|
||||
|
||||
modelBuilder.Entity("AliasClientDb.Attachment", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<byte[]>("Blob")
|
||||
.IsRequired()
|
||||
.HasColumnType("BLOB");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Filename")
|
||||
.IsRequired()
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("IsDeleted")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<Guid>("ItemId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("UpdatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("ItemId");
|
||||
|
||||
b.ToTable("Attachments");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("AliasClientDb.EncryptionKey", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("IsDeleted")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("IsPrimary")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("PrivateKey")
|
||||
.IsRequired()
|
||||
.HasMaxLength(2000)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("PublicKey")
|
||||
.IsRequired()
|
||||
.HasMaxLength(2000)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("UpdatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("EncryptionKeys");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("AliasClientDb.FieldDefinition", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("ApplicableToTypes")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("EnableHistory")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("FieldKey")
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("FieldType")
|
||||
.IsRequired()
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("IsDeleted")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("IsHidden")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("IsMultiValue")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Label")
|
||||
.IsRequired()
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("UpdatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("Weight")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("FieldKey");
|
||||
|
||||
b.ToTable("FieldDefinitions");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("AliasClientDb.FieldHistory", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("ChangedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<Guid>("FieldDefinitionId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("IsDeleted")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<Guid>("ItemId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("UpdatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("ValueSnapshot")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("FieldDefinitionId");
|
||||
|
||||
b.HasIndex("ItemId");
|
||||
|
||||
b.ToTable("FieldHistories");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("AliasClientDb.FieldValue", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<Guid>("FieldDefinitionId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("IsDeleted")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<Guid>("ItemId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("UpdatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Value")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("Weight")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("FieldDefinitionId");
|
||||
|
||||
b.HasIndex("ItemId");
|
||||
|
||||
b.HasIndex("ItemId", "FieldDefinitionId", "Weight");
|
||||
|
||||
b.ToTable("FieldValues");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("AliasClientDb.Folder", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("IsDeleted")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<Guid?>("ParentFolderId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("UpdatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("Weight")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("ParentFolderId");
|
||||
|
||||
b.ToTable("Folders");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("AliasClientDb.Item", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<Guid?>("FolderId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("IsDeleted")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("ItemType")
|
||||
.IsRequired()
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<Guid?>("LogoId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("UpdatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("FolderId");
|
||||
|
||||
b.HasIndex("LogoId");
|
||||
|
||||
b.ToTable("Items");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("AliasClientDb.Logo", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime?>("FetchedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<byte[]>("FileData")
|
||||
.HasColumnType("BLOB");
|
||||
|
||||
b.Property<bool>("IsDeleted")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("MimeType")
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Source")
|
||||
.IsRequired()
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("UpdatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("Source")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("Logos");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("AliasClientDb.Passkey", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<byte[]>("AdditionalData")
|
||||
.HasColumnType("BLOB");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("DisplayName")
|
||||
.IsRequired()
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("IsDeleted")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<Guid>("ItemId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<byte[]>("PrfKey")
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("BLOB");
|
||||
|
||||
b.Property<string>("PrivateKey")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("PublicKey")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("RpId")
|
||||
.IsRequired()
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("TEXT")
|
||||
.UseCollation("NOCASE");
|
||||
|
||||
b.Property<DateTime>("UpdatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<byte[]>("UserHandle")
|
||||
.IsRequired()
|
||||
.HasColumnType("BLOB");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("ItemId");
|
||||
|
||||
b.HasIndex("RpId");
|
||||
|
||||
b.ToTable("Passkeys");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("AliasClientDb.Setting", b =>
|
||||
{
|
||||
b.Property<string>("Key")
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("IsDeleted")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTime>("UpdatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Value")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Key");
|
||||
|
||||
b.ToTable("Settings");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("AliasClientDb.TotpCode", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("IsDeleted")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<Guid>("ItemId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("SecretKey")
|
||||
.IsRequired()
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("UpdatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("ItemId");
|
||||
|
||||
b.ToTable("TotpCodes");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("AliasClientDb.Attachment", b =>
|
||||
{
|
||||
b.HasOne("AliasClientDb.Item", "Item")
|
||||
.WithMany("Attachments")
|
||||
.HasForeignKey("ItemId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Item");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("AliasClientDb.FieldHistory", b =>
|
||||
{
|
||||
b.HasOne("AliasClientDb.FieldDefinition", "FieldDefinition")
|
||||
.WithMany("FieldHistories")
|
||||
.HasForeignKey("FieldDefinitionId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("AliasClientDb.Item", "Item")
|
||||
.WithMany()
|
||||
.HasForeignKey("ItemId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("FieldDefinition");
|
||||
|
||||
b.Navigation("Item");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("AliasClientDb.FieldValue", b =>
|
||||
{
|
||||
b.HasOne("AliasClientDb.FieldDefinition", "FieldDefinition")
|
||||
.WithMany("FieldValues")
|
||||
.HasForeignKey("FieldDefinitionId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("AliasClientDb.Item", "Item")
|
||||
.WithMany("FieldValues")
|
||||
.HasForeignKey("ItemId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("FieldDefinition");
|
||||
|
||||
b.Navigation("Item");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("AliasClientDb.Folder", b =>
|
||||
{
|
||||
b.HasOne("AliasClientDb.Folder", "ParentFolder")
|
||||
.WithMany("ChildFolders")
|
||||
.HasForeignKey("ParentFolderId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
b.Navigation("ParentFolder");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("AliasClientDb.Item", b =>
|
||||
{
|
||||
b.HasOne("AliasClientDb.Folder", "Folder")
|
||||
.WithMany("Items")
|
||||
.HasForeignKey("FolderId")
|
||||
.OnDelete(DeleteBehavior.SetNull);
|
||||
|
||||
b.HasOne("AliasClientDb.Logo", "Logo")
|
||||
.WithMany("Items")
|
||||
.HasForeignKey("LogoId")
|
||||
.OnDelete(DeleteBehavior.SetNull);
|
||||
|
||||
b.Navigation("Folder");
|
||||
|
||||
b.Navigation("Logo");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("AliasClientDb.Passkey", b =>
|
||||
{
|
||||
b.HasOne("AliasClientDb.Item", "Item")
|
||||
.WithMany("Passkeys")
|
||||
.HasForeignKey("ItemId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Item");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("AliasClientDb.TotpCode", b =>
|
||||
{
|
||||
b.HasOne("AliasClientDb.Item", "Item")
|
||||
.WithMany("TotpCodes")
|
||||
.HasForeignKey("ItemId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Item");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("AliasClientDb.FieldDefinition", b =>
|
||||
{
|
||||
b.Navigation("FieldHistories");
|
||||
|
||||
b.Navigation("FieldValues");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("AliasClientDb.Folder", b =>
|
||||
{
|
||||
b.Navigation("ChildFolders");
|
||||
|
||||
b.Navigation("Items");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("AliasClientDb.Item", b =>
|
||||
{
|
||||
b.Navigation("Attachments");
|
||||
|
||||
b.Navigation("FieldValues");
|
||||
|
||||
b.Navigation("Passkeys");
|
||||
|
||||
b.Navigation("TotpCodes");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("AliasClientDb.Logo", b =>
|
||||
{
|
||||
b.Navigation("Items");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,93 +0,0 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace AliasClientDb.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class _171RenameColumns : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "DefaultVisibility",
|
||||
table: "FieldDefinitions");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "EntityType",
|
||||
table: "FieldDefinitions");
|
||||
|
||||
migrationBuilder.RenameColumn(
|
||||
name: "DisplayOrder",
|
||||
table: "Folders",
|
||||
newName: "Weight");
|
||||
|
||||
migrationBuilder.RenameColumn(
|
||||
name: "ValueIndex",
|
||||
table: "FieldValues",
|
||||
newName: "Weight");
|
||||
|
||||
migrationBuilder.RenameIndex(
|
||||
name: "IX_FieldValues_ItemId_FieldDefinitionId_ValueIndex",
|
||||
table: "FieldValues",
|
||||
newName: "IX_FieldValues_ItemId_FieldDefinitionId_Weight");
|
||||
|
||||
migrationBuilder.RenameColumn(
|
||||
name: "DisplayOrder",
|
||||
table: "FieldDefinitions",
|
||||
newName: "Weight");
|
||||
|
||||
migrationBuilder.AddColumn<bool>(
|
||||
name: "IsHidden",
|
||||
table: "FieldDefinitions",
|
||||
type: "INTEGER",
|
||||
nullable: false,
|
||||
defaultValue: false);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "IsHidden",
|
||||
table: "FieldDefinitions");
|
||||
|
||||
migrationBuilder.RenameColumn(
|
||||
name: "Weight",
|
||||
table: "Folders",
|
||||
newName: "DisplayOrder");
|
||||
|
||||
migrationBuilder.RenameColumn(
|
||||
name: "Weight",
|
||||
table: "FieldValues",
|
||||
newName: "ValueIndex");
|
||||
|
||||
migrationBuilder.RenameIndex(
|
||||
name: "IX_FieldValues_ItemId_FieldDefinitionId_Weight",
|
||||
table: "FieldValues",
|
||||
newName: "IX_FieldValues_ItemId_FieldDefinitionId_ValueIndex");
|
||||
|
||||
migrationBuilder.RenameColumn(
|
||||
name: "Weight",
|
||||
table: "FieldDefinitions",
|
||||
newName: "DisplayOrder");
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "DefaultVisibility",
|
||||
table: "FieldDefinitions",
|
||||
type: "TEXT",
|
||||
maxLength: 50,
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "EntityType",
|
||||
table: "FieldDefinitions",
|
||||
type: "TEXT",
|
||||
maxLength: 50,
|
||||
nullable: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,92 +0,0 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace AliasClientDb.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class _172AddTagTables : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.CreateTable(
|
||||
name: "Tags",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<Guid>(type: "TEXT", nullable: false),
|
||||
Name = table.Column<string>(type: "TEXT", maxLength: 255, nullable: false),
|
||||
Color = table.Column<string>(type: "TEXT", maxLength: 50, nullable: true),
|
||||
DisplayOrder = table.Column<int>(type: "INTEGER", nullable: false),
|
||||
CreatedAt = table.Column<DateTime>(type: "TEXT", nullable: false),
|
||||
UpdatedAt = table.Column<DateTime>(type: "TEXT", nullable: false),
|
||||
IsDeleted = table.Column<bool>(type: "INTEGER", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_Tags", x => x.Id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "ItemTags",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<Guid>(type: "TEXT", nullable: false),
|
||||
ItemId = table.Column<Guid>(type: "TEXT", nullable: false),
|
||||
TagId = table.Column<Guid>(type: "TEXT", nullable: false),
|
||||
CreatedAt = table.Column<DateTime>(type: "TEXT", nullable: false),
|
||||
UpdatedAt = table.Column<DateTime>(type: "TEXT", nullable: false),
|
||||
IsDeleted = table.Column<bool>(type: "INTEGER", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_ItemTags", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_ItemTags_Items_ItemId",
|
||||
column: x => x.ItemId,
|
||||
principalTable: "Items",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
table.ForeignKey(
|
||||
name: "FK_ItemTags_Tags_TagId",
|
||||
column: x => x.TagId,
|
||||
principalTable: "Tags",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_ItemTags_ItemId",
|
||||
table: "ItemTags",
|
||||
column: "ItemId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_ItemTags_ItemId_TagId",
|
||||
table: "ItemTags",
|
||||
columns: new[] { "ItemId", "TagId" },
|
||||
unique: true);
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_ItemTags_TagId",
|
||||
table: "ItemTags",
|
||||
column: "TagId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Tags_Name",
|
||||
table: "Tags",
|
||||
column: "Name");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "ItemTags");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "Tags");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,8 +11,8 @@ using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
namespace AliasClientDb.Migrations
|
||||
{
|
||||
[DbContext(typeof(AliasClientDbContext))]
|
||||
[Migration("20251202211204_1.7.2-AddTagTables")]
|
||||
partial class _172AddTagTables
|
||||
[Migration("20251203162345_1.7.0-FieldBasedDataModelUpdate")]
|
||||
partial class _170FieldBasedDataModelUpdate
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
@@ -106,10 +106,6 @@ namespace AliasClientDb.Migrations
|
||||
b.Property<bool>("EnableHistory")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("FieldKey")
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("FieldType")
|
||||
.IsRequired()
|
||||
.HasMaxLength(50)
|
||||
@@ -137,8 +133,6 @@ namespace AliasClientDb.Migrations
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("FieldKey");
|
||||
|
||||
b.ToTable("FieldDefinitions");
|
||||
});
|
||||
|
||||
@@ -188,7 +182,11 @@ namespace AliasClientDb.Migrations
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<Guid>("FieldDefinitionId")
|
||||
b.Property<Guid?>("FieldDefinitionId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("FieldKey")
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("IsDeleted")
|
||||
@@ -210,8 +208,12 @@ namespace AliasClientDb.Migrations
|
||||
|
||||
b.HasIndex("FieldDefinitionId");
|
||||
|
||||
b.HasIndex("FieldKey");
|
||||
|
||||
b.HasIndex("ItemId");
|
||||
|
||||
b.HasIndex("ItemId", "FieldKey");
|
||||
|
||||
b.HasIndex("ItemId", "FieldDefinitionId", "Weight");
|
||||
|
||||
b.ToTable("FieldValues");
|
||||
@@ -544,8 +546,7 @@ namespace AliasClientDb.Migrations
|
||||
b.HasOne("AliasClientDb.FieldDefinition", "FieldDefinition")
|
||||
.WithMany("FieldValues")
|
||||
.HasForeignKey("FieldDefinitionId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
b.HasOne("AliasClientDb.Item", "Item")
|
||||
.WithMany("FieldValues")
|
||||
@@ -1,11 +1,11 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace AliasClientDb.Migrations
|
||||
{
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
/// <inheritdoc />
|
||||
public partial class _170FieldBasedDataModelUpdate : Migration
|
||||
{
|
||||
@@ -56,18 +56,16 @@ namespace AliasClientDb.Migrations
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<Guid>(type: "TEXT", nullable: false),
|
||||
FieldKey = table.Column<string>(type: "TEXT", maxLength: 100, nullable: true),
|
||||
EntityType = table.Column<string>(type: "TEXT", maxLength: 50, nullable: true),
|
||||
FieldType = table.Column<string>(type: "TEXT", maxLength: 50, nullable: false),
|
||||
Label = table.Column<string>(type: "TEXT", maxLength: 255, nullable: false),
|
||||
IsMultiValue = table.Column<bool>(type: "INTEGER", nullable: false),
|
||||
DefaultVisibility = table.Column<string>(type: "TEXT", maxLength: 50, nullable: true),
|
||||
IsHidden = table.Column<bool>(type: "INTEGER", nullable: false),
|
||||
EnableHistory = table.Column<bool>(type: "INTEGER", nullable: false),
|
||||
DisplayOrder = table.Column<int>(type: "INTEGER", nullable: false),
|
||||
Weight = table.Column<int>(type: "INTEGER", nullable: false),
|
||||
ApplicableToTypes = table.Column<string>(type: "TEXT", nullable: true),
|
||||
CreatedAt = table.Column<DateTime>(type: "TEXT", nullable: false),
|
||||
UpdatedAt = table.Column<DateTime>(type: "TEXT", nullable: false),
|
||||
IsDeleted = table.Column<bool>(type: "INTEGER", nullable: false)
|
||||
IsDeleted = table.Column<bool>(type: "INTEGER", nullable: false),
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
@@ -81,10 +79,10 @@ namespace AliasClientDb.Migrations
|
||||
Id = table.Column<Guid>(type: "TEXT", nullable: false),
|
||||
Name = table.Column<string>(type: "TEXT", maxLength: 255, nullable: false),
|
||||
ParentFolderId = table.Column<Guid>(type: "TEXT", nullable: true),
|
||||
DisplayOrder = table.Column<int>(type: "INTEGER", nullable: false),
|
||||
Weight = table.Column<int>(type: "INTEGER", nullable: false),
|
||||
CreatedAt = table.Column<DateTime>(type: "TEXT", nullable: false),
|
||||
UpdatedAt = table.Column<DateTime>(type: "TEXT", nullable: false),
|
||||
IsDeleted = table.Column<bool>(type: "INTEGER", nullable: false)
|
||||
IsDeleted = table.Column<bool>(type: "INTEGER", nullable: false),
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
@@ -108,13 +106,30 @@ namespace AliasClientDb.Migrations
|
||||
FetchedAt = table.Column<DateTime>(type: "TEXT", nullable: true),
|
||||
CreatedAt = table.Column<DateTime>(type: "TEXT", nullable: false),
|
||||
UpdatedAt = table.Column<DateTime>(type: "TEXT", nullable: false),
|
||||
IsDeleted = table.Column<bool>(type: "INTEGER", nullable: false)
|
||||
IsDeleted = table.Column<bool>(type: "INTEGER", nullable: false),
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_Logos", x => x.Id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "Tags",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<Guid>(type: "TEXT", nullable: false),
|
||||
Name = table.Column<string>(type: "TEXT", maxLength: 255, nullable: false),
|
||||
Color = table.Column<string>(type: "TEXT", maxLength: 50, nullable: true),
|
||||
DisplayOrder = table.Column<int>(type: "INTEGER", nullable: false),
|
||||
CreatedAt = table.Column<DateTime>(type: "TEXT", nullable: false),
|
||||
UpdatedAt = table.Column<DateTime>(type: "TEXT", nullable: false),
|
||||
IsDeleted = table.Column<bool>(type: "INTEGER", nullable: false),
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_Tags", x => x.Id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "Items",
|
||||
columns: table => new
|
||||
@@ -126,7 +141,7 @@ namespace AliasClientDb.Migrations
|
||||
FolderId = table.Column<Guid>(type: "TEXT", nullable: true),
|
||||
CreatedAt = table.Column<DateTime>(type: "TEXT", nullable: false),
|
||||
UpdatedAt = table.Column<DateTime>(type: "TEXT", nullable: false),
|
||||
IsDeleted = table.Column<bool>(type: "INTEGER", nullable: false)
|
||||
IsDeleted = table.Column<bool>(type: "INTEGER", nullable: false),
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
@@ -156,7 +171,7 @@ namespace AliasClientDb.Migrations
|
||||
ChangedAt = table.Column<DateTime>(type: "TEXT", nullable: false),
|
||||
CreatedAt = table.Column<DateTime>(type: "TEXT", nullable: false),
|
||||
UpdatedAt = table.Column<DateTime>(type: "TEXT", nullable: false),
|
||||
IsDeleted = table.Column<bool>(type: "INTEGER", nullable: false)
|
||||
IsDeleted = table.Column<bool>(type: "INTEGER", nullable: false),
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
@@ -181,12 +196,13 @@ namespace AliasClientDb.Migrations
|
||||
{
|
||||
Id = table.Column<Guid>(type: "TEXT", nullable: false),
|
||||
ItemId = table.Column<Guid>(type: "TEXT", nullable: false),
|
||||
FieldDefinitionId = table.Column<Guid>(type: "TEXT", nullable: false),
|
||||
FieldDefinitionId = table.Column<Guid>(type: "TEXT", nullable: true),
|
||||
FieldKey = table.Column<string>(type: "TEXT", maxLength: 100, nullable: true),
|
||||
Value = table.Column<string>(type: "TEXT", nullable: true),
|
||||
ValueIndex = table.Column<int>(type: "INTEGER", nullable: false),
|
||||
Weight = table.Column<int>(type: "INTEGER", nullable: false),
|
||||
CreatedAt = table.Column<DateTime>(type: "TEXT", nullable: false),
|
||||
UpdatedAt = table.Column<DateTime>(type: "TEXT", nullable: false),
|
||||
IsDeleted = table.Column<bool>(type: "INTEGER", nullable: false)
|
||||
IsDeleted = table.Column<bool>(type: "INTEGER", nullable: false),
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
@@ -205,10 +221,33 @@ namespace AliasClientDb.Migrations
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_FieldDefinitions_FieldKey",
|
||||
table: "FieldDefinitions",
|
||||
column: "FieldKey");
|
||||
migrationBuilder.CreateTable(
|
||||
name: "ItemTags",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<Guid>(type: "TEXT", nullable: false),
|
||||
ItemId = table.Column<Guid>(type: "TEXT", nullable: false),
|
||||
TagId = table.Column<Guid>(type: "TEXT", nullable: false),
|
||||
CreatedAt = table.Column<DateTime>(type: "TEXT", nullable: false),
|
||||
UpdatedAt = table.Column<DateTime>(type: "TEXT", nullable: false),
|
||||
IsDeleted = table.Column<bool>(type: "INTEGER", nullable: false),
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_ItemTags", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_ItemTags_Items_ItemId",
|
||||
column: x => x.ItemId,
|
||||
principalTable: "Items",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
table.ForeignKey(
|
||||
name: "FK_ItemTags_Tags_TagId",
|
||||
column: x => x.TagId,
|
||||
principalTable: "Tags",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_FieldHistories_FieldDefinitionId",
|
||||
@@ -225,15 +264,25 @@ namespace AliasClientDb.Migrations
|
||||
table: "FieldValues",
|
||||
column: "FieldDefinitionId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_FieldValues_FieldKey",
|
||||
table: "FieldValues",
|
||||
column: "FieldKey");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_FieldValues_ItemId",
|
||||
table: "FieldValues",
|
||||
column: "ItemId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_FieldValues_ItemId_FieldDefinitionId_ValueIndex",
|
||||
name: "IX_FieldValues_ItemId_FieldDefinitionId_Weight",
|
||||
table: "FieldValues",
|
||||
columns: new[] { "ItemId", "FieldDefinitionId", "ValueIndex" });
|
||||
columns: new[] { "ItemId", "FieldDefinitionId", "Weight" });
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_FieldValues_ItemId_FieldKey",
|
||||
table: "FieldValues",
|
||||
columns: new[] { "ItemId", "FieldKey" });
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Folders_ParentFolderId",
|
||||
@@ -250,12 +299,33 @@ namespace AliasClientDb.Migrations
|
||||
table: "Items",
|
||||
column: "LogoId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_ItemTags_ItemId",
|
||||
table: "ItemTags",
|
||||
column: "ItemId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_ItemTags_ItemId_TagId",
|
||||
table: "ItemTags",
|
||||
columns: new[] { "ItemId", "TagId" },
|
||||
unique: true);
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_ItemTags_TagId",
|
||||
table: "ItemTags",
|
||||
column: "TagId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Logos_Source",
|
||||
table: "Logos",
|
||||
column: "Source",
|
||||
unique: true);
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Tags_Name",
|
||||
table: "Tags",
|
||||
column: "Name");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_Attachments_Items_ItemId",
|
||||
table: "Attachments",
|
||||
@@ -280,33 +350,10 @@ namespace AliasClientDb.Migrations
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
// ==============================================================
|
||||
// CUSTOM DATA MIGRATION SCRIPT
|
||||
// Migrates existing data from old schema to V5 field-based schema
|
||||
// ==============================================================
|
||||
// Data migration: Migrate from old Credentials/Services/Aliases structure to new Items/FieldValues structure
|
||||
// System fields now use FieldKey directly in FieldValues (no FieldDefinitions needed)
|
||||
|
||||
// Step 1: Populate core FieldDefinitions (system fields)
|
||||
migrationBuilder.Sql(@"
|
||||
-- Login fields
|
||||
INSERT INTO FieldDefinitions (Id, FieldKey, EntityType, FieldType, Label, IsMultiValue, DefaultVisibility, EnableHistory, DisplayOrder, ApplicableToTypes, CreatedAt, UpdatedAt, IsDeleted)
|
||||
VALUES
|
||||
(lower(hex(randomblob(16))), 'login.username', 'Item', 'Text', 'Username', 0, 'Visible', 1, 0, '[""Login""]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'login.password', 'Item', 'Password', 'Password', 0, 'Hidden', 1, 0, '[""Login""]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'login.notes', 'Item', 'Text', 'Notes', 0, 'Collapsed', 0, 0, NULL, datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'login.url', 'Item', 'URL', 'Website URLs', 1, 'Visible', 0, 0, '[""Login""]', datetime('now'), datetime('now'), 0);
|
||||
|
||||
-- Alias fields
|
||||
INSERT INTO FieldDefinitions (Id, FieldKey, EntityType, FieldType, Label, IsMultiValue, DefaultVisibility, EnableHistory, DisplayOrder, ApplicableToTypes, CreatedAt, UpdatedAt, IsDeleted)
|
||||
VALUES
|
||||
(lower(hex(randomblob(16))), 'alias.email', 'Item', 'Email', 'Alias Email', 0, 'Visible', 1, 0, '[""Login""]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'alias.first_name', 'Item', 'Text', 'First Name', 0, 'Visible', 0, 0, '[""Login""]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'alias.last_name', 'Item', 'Text', 'Last Name', 0, 'Visible', 0, 0, '[""Login""]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'alias.nickname', 'Item', 'Text', 'Nickname', 0, 'Visible', 0, 0, '[""Login""]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'alias.gender', 'Item', 'Text', 'Gender', 0, 'Visible', 0, 0, '[""Login""]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'alias.birthdate', 'Item', 'Date', 'Birth Date', 0, 'Visible', 0, 0, '[""Login""]', datetime('now'), datetime('now'), 0);
|
||||
");
|
||||
|
||||
// Step 2: Migrate Credentials to Items
|
||||
// Migrate Items from Credentials
|
||||
migrationBuilder.Sql(@"
|
||||
INSERT INTO Items (Id, Name, ItemType, LogoId, FolderId, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
@@ -322,7 +369,7 @@ namespace AliasClientDb.Migrations
|
||||
LEFT JOIN Services s ON s.Id = c.ServiceId;
|
||||
");
|
||||
|
||||
// Step 3: Create Logo entries from Services (deduplicated)
|
||||
// Migrate Logos from Services
|
||||
migrationBuilder.Sql(@"
|
||||
INSERT INTO Logos (Id, Source, FileData, MimeType, FetchedAt, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
@@ -339,7 +386,7 @@ namespace AliasClientDb.Migrations
|
||||
GROUP BY s.Url;
|
||||
");
|
||||
|
||||
// Step 4: Link Items to Logos
|
||||
// Update Items with LogoId
|
||||
migrationBuilder.Sql(@"
|
||||
UPDATE Items
|
||||
SET LogoId = (
|
||||
@@ -356,15 +403,16 @@ namespace AliasClientDb.Migrations
|
||||
);
|
||||
");
|
||||
|
||||
// Step 5: Migrate Service.Url → FieldValue (multi-value URLs)
|
||||
// Migrate login.url field (system field using FieldKey)
|
||||
migrationBuilder.Sql(@"
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'login.url' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'login.url' AS FieldKey,
|
||||
s.Url AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
s.UpdatedAt AS CreatedAt,
|
||||
s.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
@@ -373,15 +421,16 @@ namespace AliasClientDb.Migrations
|
||||
WHERE s.Url IS NOT NULL AND s.Url != '';
|
||||
");
|
||||
|
||||
// Step 6: Migrate Credential.Username → FieldValue
|
||||
// Migrate login.username field (system field using FieldKey)
|
||||
migrationBuilder.Sql(@"
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'login.username' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'login.username' AS FieldKey,
|
||||
c.Username AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
c.UpdatedAt AS CreatedAt,
|
||||
c.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
@@ -389,15 +438,16 @@ namespace AliasClientDb.Migrations
|
||||
WHERE c.Username IS NOT NULL AND c.Username != '';
|
||||
");
|
||||
|
||||
// Step 7: Migrate Credential.Notes → FieldValue
|
||||
// Migrate login.notes field (system field using FieldKey)
|
||||
migrationBuilder.Sql(@"
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'login.notes' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'login.notes' AS FieldKey,
|
||||
c.Notes AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
c.UpdatedAt AS CreatedAt,
|
||||
c.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
@@ -405,135 +455,129 @@ namespace AliasClientDb.Migrations
|
||||
WHERE c.Notes IS NOT NULL AND c.Notes != '';
|
||||
");
|
||||
|
||||
// Step 8: Migrate Passwords → FieldValue (most recent password)
|
||||
// Password table stores plain text as whole client DB is encrypted
|
||||
// Migrate login.password field (system field using FieldKey) - only most recent password
|
||||
migrationBuilder.Sql(@"
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
p.CredentialId AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'login.password' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'login.password' AS FieldKey,
|
||||
p.Value AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
p.UpdatedAt AS CreatedAt,
|
||||
p.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Passwords p
|
||||
INNER JOIN (
|
||||
SELECT CredentialId, MAX(UpdatedAt) AS MaxUpdated
|
||||
SELECT CredentialId, MAX(UpdatedAt) AS MaxUpdated, MAX(Id) AS MaxId
|
||||
FROM Passwords
|
||||
WHERE IsDeleted = 0
|
||||
GROUP BY CredentialId
|
||||
) pm ON p.CredentialId = pm.CredentialId AND p.UpdatedAt = pm.MaxUpdated;
|
||||
) pm ON p.CredentialId = pm.CredentialId AND p.UpdatedAt = pm.MaxUpdated AND p.Id = pm.MaxId
|
||||
WHERE p.IsDeleted = 0;
|
||||
");
|
||||
|
||||
// Step 9: Migrate historical passwords → FieldHistory
|
||||
// Migrate alias.email field (system field using FieldKey)
|
||||
migrationBuilder.Sql(@"
|
||||
INSERT INTO FieldHistories (Id, ItemId, FieldDefinitionId, ValueSnapshot, ChangedAt, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
p.CredentialId AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'login.password' LIMIT 1) AS FieldDefinitionId,
|
||||
'{""values"":[""' || p.Value || '""]}' AS ValueSnapshot,
|
||||
p.UpdatedAt AS ChangedAt,
|
||||
p.CreatedAt AS CreatedAt,
|
||||
p.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Passwords p
|
||||
WHERE p.Id NOT IN (
|
||||
SELECT p2.Id FROM Passwords p2
|
||||
INNER JOIN (
|
||||
SELECT CredentialId, MAX(UpdatedAt) AS MaxUpdated
|
||||
FROM Passwords
|
||||
GROUP BY CredentialId
|
||||
) pm ON p2.CredentialId = pm.CredentialId AND p2.UpdatedAt = pm.MaxUpdated
|
||||
);
|
||||
");
|
||||
|
||||
// Step 10: Migrate Alias fields → FieldValues
|
||||
migrationBuilder.Sql(@"
|
||||
-- Migrate Alias.Email
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'alias.email' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'alias.email' AS FieldKey,
|
||||
a.Email AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
a.UpdatedAt AS CreatedAt,
|
||||
a.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Credentials c
|
||||
INNER JOIN Aliases a ON a.Id = c.AliasId
|
||||
WHERE a.Email IS NOT NULL AND a.Email != '';
|
||||
");
|
||||
|
||||
-- Migrate Alias.FirstName
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
// Migrate alias.first_name field (system field using FieldKey)
|
||||
migrationBuilder.Sql(@"
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'alias.first_name' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'alias.first_name' AS FieldKey,
|
||||
a.FirstName AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
a.UpdatedAt AS CreatedAt,
|
||||
a.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Credentials c
|
||||
INNER JOIN Aliases a ON a.Id = c.AliasId
|
||||
WHERE a.FirstName IS NOT NULL AND a.FirstName != '';
|
||||
");
|
||||
|
||||
-- Migrate Alias.LastName
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
// Migrate alias.last_name field (system field using FieldKey)
|
||||
migrationBuilder.Sql(@"
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'alias.last_name' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'alias.last_name' AS FieldKey,
|
||||
a.LastName AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
a.UpdatedAt AS CreatedAt,
|
||||
a.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Credentials c
|
||||
INNER JOIN Aliases a ON a.Id = c.AliasId
|
||||
WHERE a.LastName IS NOT NULL AND a.LastName != '';
|
||||
");
|
||||
|
||||
-- Migrate Alias.NickName
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
// Migrate alias.nickname field (system field using FieldKey)
|
||||
migrationBuilder.Sql(@"
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'alias.nickname' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'alias.nickname' AS FieldKey,
|
||||
a.NickName AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
a.UpdatedAt AS CreatedAt,
|
||||
a.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Credentials c
|
||||
INNER JOIN Aliases a ON a.Id = c.AliasId
|
||||
WHERE a.NickName IS NOT NULL AND a.NickName != '';
|
||||
");
|
||||
|
||||
-- Migrate Alias.Gender
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
// Migrate alias.gender field (system field using FieldKey)
|
||||
migrationBuilder.Sql(@"
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'alias.gender' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'alias.gender' AS FieldKey,
|
||||
a.Gender AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
a.UpdatedAt AS CreatedAt,
|
||||
a.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Credentials c
|
||||
INNER JOIN Aliases a ON a.Id = c.AliasId
|
||||
WHERE a.Gender IS NOT NULL AND a.Gender != '';
|
||||
");
|
||||
|
||||
-- Migrate Alias.BirthDate
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
// Migrate alias.birthdate field (system field using FieldKey)
|
||||
migrationBuilder.Sql(@"
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'alias.birthdate' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'alias.birthdate' AS FieldKey,
|
||||
a.BirthDate AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
a.UpdatedAt AS CreatedAt,
|
||||
a.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
@@ -542,14 +586,6 @@ namespace AliasClientDb.Migrations
|
||||
WHERE a.BirthDate IS NOT NULL AND a.BirthDate != '' AND a.BirthDate != '0001-01-01 00:00:00.000';
|
||||
");
|
||||
|
||||
// Step 11: Update foreign keys to reference Items instead of Credentials
|
||||
// NOTE: This step is not needed because RenameColumn already renamed CredentialId to ItemId
|
||||
// at the beginning of the migration, so the data is already in the correct column.
|
||||
|
||||
// ==============================================================
|
||||
// END OF CUSTOM DATA MIGRATION SCRIPT
|
||||
// ==============================================================
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "Passwords");
|
||||
|
||||
@@ -584,12 +620,18 @@ namespace AliasClientDb.Migrations
|
||||
migrationBuilder.DropTable(
|
||||
name: "FieldValues");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "ItemTags");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "FieldDefinitions");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "Items");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "Tags");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "Folders");
|
||||
|
||||
@@ -103,10 +103,6 @@ namespace AliasClientDb.Migrations
|
||||
b.Property<bool>("EnableHistory")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("FieldKey")
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("FieldType")
|
||||
.IsRequired()
|
||||
.HasMaxLength(50)
|
||||
@@ -134,8 +130,6 @@ namespace AliasClientDb.Migrations
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("FieldKey");
|
||||
|
||||
b.ToTable("FieldDefinitions");
|
||||
});
|
||||
|
||||
@@ -185,7 +179,11 @@ namespace AliasClientDb.Migrations
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<Guid>("FieldDefinitionId")
|
||||
b.Property<Guid?>("FieldDefinitionId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("FieldKey")
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("IsDeleted")
|
||||
@@ -207,8 +205,12 @@ namespace AliasClientDb.Migrations
|
||||
|
||||
b.HasIndex("FieldDefinitionId");
|
||||
|
||||
b.HasIndex("FieldKey");
|
||||
|
||||
b.HasIndex("ItemId");
|
||||
|
||||
b.HasIndex("ItemId", "FieldKey");
|
||||
|
||||
b.HasIndex("ItemId", "FieldDefinitionId", "Weight");
|
||||
|
||||
b.ToTable("FieldValues");
|
||||
@@ -541,8 +543,7 @@ namespace AliasClientDb.Migrations
|
||||
b.HasOne("AliasClientDb.FieldDefinition", "FieldDefinition")
|
||||
.WithMany("FieldValues")
|
||||
.HasForeignKey("FieldDefinitionId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
b.HasOne("AliasClientDb.Item", "Item")
|
||||
.WithMany("FieldValues")
|
||||
|
||||
@@ -690,14 +690,12 @@ CREATE INDEX IF NOT EXISTS "IX_Attachments_ItemId" ON "Attachments" ("ItemId");
|
||||
|
||||
CREATE TABLE "FieldDefinitions" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_FieldDefinitions" PRIMARY KEY,
|
||||
"FieldKey" TEXT NULL,
|
||||
"EntityType" TEXT NULL,
|
||||
"FieldType" TEXT NOT NULL,
|
||||
"Label" TEXT NOT NULL,
|
||||
"IsMultiValue" INTEGER NOT NULL,
|
||||
"DefaultVisibility" TEXT NULL,
|
||||
"IsHidden" INTEGER NOT NULL,
|
||||
"EnableHistory" INTEGER NOT NULL,
|
||||
"DisplayOrder" INTEGER NOT NULL,
|
||||
"Weight" INTEGER NOT NULL,
|
||||
"ApplicableToTypes" TEXT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
@@ -708,7 +706,7 @@ CREATE TABLE "Folders" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_Folders" PRIMARY KEY,
|
||||
"Name" TEXT NOT NULL,
|
||||
"ParentFolderId" TEXT NULL,
|
||||
"DisplayOrder" INTEGER NOT NULL,
|
||||
"Weight" INTEGER NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL,
|
||||
@@ -726,6 +724,16 @@ CREATE TABLE "Logos" (
|
||||
"IsDeleted" INTEGER NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE "Tags" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_Tags" PRIMARY KEY,
|
||||
"Name" TEXT NOT NULL,
|
||||
"Color" TEXT NULL,
|
||||
"DisplayOrder" INTEGER NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE "Items" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_Items" PRIMARY KEY,
|
||||
"Name" TEXT NULL,
|
||||
@@ -755,9 +763,10 @@ CREATE TABLE "FieldHistories" (
|
||||
CREATE TABLE "FieldValues" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_FieldValues" PRIMARY KEY,
|
||||
"ItemId" TEXT NOT NULL,
|
||||
"FieldDefinitionId" TEXT NOT NULL,
|
||||
"FieldDefinitionId" TEXT NULL,
|
||||
"FieldKey" TEXT NULL,
|
||||
"Value" TEXT NULL,
|
||||
"ValueIndex" INTEGER NOT NULL,
|
||||
"Weight" INTEGER NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL,
|
||||
@@ -765,7 +774,16 @@ CREATE TABLE "FieldValues" (
|
||||
CONSTRAINT "FK_FieldValues_Items_ItemId" FOREIGN KEY ("ItemId") REFERENCES "Items" ("Id") ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE INDEX "IX_FieldDefinitions_FieldKey" ON "FieldDefinitions" ("FieldKey");
|
||||
CREATE TABLE "ItemTags" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_ItemTags" PRIMARY KEY,
|
||||
"ItemId" TEXT NOT NULL,
|
||||
"TagId" TEXT NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL,
|
||||
CONSTRAINT "FK_ItemTags_Items_ItemId" FOREIGN KEY ("ItemId") REFERENCES "Items" ("Id") ON DELETE CASCADE,
|
||||
CONSTRAINT "FK_ItemTags_Tags_TagId" FOREIGN KEY ("TagId") REFERENCES "Tags" ("Id") ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE INDEX "IX_FieldHistories_FieldDefinitionId" ON "FieldHistories" ("FieldDefinitionId");
|
||||
|
||||
@@ -773,9 +791,13 @@ CREATE INDEX "IX_FieldHistories_ItemId" ON "FieldHistories" ("ItemId");
|
||||
|
||||
CREATE INDEX "IX_FieldValues_FieldDefinitionId" ON "FieldValues" ("FieldDefinitionId");
|
||||
|
||||
CREATE INDEX "IX_FieldValues_FieldKey" ON "FieldValues" ("FieldKey");
|
||||
|
||||
CREATE INDEX "IX_FieldValues_ItemId" ON "FieldValues" ("ItemId");
|
||||
|
||||
CREATE INDEX "IX_FieldValues_ItemId_FieldDefinitionId_ValueIndex" ON "FieldValues" ("ItemId", "FieldDefinitionId", "ValueIndex");
|
||||
CREATE INDEX "IX_FieldValues_ItemId_FieldDefinitionId_Weight" ON "FieldValues" ("ItemId", "FieldDefinitionId", "Weight");
|
||||
|
||||
CREATE INDEX "IX_FieldValues_ItemId_FieldKey" ON "FieldValues" ("ItemId", "FieldKey");
|
||||
|
||||
CREATE INDEX "IX_Folders_ParentFolderId" ON "Folders" ("ParentFolderId");
|
||||
|
||||
@@ -783,27 +805,15 @@ CREATE INDEX "IX_Items_FolderId" ON "Items" ("FolderId");
|
||||
|
||||
CREATE INDEX "IX_Items_LogoId" ON "Items" ("LogoId");
|
||||
|
||||
CREATE INDEX "IX_ItemTags_ItemId" ON "ItemTags" ("ItemId");
|
||||
|
||||
CREATE UNIQUE INDEX "IX_ItemTags_ItemId_TagId" ON "ItemTags" ("ItemId", "TagId");
|
||||
|
||||
CREATE INDEX "IX_ItemTags_TagId" ON "ItemTags" ("TagId");
|
||||
|
||||
CREATE UNIQUE INDEX "IX_Logos_Source" ON "Logos" ("Source");
|
||||
|
||||
|
||||
-- Login fields
|
||||
INSERT INTO FieldDefinitions (Id, FieldKey, EntityType, FieldType, Label, IsMultiValue, DefaultVisibility, EnableHistory, DisplayOrder, ApplicableToTypes, CreatedAt, UpdatedAt, IsDeleted)
|
||||
VALUES
|
||||
(lower(hex(randomblob(16))), 'login.username', 'Item', 'Text', 'Username', 0, 'Visible', 1, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'login.password', 'Item', 'Password', 'Password', 0, 'Hidden', 1, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'login.notes', 'Item', 'Text', 'Notes', 0, 'Collapsed', 0, 0, NULL, datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'login.url', 'Item', 'URL', 'Website URLs', 1, 'Visible', 0, 0, '["Login"]', datetime('now'), datetime('now'), 0);
|
||||
|
||||
-- Alias fields
|
||||
INSERT INTO FieldDefinitions (Id, FieldKey, EntityType, FieldType, Label, IsMultiValue, DefaultVisibility, EnableHistory, DisplayOrder, ApplicableToTypes, CreatedAt, UpdatedAt, IsDeleted)
|
||||
VALUES
|
||||
(lower(hex(randomblob(16))), 'alias.email', 'Item', 'Email', 'Alias Email', 0, 'Visible', 1, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'alias.first_name', 'Item', 'Text', 'First Name', 0, 'Visible', 0, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'alias.last_name', 'Item', 'Text', 'Last Name', 0, 'Visible', 0, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'alias.nickname', 'Item', 'Text', 'Nickname', 0, 'Visible', 0, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'alias.gender', 'Item', 'Text', 'Gender', 0, 'Visible', 0, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'alias.birthdate', 'Item', 'Date', 'Birth Date', 0, 'Visible', 0, 0, '["Login"]', datetime('now'), datetime('now'), 0);
|
||||
|
||||
CREATE INDEX "IX_Tags_Name" ON "Tags" ("Name");
|
||||
|
||||
|
||||
INSERT INTO Items (Id, Name, ItemType, LogoId, FolderId, CreatedAt, UpdatedAt, IsDeleted)
|
||||
@@ -853,13 +863,14 @@ CREATE UNIQUE INDEX "IX_Logos_Source" ON "Logos" ("Source");
|
||||
|
||||
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'login.url' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'login.url' AS FieldKey,
|
||||
s.Url AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
s.UpdatedAt AS CreatedAt,
|
||||
s.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
@@ -869,13 +880,14 @@ CREATE UNIQUE INDEX "IX_Logos_Source" ON "Logos" ("Source");
|
||||
|
||||
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'login.username' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'login.username' AS FieldKey,
|
||||
c.Username AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
c.UpdatedAt AS CreatedAt,
|
||||
c.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
@@ -884,13 +896,14 @@ CREATE UNIQUE INDEX "IX_Logos_Source" ON "Logos" ("Source");
|
||||
|
||||
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'login.notes' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'login.notes' AS FieldKey,
|
||||
c.Notes AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
c.UpdatedAt AS CreatedAt,
|
||||
c.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
@@ -899,130 +912,121 @@ CREATE UNIQUE INDEX "IX_Logos_Source" ON "Logos" ("Source");
|
||||
|
||||
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
p.CredentialId AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'login.password' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'login.password' AS FieldKey,
|
||||
p.Value AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
p.UpdatedAt AS CreatedAt,
|
||||
p.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Passwords p
|
||||
INNER JOIN (
|
||||
SELECT CredentialId, MAX(UpdatedAt) AS MaxUpdated
|
||||
SELECT CredentialId, MAX(UpdatedAt) AS MaxUpdated, MAX(Id) AS MaxId
|
||||
FROM Passwords
|
||||
WHERE IsDeleted = 0
|
||||
GROUP BY CredentialId
|
||||
) pm ON p.CredentialId = pm.CredentialId AND p.UpdatedAt = pm.MaxUpdated;
|
||||
) pm ON p.CredentialId = pm.CredentialId AND p.UpdatedAt = pm.MaxUpdated AND p.Id = pm.MaxId
|
||||
WHERE p.IsDeleted = 0;
|
||||
|
||||
|
||||
|
||||
INSERT INTO FieldHistories (Id, ItemId, FieldDefinitionId, ValueSnapshot, ChangedAt, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
p.CredentialId AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'login.password' LIMIT 1) AS FieldDefinitionId,
|
||||
'{"values":["' || p.Value || '"]}' AS ValueSnapshot,
|
||||
p.UpdatedAt AS ChangedAt,
|
||||
p.CreatedAt AS CreatedAt,
|
||||
p.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Passwords p
|
||||
WHERE p.Id NOT IN (
|
||||
SELECT p2.Id FROM Passwords p2
|
||||
INNER JOIN (
|
||||
SELECT CredentialId, MAX(UpdatedAt) AS MaxUpdated
|
||||
FROM Passwords
|
||||
GROUP BY CredentialId
|
||||
) pm ON p2.CredentialId = pm.CredentialId AND p2.UpdatedAt = pm.MaxUpdated
|
||||
);
|
||||
|
||||
|
||||
|
||||
-- Migrate Alias.Email
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'alias.email' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'alias.email' AS FieldKey,
|
||||
a.Email AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
a.UpdatedAt AS CreatedAt,
|
||||
a.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Credentials c
|
||||
INNER JOIN Aliases a ON a.Id = c.AliasId
|
||||
WHERE a.Email IS NOT NULL AND a.Email != '';
|
||||
|
||||
|
||||
-- Migrate Alias.FirstName
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'alias.first_name' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'alias.first_name' AS FieldKey,
|
||||
a.FirstName AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
a.UpdatedAt AS CreatedAt,
|
||||
a.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Credentials c
|
||||
INNER JOIN Aliases a ON a.Id = c.AliasId
|
||||
WHERE a.FirstName IS NOT NULL AND a.FirstName != '';
|
||||
|
||||
|
||||
-- Migrate Alias.LastName
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'alias.last_name' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'alias.last_name' AS FieldKey,
|
||||
a.LastName AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
a.UpdatedAt AS CreatedAt,
|
||||
a.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Credentials c
|
||||
INNER JOIN Aliases a ON a.Id = c.AliasId
|
||||
WHERE a.LastName IS NOT NULL AND a.LastName != '';
|
||||
|
||||
|
||||
-- Migrate Alias.NickName
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'alias.nickname' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'alias.nickname' AS FieldKey,
|
||||
a.NickName AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
a.UpdatedAt AS CreatedAt,
|
||||
a.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Credentials c
|
||||
INNER JOIN Aliases a ON a.Id = c.AliasId
|
||||
WHERE a.NickName IS NOT NULL AND a.NickName != '';
|
||||
|
||||
|
||||
-- Migrate Alias.Gender
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'alias.gender' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'alias.gender' AS FieldKey,
|
||||
a.Gender AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
a.UpdatedAt AS CreatedAt,
|
||||
a.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Credentials c
|
||||
INNER JOIN Aliases a ON a.Id = c.AliasId
|
||||
WHERE a.Gender IS NOT NULL AND a.Gender != '';
|
||||
|
||||
|
||||
-- Migrate Alias.BirthDate
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'alias.birthdate' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'alias.birthdate' AS FieldKey,
|
||||
a.BirthDate AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
a.UpdatedAt AS CreatedAt,
|
||||
a.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
@@ -1122,93 +1126,5 @@ CREATE INDEX "IX_TotpCodes_ItemId" ON "TotpCodes" ("ItemId");
|
||||
COMMIT;
|
||||
|
||||
INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion")
|
||||
VALUES ('20251126211441_1.7.0-FieldBasedDataModelUpdate', '9.0.4');
|
||||
|
||||
BEGIN TRANSACTION;
|
||||
ALTER TABLE "Folders" RENAME COLUMN "DisplayOrder" TO "Weight";
|
||||
|
||||
ALTER TABLE "FieldValues" RENAME COLUMN "ValueIndex" TO "Weight";
|
||||
|
||||
DROP INDEX "IX_FieldValues_ItemId_FieldDefinitionId_ValueIndex";
|
||||
|
||||
CREATE INDEX "IX_FieldValues_ItemId_FieldDefinitionId_Weight" ON "FieldValues" ("ItemId", "FieldDefinitionId", "Weight");
|
||||
|
||||
ALTER TABLE "FieldDefinitions" RENAME COLUMN "DisplayOrder" TO "Weight";
|
||||
|
||||
ALTER TABLE "FieldDefinitions" ADD "IsHidden" INTEGER NOT NULL DEFAULT 0;
|
||||
|
||||
CREATE TABLE "ef_temp_FieldDefinitions" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_FieldDefinitions" PRIMARY KEY,
|
||||
"ApplicableToTypes" TEXT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"EnableHistory" INTEGER NOT NULL,
|
||||
"FieldKey" TEXT NULL,
|
||||
"FieldType" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL,
|
||||
"IsHidden" INTEGER NOT NULL,
|
||||
"IsMultiValue" INTEGER NOT NULL,
|
||||
"Label" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"Weight" INTEGER NOT NULL
|
||||
);
|
||||
|
||||
INSERT INTO "ef_temp_FieldDefinitions" ("Id", "ApplicableToTypes", "CreatedAt", "EnableHistory", "FieldKey", "FieldType", "IsDeleted", "IsHidden", "IsMultiValue", "Label", "UpdatedAt", "Weight")
|
||||
SELECT "Id", "ApplicableToTypes", "CreatedAt", "EnableHistory", "FieldKey", "FieldType", "IsDeleted", "IsHidden", "IsMultiValue", "Label", "UpdatedAt", "Weight"
|
||||
FROM "FieldDefinitions";
|
||||
|
||||
COMMIT;
|
||||
|
||||
PRAGMA foreign_keys = 0;
|
||||
|
||||
BEGIN TRANSACTION;
|
||||
DROP TABLE "FieldDefinitions";
|
||||
|
||||
ALTER TABLE "ef_temp_FieldDefinitions" RENAME TO "FieldDefinitions";
|
||||
|
||||
COMMIT;
|
||||
|
||||
PRAGMA foreign_keys = 1;
|
||||
|
||||
BEGIN TRANSACTION;
|
||||
CREATE INDEX "IX_FieldDefinitions_FieldKey" ON "FieldDefinitions" ("FieldKey");
|
||||
|
||||
COMMIT;
|
||||
|
||||
INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion")
|
||||
VALUES ('20251126221717_1.7.1-RenameColumns', '9.0.4');
|
||||
|
||||
BEGIN TRANSACTION;
|
||||
CREATE TABLE "Tags" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_Tags" PRIMARY KEY,
|
||||
"Name" TEXT NOT NULL,
|
||||
"Color" TEXT NULL,
|
||||
"DisplayOrder" INTEGER NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE "ItemTags" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_ItemTags" PRIMARY KEY,
|
||||
"ItemId" TEXT NOT NULL,
|
||||
"TagId" TEXT NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL,
|
||||
CONSTRAINT "FK_ItemTags_Items_ItemId" FOREIGN KEY ("ItemId") REFERENCES "Items" ("Id") ON DELETE CASCADE,
|
||||
CONSTRAINT "FK_ItemTags_Tags_TagId" FOREIGN KEY ("TagId") REFERENCES "Tags" ("Id") ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE INDEX "IX_ItemTags_ItemId" ON "ItemTags" ("ItemId");
|
||||
|
||||
CREATE UNIQUE INDEX "IX_ItemTags_ItemId_TagId" ON "ItemTags" ("ItemId", "TagId");
|
||||
|
||||
CREATE INDEX "IX_ItemTags_TagId" ON "ItemTags" ("TagId");
|
||||
|
||||
CREATE INDEX "IX_Tags_Name" ON "Tags" ("Name");
|
||||
|
||||
INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion")
|
||||
VALUES ('20251202211204_1.7.2-AddTagTables', '9.0.4');
|
||||
|
||||
COMMIT;
|
||||
VALUES ('20251203162345_1.7.0-FieldBasedDataModelUpdate', '9.0.4');
|
||||
|
||||
|
||||
@@ -19,14 +19,12 @@ CREATE INDEX IF NOT EXISTS "IX_Attachments_ItemId" ON "Attachments" ("ItemId");
|
||||
|
||||
CREATE TABLE "FieldDefinitions" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_FieldDefinitions" PRIMARY KEY,
|
||||
"FieldKey" TEXT NULL,
|
||||
"EntityType" TEXT NULL,
|
||||
"FieldType" TEXT NOT NULL,
|
||||
"Label" TEXT NOT NULL,
|
||||
"IsMultiValue" INTEGER NOT NULL,
|
||||
"DefaultVisibility" TEXT NULL,
|
||||
"IsHidden" INTEGER NOT NULL,
|
||||
"EnableHistory" INTEGER NOT NULL,
|
||||
"DisplayOrder" INTEGER NOT NULL,
|
||||
"Weight" INTEGER NOT NULL,
|
||||
"ApplicableToTypes" TEXT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
@@ -37,7 +35,7 @@ CREATE TABLE "Folders" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_Folders" PRIMARY KEY,
|
||||
"Name" TEXT NOT NULL,
|
||||
"ParentFolderId" TEXT NULL,
|
||||
"DisplayOrder" INTEGER NOT NULL,
|
||||
"Weight" INTEGER NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL,
|
||||
@@ -55,6 +53,16 @@ CREATE TABLE "Logos" (
|
||||
"IsDeleted" INTEGER NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE "Tags" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_Tags" PRIMARY KEY,
|
||||
"Name" TEXT NOT NULL,
|
||||
"Color" TEXT NULL,
|
||||
"DisplayOrder" INTEGER NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE "Items" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_Items" PRIMARY KEY,
|
||||
"Name" TEXT NULL,
|
||||
@@ -84,9 +92,10 @@ CREATE TABLE "FieldHistories" (
|
||||
CREATE TABLE "FieldValues" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_FieldValues" PRIMARY KEY,
|
||||
"ItemId" TEXT NOT NULL,
|
||||
"FieldDefinitionId" TEXT NOT NULL,
|
||||
"FieldDefinitionId" TEXT NULL,
|
||||
"FieldKey" TEXT NULL,
|
||||
"Value" TEXT NULL,
|
||||
"ValueIndex" INTEGER NOT NULL,
|
||||
"Weight" INTEGER NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL,
|
||||
@@ -94,7 +103,16 @@ CREATE TABLE "FieldValues" (
|
||||
CONSTRAINT "FK_FieldValues_Items_ItemId" FOREIGN KEY ("ItemId") REFERENCES "Items" ("Id") ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE INDEX "IX_FieldDefinitions_FieldKey" ON "FieldDefinitions" ("FieldKey");
|
||||
CREATE TABLE "ItemTags" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_ItemTags" PRIMARY KEY,
|
||||
"ItemId" TEXT NOT NULL,
|
||||
"TagId" TEXT NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL,
|
||||
CONSTRAINT "FK_ItemTags_Items_ItemId" FOREIGN KEY ("ItemId") REFERENCES "Items" ("Id") ON DELETE CASCADE,
|
||||
CONSTRAINT "FK_ItemTags_Tags_TagId" FOREIGN KEY ("TagId") REFERENCES "Tags" ("Id") ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE INDEX "IX_FieldHistories_FieldDefinitionId" ON "FieldHistories" ("FieldDefinitionId");
|
||||
|
||||
@@ -102,9 +120,13 @@ CREATE INDEX "IX_FieldHistories_ItemId" ON "FieldHistories" ("ItemId");
|
||||
|
||||
CREATE INDEX "IX_FieldValues_FieldDefinitionId" ON "FieldValues" ("FieldDefinitionId");
|
||||
|
||||
CREATE INDEX "IX_FieldValues_FieldKey" ON "FieldValues" ("FieldKey");
|
||||
|
||||
CREATE INDEX "IX_FieldValues_ItemId" ON "FieldValues" ("ItemId");
|
||||
|
||||
CREATE INDEX "IX_FieldValues_ItemId_FieldDefinitionId_ValueIndex" ON "FieldValues" ("ItemId", "FieldDefinitionId", "ValueIndex");
|
||||
CREATE INDEX "IX_FieldValues_ItemId_FieldDefinitionId_Weight" ON "FieldValues" ("ItemId", "FieldDefinitionId", "Weight");
|
||||
|
||||
CREATE INDEX "IX_FieldValues_ItemId_FieldKey" ON "FieldValues" ("ItemId", "FieldKey");
|
||||
|
||||
CREATE INDEX "IX_Folders_ParentFolderId" ON "Folders" ("ParentFolderId");
|
||||
|
||||
@@ -112,27 +134,15 @@ CREATE INDEX "IX_Items_FolderId" ON "Items" ("FolderId");
|
||||
|
||||
CREATE INDEX "IX_Items_LogoId" ON "Items" ("LogoId");
|
||||
|
||||
CREATE INDEX "IX_ItemTags_ItemId" ON "ItemTags" ("ItemId");
|
||||
|
||||
CREATE UNIQUE INDEX "IX_ItemTags_ItemId_TagId" ON "ItemTags" ("ItemId", "TagId");
|
||||
|
||||
CREATE INDEX "IX_ItemTags_TagId" ON "ItemTags" ("TagId");
|
||||
|
||||
CREATE UNIQUE INDEX "IX_Logos_Source" ON "Logos" ("Source");
|
||||
|
||||
|
||||
-- Login fields
|
||||
INSERT INTO FieldDefinitions (Id, FieldKey, EntityType, FieldType, Label, IsMultiValue, DefaultVisibility, EnableHistory, DisplayOrder, ApplicableToTypes, CreatedAt, UpdatedAt, IsDeleted)
|
||||
VALUES
|
||||
(lower(hex(randomblob(16))), 'login.username', 'Item', 'Text', 'Username', 0, 'Visible', 1, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'login.password', 'Item', 'Password', 'Password', 0, 'Hidden', 1, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'login.notes', 'Item', 'Text', 'Notes', 0, 'Collapsed', 0, 0, NULL, datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'login.url', 'Item', 'URL', 'Website URLs', 1, 'Visible', 0, 0, '["Login"]', datetime('now'), datetime('now'), 0);
|
||||
|
||||
-- Alias fields
|
||||
INSERT INTO FieldDefinitions (Id, FieldKey, EntityType, FieldType, Label, IsMultiValue, DefaultVisibility, EnableHistory, DisplayOrder, ApplicableToTypes, CreatedAt, UpdatedAt, IsDeleted)
|
||||
VALUES
|
||||
(lower(hex(randomblob(16))), 'alias.email', 'Item', 'Email', 'Alias Email', 0, 'Visible', 1, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'alias.first_name', 'Item', 'Text', 'First Name', 0, 'Visible', 0, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'alias.last_name', 'Item', 'Text', 'Last Name', 0, 'Visible', 0, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'alias.nickname', 'Item', 'Text', 'Nickname', 0, 'Visible', 0, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'alias.gender', 'Item', 'Text', 'Gender', 0, 'Visible', 0, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'alias.birthdate', 'Item', 'Date', 'Birth Date', 0, 'Visible', 0, 0, '["Login"]', datetime('now'), datetime('now'), 0);
|
||||
|
||||
CREATE INDEX "IX_Tags_Name" ON "Tags" ("Name");
|
||||
|
||||
|
||||
INSERT INTO Items (Id, Name, ItemType, LogoId, FolderId, CreatedAt, UpdatedAt, IsDeleted)
|
||||
@@ -182,13 +192,14 @@ CREATE UNIQUE INDEX "IX_Logos_Source" ON "Logos" ("Source");
|
||||
|
||||
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'login.url' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'login.url' AS FieldKey,
|
||||
s.Url AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
s.UpdatedAt AS CreatedAt,
|
||||
s.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
@@ -198,13 +209,14 @@ CREATE UNIQUE INDEX "IX_Logos_Source" ON "Logos" ("Source");
|
||||
|
||||
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'login.username' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'login.username' AS FieldKey,
|
||||
c.Username AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
c.UpdatedAt AS CreatedAt,
|
||||
c.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
@@ -213,13 +225,14 @@ CREATE UNIQUE INDEX "IX_Logos_Source" ON "Logos" ("Source");
|
||||
|
||||
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'login.notes' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'login.notes' AS FieldKey,
|
||||
c.Notes AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
c.UpdatedAt AS CreatedAt,
|
||||
c.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
@@ -228,130 +241,121 @@ CREATE UNIQUE INDEX "IX_Logos_Source" ON "Logos" ("Source");
|
||||
|
||||
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
p.CredentialId AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'login.password' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'login.password' AS FieldKey,
|
||||
p.Value AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
p.UpdatedAt AS CreatedAt,
|
||||
p.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Passwords p
|
||||
INNER JOIN (
|
||||
SELECT CredentialId, MAX(UpdatedAt) AS MaxUpdated
|
||||
SELECT CredentialId, MAX(UpdatedAt) AS MaxUpdated, MAX(Id) AS MaxId
|
||||
FROM Passwords
|
||||
WHERE IsDeleted = 0
|
||||
GROUP BY CredentialId
|
||||
) pm ON p.CredentialId = pm.CredentialId AND p.UpdatedAt = pm.MaxUpdated;
|
||||
) pm ON p.CredentialId = pm.CredentialId AND p.UpdatedAt = pm.MaxUpdated AND p.Id = pm.MaxId
|
||||
WHERE p.IsDeleted = 0;
|
||||
|
||||
|
||||
|
||||
INSERT INTO FieldHistories (Id, ItemId, FieldDefinitionId, ValueSnapshot, ChangedAt, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
p.CredentialId AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'login.password' LIMIT 1) AS FieldDefinitionId,
|
||||
'{"values":["' || p.Value || '"]}' AS ValueSnapshot,
|
||||
p.UpdatedAt AS ChangedAt,
|
||||
p.CreatedAt AS CreatedAt,
|
||||
p.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Passwords p
|
||||
WHERE p.Id NOT IN (
|
||||
SELECT p2.Id FROM Passwords p2
|
||||
INNER JOIN (
|
||||
SELECT CredentialId, MAX(UpdatedAt) AS MaxUpdated
|
||||
FROM Passwords
|
||||
GROUP BY CredentialId
|
||||
) pm ON p2.CredentialId = pm.CredentialId AND p2.UpdatedAt = pm.MaxUpdated
|
||||
);
|
||||
|
||||
|
||||
|
||||
-- Migrate Alias.Email
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'alias.email' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'alias.email' AS FieldKey,
|
||||
a.Email AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
a.UpdatedAt AS CreatedAt,
|
||||
a.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Credentials c
|
||||
INNER JOIN Aliases a ON a.Id = c.AliasId
|
||||
WHERE a.Email IS NOT NULL AND a.Email != '';
|
||||
|
||||
|
||||
-- Migrate Alias.FirstName
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'alias.first_name' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'alias.first_name' AS FieldKey,
|
||||
a.FirstName AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
a.UpdatedAt AS CreatedAt,
|
||||
a.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Credentials c
|
||||
INNER JOIN Aliases a ON a.Id = c.AliasId
|
||||
WHERE a.FirstName IS NOT NULL AND a.FirstName != '';
|
||||
|
||||
|
||||
-- Migrate Alias.LastName
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'alias.last_name' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'alias.last_name' AS FieldKey,
|
||||
a.LastName AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
a.UpdatedAt AS CreatedAt,
|
||||
a.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Credentials c
|
||||
INNER JOIN Aliases a ON a.Id = c.AliasId
|
||||
WHERE a.LastName IS NOT NULL AND a.LastName != '';
|
||||
|
||||
|
||||
-- Migrate Alias.NickName
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'alias.nickname' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'alias.nickname' AS FieldKey,
|
||||
a.NickName AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
a.UpdatedAt AS CreatedAt,
|
||||
a.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Credentials c
|
||||
INNER JOIN Aliases a ON a.Id = c.AliasId
|
||||
WHERE a.NickName IS NOT NULL AND a.NickName != '';
|
||||
|
||||
|
||||
-- Migrate Alias.Gender
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'alias.gender' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'alias.gender' AS FieldKey,
|
||||
a.Gender AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
a.UpdatedAt AS CreatedAt,
|
||||
a.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Credentials c
|
||||
INNER JOIN Aliases a ON a.Id = c.AliasId
|
||||
WHERE a.Gender IS NOT NULL AND a.Gender != '';
|
||||
|
||||
|
||||
-- Migrate Alias.BirthDate
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'alias.birthdate' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'alias.birthdate' AS FieldKey,
|
||||
a.BirthDate AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
a.UpdatedAt AS CreatedAt,
|
||||
a.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
@@ -451,5 +455,5 @@ CREATE INDEX "IX_TotpCodes_ItemId" ON "TotpCodes" ("ItemId");
|
||||
COMMIT;
|
||||
|
||||
INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion")
|
||||
VALUES ('20251126211441_1.7.0-FieldBasedDataModelUpdate', '9.0.4');
|
||||
VALUES ('20251203162345_1.7.0-FieldBasedDataModelUpdate', '9.0.4');
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
BEGIN TRANSACTION;
|
||||
ALTER TABLE "Folders" RENAME COLUMN "DisplayOrder" TO "Weight";
|
||||
|
||||
ALTER TABLE "FieldValues" RENAME COLUMN "ValueIndex" TO "Weight";
|
||||
|
||||
DROP INDEX "IX_FieldValues_ItemId_FieldDefinitionId_ValueIndex";
|
||||
|
||||
CREATE INDEX "IX_FieldValues_ItemId_FieldDefinitionId_Weight" ON "FieldValues" ("ItemId", "FieldDefinitionId", "Weight");
|
||||
|
||||
ALTER TABLE "FieldDefinitions" RENAME COLUMN "DisplayOrder" TO "Weight";
|
||||
|
||||
ALTER TABLE "FieldDefinitions" ADD "IsHidden" INTEGER NOT NULL DEFAULT 0;
|
||||
|
||||
CREATE TABLE "ef_temp_FieldDefinitions" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_FieldDefinitions" PRIMARY KEY,
|
||||
"ApplicableToTypes" TEXT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"EnableHistory" INTEGER NOT NULL,
|
||||
"FieldKey" TEXT NULL,
|
||||
"FieldType" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL,
|
||||
"IsHidden" INTEGER NOT NULL,
|
||||
"IsMultiValue" INTEGER NOT NULL,
|
||||
"Label" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"Weight" INTEGER NOT NULL
|
||||
);
|
||||
|
||||
INSERT INTO "ef_temp_FieldDefinitions" ("Id", "ApplicableToTypes", "CreatedAt", "EnableHistory", "FieldKey", "FieldType", "IsDeleted", "IsHidden", "IsMultiValue", "Label", "UpdatedAt", "Weight")
|
||||
SELECT "Id", "ApplicableToTypes", "CreatedAt", "EnableHistory", "FieldKey", "FieldType", "IsDeleted", "IsHidden", "IsMultiValue", "Label", "UpdatedAt", "Weight"
|
||||
FROM "FieldDefinitions";
|
||||
|
||||
COMMIT;
|
||||
|
||||
PRAGMA foreign_keys = 0;
|
||||
|
||||
BEGIN TRANSACTION;
|
||||
DROP TABLE "FieldDefinitions";
|
||||
|
||||
ALTER TABLE "ef_temp_FieldDefinitions" RENAME TO "FieldDefinitions";
|
||||
|
||||
COMMIT;
|
||||
|
||||
PRAGMA foreign_keys = 1;
|
||||
|
||||
BEGIN TRANSACTION;
|
||||
CREATE INDEX "IX_FieldDefinitions_FieldKey" ON "FieldDefinitions" ("FieldKey");
|
||||
|
||||
COMMIT;
|
||||
|
||||
INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion")
|
||||
VALUES ('20251126221717_1.7.1-RenameColumns', '9.0.4');
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
BEGIN TRANSACTION;
|
||||
CREATE TABLE "Tags" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_Tags" PRIMARY KEY,
|
||||
"Name" TEXT NOT NULL,
|
||||
"Color" TEXT NULL,
|
||||
"DisplayOrder" INTEGER NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE "ItemTags" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_ItemTags" PRIMARY KEY,
|
||||
"ItemId" TEXT NOT NULL,
|
||||
"TagId" TEXT NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL,
|
||||
CONSTRAINT "FK_ItemTags_Items_ItemId" FOREIGN KEY ("ItemId") REFERENCES "Items" ("Id") ON DELETE CASCADE,
|
||||
CONSTRAINT "FK_ItemTags_Tags_TagId" FOREIGN KEY ("TagId") REFERENCES "Tags" ("Id") ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE INDEX "IX_ItemTags_ItemId" ON "ItemTags" ("ItemId");
|
||||
|
||||
CREATE UNIQUE INDEX "IX_ItemTags_ItemId_TagId" ON "ItemTags" ("ItemId", "TagId");
|
||||
|
||||
CREATE INDEX "IX_ItemTags_TagId" ON "ItemTags" ("TagId");
|
||||
|
||||
CREATE INDEX "IX_Tags_Name" ON "Tags" ("Name");
|
||||
|
||||
INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion")
|
||||
VALUES ('20251202211204_1.7.2-AddTagTables', '9.0.4');
|
||||
|
||||
COMMIT;
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
# Configurable settings
|
||||
SQL_DIR="MigrationSql"
|
||||
OUTPUT_FILE="MigrationTs/SqlConstants.ts"
|
||||
VERSIONS_FILE="MigrationTs/VaultVersions.ts"
|
||||
TEMP_DIR="/tmp/sql_to_ts"
|
||||
|
||||
# Path to the shared vault-sql package
|
||||
|
||||
5
shared/models/src/vault/CredentialCompat.ts
Normal file
5
shared/models/src/vault/CredentialCompat.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
/**
|
||||
* @deprecated This file is deprecated. Use ItemMethods.ts instead.
|
||||
* Kept for backward compatibility during migration.
|
||||
*/
|
||||
export { itemToCredential } from './ItemMethods';
|
||||
62
shared/models/src/vault/Item.ts
Normal file
62
shared/models/src/vault/Item.ts
Normal file
@@ -0,0 +1,62 @@
|
||||
/**
|
||||
* Item types supported by the vault
|
||||
*/
|
||||
export type ItemType =
|
||||
| 'Login'
|
||||
| 'CreditCard'
|
||||
| 'Identity'
|
||||
| 'Note';
|
||||
|
||||
/**
|
||||
* Item type representing vault entries in the new field-based data model.
|
||||
* Replaces the old Credential type.
|
||||
*/
|
||||
export type Item = {
|
||||
Id: string;
|
||||
Name: string | null;
|
||||
ItemType: ItemType;
|
||||
Logo?: Uint8Array | number[];
|
||||
FolderId?: string | null;
|
||||
FolderPath?: string | null;
|
||||
Tags?: ItemTagRef[];
|
||||
Fields: ItemField[];
|
||||
HasPasskey?: boolean;
|
||||
HasAttachment?: boolean;
|
||||
HasTotp?: boolean;
|
||||
CreatedAt: string;
|
||||
UpdatedAt: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Field value within an item
|
||||
*/
|
||||
export type ItemField = {
|
||||
FieldKey: string;
|
||||
Label: string;
|
||||
FieldType: FieldType;
|
||||
Value: string | string[];
|
||||
IsHidden: boolean;
|
||||
DisplayOrder: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Field types for rendering and validation
|
||||
*/
|
||||
export type FieldType =
|
||||
| 'Text'
|
||||
| 'Password'
|
||||
| 'Email'
|
||||
| 'URL'
|
||||
| 'Date'
|
||||
| 'Number'
|
||||
| 'Phone'
|
||||
| 'TextArea';
|
||||
|
||||
/**
|
||||
* Tag reference for display within an item
|
||||
*/
|
||||
export type ItemTagRef = {
|
||||
Id: string;
|
||||
Name: string;
|
||||
Color?: string;
|
||||
}
|
||||
113
shared/models/src/vault/ItemMethods.ts
Normal file
113
shared/models/src/vault/ItemMethods.ts
Normal file
@@ -0,0 +1,113 @@
|
||||
import type { Item, ItemField } from './Item';
|
||||
import type { Credential } from './Credential';
|
||||
import { FieldKey } from './FieldKey';
|
||||
|
||||
/**
|
||||
* Helper functions for working with Item model
|
||||
*/
|
||||
|
||||
/**
|
||||
* Get a single field value by FieldKey
|
||||
*/
|
||||
export function getFieldValue(item: Item, fieldKey: string): string | undefined {
|
||||
const field = item.Fields.find(f => f.FieldKey === fieldKey);
|
||||
if (!field) {
|
||||
return undefined;
|
||||
}
|
||||
return Array.isArray(field.Value) ? field.Value[0] : field.Value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all values for a multi-value field
|
||||
*/
|
||||
export function getFieldValues(item: Item, fieldKey: string): string[] {
|
||||
const field = item.Fields.find(f => f.FieldKey === fieldKey);
|
||||
if (!field) {
|
||||
return [];
|
||||
}
|
||||
return Array.isArray(field.Value) ? field.Value : [field.Value];
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a field exists and has a value
|
||||
*/
|
||||
export function hasField(item: Item, fieldKey: string): boolean {
|
||||
const value = getFieldValue(item, fieldKey);
|
||||
return value !== undefined && value !== '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Group fields by a categorization function
|
||||
*/
|
||||
export function groupFields(
|
||||
item: Item,
|
||||
grouper: (field: ItemField) => string
|
||||
): Record<string, ItemField[]> {
|
||||
const groups: Record<string, ItemField[]> = {};
|
||||
|
||||
item.Fields.forEach(field => {
|
||||
const group = grouper(field);
|
||||
if (!groups[group]) {
|
||||
groups[group] = [];
|
||||
}
|
||||
groups[group].push(field);
|
||||
});
|
||||
|
||||
return groups;
|
||||
}
|
||||
|
||||
/**
|
||||
* Group fields by standard categories (Login, Alias, Custom)
|
||||
*/
|
||||
export function groupFieldsByCategory(item: Item): Record<string, ItemField[]> {
|
||||
return groupFields(item, (field) => {
|
||||
|
||||
// Render alias.email as login
|
||||
if (field.FieldKey === FieldKey.AliasEmail) {
|
||||
return 'Login';
|
||||
}
|
||||
|
||||
if (field.FieldKey.startsWith('login.')) {
|
||||
return 'Login';
|
||||
}
|
||||
if (field.FieldKey.startsWith('alias.')) {
|
||||
return 'Alias';
|
||||
}
|
||||
if (field.FieldKey.startsWith('card.')) {
|
||||
return 'Card';
|
||||
}
|
||||
if (field.FieldKey.startsWith('identity.')) {
|
||||
return 'Identity';
|
||||
}
|
||||
if (field.FieldKey.startsWith('api.')) {
|
||||
return 'API';
|
||||
}
|
||||
return 'Custom';
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert new Item model to legacy Credential model for backward compatibility.
|
||||
* @deprecated Use Item model directly. This is a temporary compatibility layer.
|
||||
*/
|
||||
export function itemToCredential(item: Item): Credential {
|
||||
return {
|
||||
Id: item.Id,
|
||||
Username: getFieldValue(item, FieldKey.LoginUsername),
|
||||
Password: getFieldValue(item, FieldKey.LoginPassword) || '',
|
||||
ServiceName: item.Name || '',
|
||||
ServiceUrl: getFieldValue(item, FieldKey.LoginUrl),
|
||||
Logo: item.Logo,
|
||||
Notes: getFieldValue(item, FieldKey.LoginNotes),
|
||||
Alias: {
|
||||
FirstName: getFieldValue(item, FieldKey.AliasFirstName),
|
||||
LastName: getFieldValue(item, FieldKey.AliasLastName),
|
||||
NickName: getFieldValue(item, FieldKey.AliasNickname),
|
||||
BirthDate: getFieldValue(item, FieldKey.AliasBirthdate) || '',
|
||||
Gender: getFieldValue(item, FieldKey.AliasGender),
|
||||
Email: getFieldValue(item, FieldKey.AliasEmail)
|
||||
},
|
||||
HasPasskey: item.HasPasskey,
|
||||
HasAttachment: item.HasAttachment
|
||||
};
|
||||
}
|
||||
201
shared/models/src/vault/SystemFieldRegistry.ts
Normal file
201
shared/models/src/vault/SystemFieldRegistry.ts
Normal file
@@ -0,0 +1,201 @@
|
||||
import type { FieldType, ItemType } from './Item';
|
||||
|
||||
/**
|
||||
* System field definition with metadata.
|
||||
* System fields are predefined fields with immutable keys like 'login.username'.
|
||||
* Their metadata (label, type, etc.) is defined here in code, not in the database.
|
||||
*/
|
||||
export type SystemFieldDefinition = {
|
||||
/** Unique system field key (e.g., 'login.username') */
|
||||
FieldKey: string;
|
||||
/** Display label for the field */
|
||||
Label: string;
|
||||
/** Field type for rendering/validation */
|
||||
FieldType: FieldType;
|
||||
/** Whether field is hidden/masked by default */
|
||||
IsHidden: boolean;
|
||||
/** Whether field supports multiple values */
|
||||
IsMultiValue: boolean;
|
||||
/** Item types this field applies to */
|
||||
ApplicableToTypes: ItemType[];
|
||||
/** Whether to track field value history */
|
||||
EnableHistory: boolean;
|
||||
/** Category for grouping in UI */
|
||||
Category: 'Login' | 'Alias' | 'Card' | 'Identity' | 'API' | 'Note';
|
||||
/** Default display order within category (lower = first) */
|
||||
DefaultDisplayOrder: number;
|
||||
};
|
||||
|
||||
/**
|
||||
* Registry of all system-defined fields.
|
||||
* These fields are immutable and their metadata is defined in code.
|
||||
* DO NOT modify these definitions without careful consideration of backwards compatibility.
|
||||
*/
|
||||
export const SystemFieldRegistry: Record<string, SystemFieldDefinition> = {
|
||||
// Login Fields
|
||||
'login.username': {
|
||||
FieldKey: 'login.username',
|
||||
Label: 'Username',
|
||||
FieldType: 'Text',
|
||||
IsHidden: false,
|
||||
IsMultiValue: false,
|
||||
ApplicableToTypes: ['Login'],
|
||||
EnableHistory: true,
|
||||
Category: 'Login',
|
||||
DefaultDisplayOrder: 10
|
||||
},
|
||||
'login.password': {
|
||||
FieldKey: 'login.password',
|
||||
Label: 'Password',
|
||||
FieldType: 'Password',
|
||||
IsHidden: true,
|
||||
IsMultiValue: false,
|
||||
ApplicableToTypes: ['Login'],
|
||||
EnableHistory: true,
|
||||
Category: 'Login',
|
||||
DefaultDisplayOrder: 20
|
||||
},
|
||||
'login.url': {
|
||||
FieldKey: 'login.url',
|
||||
Label: 'Website',
|
||||
FieldType: 'URL',
|
||||
IsHidden: false,
|
||||
IsMultiValue: true,
|
||||
ApplicableToTypes: ['Login'],
|
||||
EnableHistory: false,
|
||||
Category: 'Login',
|
||||
DefaultDisplayOrder: 30
|
||||
},
|
||||
'login.notes': {
|
||||
FieldKey: 'login.notes',
|
||||
Label: 'Notes',
|
||||
FieldType: 'TextArea',
|
||||
IsHidden: false,
|
||||
IsMultiValue: false,
|
||||
ApplicableToTypes: ['Login', 'CreditCard', 'Identity', 'Note'],
|
||||
EnableHistory: false,
|
||||
Category: 'Login',
|
||||
DefaultDisplayOrder: 100
|
||||
},
|
||||
|
||||
// Alias Fields
|
||||
'alias.email': {
|
||||
FieldKey: 'alias.email',
|
||||
Label: 'Email',
|
||||
FieldType: 'Email',
|
||||
IsHidden: false,
|
||||
IsMultiValue: false,
|
||||
ApplicableToTypes: ['Login'],
|
||||
EnableHistory: true,
|
||||
Category: 'Alias',
|
||||
DefaultDisplayOrder: 10
|
||||
},
|
||||
'alias.first_name': {
|
||||
FieldKey: 'alias.first_name',
|
||||
Label: 'First Name',
|
||||
FieldType: 'Text',
|
||||
IsHidden: false,
|
||||
IsMultiValue: false,
|
||||
ApplicableToTypes: ['Login', 'Identity'],
|
||||
EnableHistory: false,
|
||||
Category: 'Alias',
|
||||
DefaultDisplayOrder: 20
|
||||
},
|
||||
'alias.last_name': {
|
||||
FieldKey: 'alias.last_name',
|
||||
Label: 'Last Name',
|
||||
FieldType: 'Text',
|
||||
IsHidden: false,
|
||||
IsMultiValue: false,
|
||||
ApplicableToTypes: ['Login', 'Identity'],
|
||||
EnableHistory: false,
|
||||
Category: 'Alias',
|
||||
DefaultDisplayOrder: 30
|
||||
},
|
||||
'alias.nickname': {
|
||||
FieldKey: 'alias.nickname',
|
||||
Label: 'Nickname',
|
||||
FieldType: 'Text',
|
||||
IsHidden: false,
|
||||
IsMultiValue: false,
|
||||
ApplicableToTypes: ['Login'],
|
||||
EnableHistory: false,
|
||||
Category: 'Alias',
|
||||
DefaultDisplayOrder: 40
|
||||
},
|
||||
'alias.gender': {
|
||||
FieldKey: 'alias.gender',
|
||||
Label: 'Gender',
|
||||
FieldType: 'Text',
|
||||
IsHidden: false,
|
||||
IsMultiValue: false,
|
||||
ApplicableToTypes: ['Login', 'Identity'],
|
||||
EnableHistory: false,
|
||||
Category: 'Alias',
|
||||
DefaultDisplayOrder: 50
|
||||
},
|
||||
'alias.birthdate': {
|
||||
FieldKey: 'alias.birthdate',
|
||||
Label: 'Birth Date',
|
||||
FieldType: 'Date',
|
||||
IsHidden: false,
|
||||
IsMultiValue: false,
|
||||
ApplicableToTypes: ['Login', 'Identity'],
|
||||
EnableHistory: false,
|
||||
Category: 'Alias',
|
||||
DefaultDisplayOrder: 60
|
||||
},
|
||||
|
||||
/*
|
||||
* Note: Card, Identity, and API fields can be added here when those item types are implemented
|
||||
* Example:
|
||||
* 'card.number': { ... },
|
||||
* 'card.cardholder_name': { ... },
|
||||
* 'identity.phone_number': { ... },
|
||||
*/
|
||||
};
|
||||
|
||||
/**
|
||||
* Get system field definition by key.
|
||||
* Returns undefined if the field key is not a system field.
|
||||
*/
|
||||
export function getSystemField(fieldKey: string): SystemFieldDefinition | undefined {
|
||||
return SystemFieldRegistry[fieldKey];
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a field key represents a system field.
|
||||
*/
|
||||
export function isSystemField(fieldKey: string): boolean {
|
||||
return fieldKey in SystemFieldRegistry;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all system fields applicable to a specific item type.
|
||||
* Results are sorted by DefaultDisplayOrder.
|
||||
*/
|
||||
export function getSystemFieldsForItemType(itemType: ItemType): SystemFieldDefinition[] {
|
||||
return Object.values(SystemFieldRegistry)
|
||||
.filter(field => field.ApplicableToTypes.includes(itemType))
|
||||
.sort((a, b) => a.DefaultDisplayOrder - b.DefaultDisplayOrder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all system field keys.
|
||||
*/
|
||||
export function getAllSystemFieldKeys(): string[] {
|
||||
return Object.keys(SystemFieldRegistry);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a field key matches a known system field prefix.
|
||||
* This is useful for validation even before a specific field is registered.
|
||||
*/
|
||||
export function isSystemFieldPrefix(fieldKey: string): boolean {
|
||||
return fieldKey.startsWith('login.') ||
|
||||
fieldKey.startsWith('alias.') ||
|
||||
fieldKey.startsWith('card.') ||
|
||||
fieldKey.startsWith('identity.') ||
|
||||
fieldKey.startsWith('api.') ||
|
||||
fieldKey.startsWith('note.');
|
||||
}
|
||||
@@ -10,3 +10,7 @@ export * from './Passkey';
|
||||
export * from './FieldKey';
|
||||
export * from './Tag';
|
||||
export * from './ItemTag';
|
||||
export * from './Item';
|
||||
export * from './CredentialCompat';
|
||||
export * from './ItemMethods';
|
||||
export * from './SystemFieldRegistry';
|
||||
|
||||
@@ -697,14 +697,12 @@ CREATE INDEX IF NOT EXISTS "IX_Attachments_ItemId" ON "Attachments" ("ItemId");
|
||||
|
||||
CREATE TABLE "FieldDefinitions" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_FieldDefinitions" PRIMARY KEY,
|
||||
"FieldKey" TEXT NULL,
|
||||
"EntityType" TEXT NULL,
|
||||
"FieldType" TEXT NOT NULL,
|
||||
"Label" TEXT NOT NULL,
|
||||
"IsMultiValue" INTEGER NOT NULL,
|
||||
"DefaultVisibility" TEXT NULL,
|
||||
"IsHidden" INTEGER NOT NULL,
|
||||
"EnableHistory" INTEGER NOT NULL,
|
||||
"DisplayOrder" INTEGER NOT NULL,
|
||||
"Weight" INTEGER NOT NULL,
|
||||
"ApplicableToTypes" TEXT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
@@ -715,7 +713,7 @@ CREATE TABLE "Folders" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_Folders" PRIMARY KEY,
|
||||
"Name" TEXT NOT NULL,
|
||||
"ParentFolderId" TEXT NULL,
|
||||
"DisplayOrder" INTEGER NOT NULL,
|
||||
"Weight" INTEGER NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL,
|
||||
@@ -733,6 +731,16 @@ CREATE TABLE "Logos" (
|
||||
"IsDeleted" INTEGER NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE "Tags" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_Tags" PRIMARY KEY,
|
||||
"Name" TEXT NOT NULL,
|
||||
"Color" TEXT NULL,
|
||||
"DisplayOrder" INTEGER NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE "Items" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_Items" PRIMARY KEY,
|
||||
"Name" TEXT NULL,
|
||||
@@ -762,9 +770,10 @@ CREATE TABLE "FieldHistories" (
|
||||
CREATE TABLE "FieldValues" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_FieldValues" PRIMARY KEY,
|
||||
"ItemId" TEXT NOT NULL,
|
||||
"FieldDefinitionId" TEXT NOT NULL,
|
||||
"FieldDefinitionId" TEXT NULL,
|
||||
"FieldKey" TEXT NULL,
|
||||
"Value" TEXT NULL,
|
||||
"ValueIndex" INTEGER NOT NULL,
|
||||
"Weight" INTEGER NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL,
|
||||
@@ -772,7 +781,16 @@ CREATE TABLE "FieldValues" (
|
||||
CONSTRAINT "FK_FieldValues_Items_ItemId" FOREIGN KEY ("ItemId") REFERENCES "Items" ("Id") ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE INDEX "IX_FieldDefinitions_FieldKey" ON "FieldDefinitions" ("FieldKey");
|
||||
CREATE TABLE "ItemTags" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_ItemTags" PRIMARY KEY,
|
||||
"ItemId" TEXT NOT NULL,
|
||||
"TagId" TEXT NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL,
|
||||
CONSTRAINT "FK_ItemTags_Items_ItemId" FOREIGN KEY ("ItemId") REFERENCES "Items" ("Id") ON DELETE CASCADE,
|
||||
CONSTRAINT "FK_ItemTags_Tags_TagId" FOREIGN KEY ("TagId") REFERENCES "Tags" ("Id") ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE INDEX "IX_FieldHistories_FieldDefinitionId" ON "FieldHistories" ("FieldDefinitionId");
|
||||
|
||||
@@ -780,9 +798,13 @@ CREATE INDEX "IX_FieldHistories_ItemId" ON "FieldHistories" ("ItemId");
|
||||
|
||||
CREATE INDEX "IX_FieldValues_FieldDefinitionId" ON "FieldValues" ("FieldDefinitionId");
|
||||
|
||||
CREATE INDEX "IX_FieldValues_FieldKey" ON "FieldValues" ("FieldKey");
|
||||
|
||||
CREATE INDEX "IX_FieldValues_ItemId" ON "FieldValues" ("ItemId");
|
||||
|
||||
CREATE INDEX "IX_FieldValues_ItemId_FieldDefinitionId_ValueIndex" ON "FieldValues" ("ItemId", "FieldDefinitionId", "ValueIndex");
|
||||
CREATE INDEX "IX_FieldValues_ItemId_FieldDefinitionId_Weight" ON "FieldValues" ("ItemId", "FieldDefinitionId", "Weight");
|
||||
|
||||
CREATE INDEX "IX_FieldValues_ItemId_FieldKey" ON "FieldValues" ("ItemId", "FieldKey");
|
||||
|
||||
CREATE INDEX "IX_Folders_ParentFolderId" ON "Folders" ("ParentFolderId");
|
||||
|
||||
@@ -790,27 +812,15 @@ CREATE INDEX "IX_Items_FolderId" ON "Items" ("FolderId");
|
||||
|
||||
CREATE INDEX "IX_Items_LogoId" ON "Items" ("LogoId");
|
||||
|
||||
CREATE INDEX "IX_ItemTags_ItemId" ON "ItemTags" ("ItemId");
|
||||
|
||||
CREATE UNIQUE INDEX "IX_ItemTags_ItemId_TagId" ON "ItemTags" ("ItemId", "TagId");
|
||||
|
||||
CREATE INDEX "IX_ItemTags_TagId" ON "ItemTags" ("TagId");
|
||||
|
||||
CREATE UNIQUE INDEX "IX_Logos_Source" ON "Logos" ("Source");
|
||||
|
||||
|
||||
-- Login fields
|
||||
INSERT INTO FieldDefinitions (Id, FieldKey, EntityType, FieldType, Label, IsMultiValue, DefaultVisibility, EnableHistory, DisplayOrder, ApplicableToTypes, CreatedAt, UpdatedAt, IsDeleted)
|
||||
VALUES
|
||||
(lower(hex(randomblob(16))), 'login.username', 'Item', 'Text', 'Username', 0, 'Visible', 1, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'login.password', 'Item', 'Password', 'Password', 0, 'Hidden', 1, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'login.notes', 'Item', 'Text', 'Notes', 0, 'Collapsed', 0, 0, NULL, datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'login.url', 'Item', 'URL', 'Website URLs', 1, 'Visible', 0, 0, '["Login"]', datetime('now'), datetime('now'), 0);
|
||||
|
||||
-- Alias fields
|
||||
INSERT INTO FieldDefinitions (Id, FieldKey, EntityType, FieldType, Label, IsMultiValue, DefaultVisibility, EnableHistory, DisplayOrder, ApplicableToTypes, CreatedAt, UpdatedAt, IsDeleted)
|
||||
VALUES
|
||||
(lower(hex(randomblob(16))), 'alias.email', 'Item', 'Email', 'Alias Email', 0, 'Visible', 1, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'alias.first_name', 'Item', 'Text', 'First Name', 0, 'Visible', 0, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'alias.last_name', 'Item', 'Text', 'Last Name', 0, 'Visible', 0, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'alias.nickname', 'Item', 'Text', 'Nickname', 0, 'Visible', 0, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'alias.gender', 'Item', 'Text', 'Gender', 0, 'Visible', 0, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'alias.birthdate', 'Item', 'Date', 'Birth Date', 0, 'Visible', 0, 0, '["Login"]', datetime('now'), datetime('now'), 0);
|
||||
|
||||
CREATE INDEX "IX_Tags_Name" ON "Tags" ("Name");
|
||||
|
||||
|
||||
INSERT INTO Items (Id, Name, ItemType, LogoId, FolderId, CreatedAt, UpdatedAt, IsDeleted)
|
||||
@@ -860,13 +870,14 @@ CREATE UNIQUE INDEX "IX_Logos_Source" ON "Logos" ("Source");
|
||||
|
||||
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'login.url' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'login.url' AS FieldKey,
|
||||
s.Url AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
s.UpdatedAt AS CreatedAt,
|
||||
s.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
@@ -876,13 +887,14 @@ CREATE UNIQUE INDEX "IX_Logos_Source" ON "Logos" ("Source");
|
||||
|
||||
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'login.username' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'login.username' AS FieldKey,
|
||||
c.Username AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
c.UpdatedAt AS CreatedAt,
|
||||
c.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
@@ -891,13 +903,14 @@ CREATE UNIQUE INDEX "IX_Logos_Source" ON "Logos" ("Source");
|
||||
|
||||
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'login.notes' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'login.notes' AS FieldKey,
|
||||
c.Notes AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
c.UpdatedAt AS CreatedAt,
|
||||
c.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
@@ -906,130 +919,121 @@ CREATE UNIQUE INDEX "IX_Logos_Source" ON "Logos" ("Source");
|
||||
|
||||
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
p.CredentialId AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'login.password' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'login.password' AS FieldKey,
|
||||
p.Value AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
p.UpdatedAt AS CreatedAt,
|
||||
p.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Passwords p
|
||||
INNER JOIN (
|
||||
SELECT CredentialId, MAX(UpdatedAt) AS MaxUpdated
|
||||
SELECT CredentialId, MAX(UpdatedAt) AS MaxUpdated, MAX(Id) AS MaxId
|
||||
FROM Passwords
|
||||
WHERE IsDeleted = 0
|
||||
GROUP BY CredentialId
|
||||
) pm ON p.CredentialId = pm.CredentialId AND p.UpdatedAt = pm.MaxUpdated;
|
||||
) pm ON p.CredentialId = pm.CredentialId AND p.UpdatedAt = pm.MaxUpdated AND p.Id = pm.MaxId
|
||||
WHERE p.IsDeleted = 0;
|
||||
|
||||
|
||||
|
||||
INSERT INTO FieldHistories (Id, ItemId, FieldDefinitionId, ValueSnapshot, ChangedAt, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
p.CredentialId AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'login.password' LIMIT 1) AS FieldDefinitionId,
|
||||
'{"values":["' || p.Value || '"]}' AS ValueSnapshot,
|
||||
p.UpdatedAt AS ChangedAt,
|
||||
p.CreatedAt AS CreatedAt,
|
||||
p.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Passwords p
|
||||
WHERE p.Id NOT IN (
|
||||
SELECT p2.Id FROM Passwords p2
|
||||
INNER JOIN (
|
||||
SELECT CredentialId, MAX(UpdatedAt) AS MaxUpdated
|
||||
FROM Passwords
|
||||
GROUP BY CredentialId
|
||||
) pm ON p2.CredentialId = pm.CredentialId AND p2.UpdatedAt = pm.MaxUpdated
|
||||
);
|
||||
|
||||
|
||||
|
||||
-- Migrate Alias.Email
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'alias.email' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'alias.email' AS FieldKey,
|
||||
a.Email AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
a.UpdatedAt AS CreatedAt,
|
||||
a.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Credentials c
|
||||
INNER JOIN Aliases a ON a.Id = c.AliasId
|
||||
WHERE a.Email IS NOT NULL AND a.Email != '';
|
||||
|
||||
|
||||
-- Migrate Alias.FirstName
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'alias.first_name' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'alias.first_name' AS FieldKey,
|
||||
a.FirstName AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
a.UpdatedAt AS CreatedAt,
|
||||
a.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Credentials c
|
||||
INNER JOIN Aliases a ON a.Id = c.AliasId
|
||||
WHERE a.FirstName IS NOT NULL AND a.FirstName != '';
|
||||
|
||||
|
||||
-- Migrate Alias.LastName
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'alias.last_name' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'alias.last_name' AS FieldKey,
|
||||
a.LastName AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
a.UpdatedAt AS CreatedAt,
|
||||
a.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Credentials c
|
||||
INNER JOIN Aliases a ON a.Id = c.AliasId
|
||||
WHERE a.LastName IS NOT NULL AND a.LastName != '';
|
||||
|
||||
|
||||
-- Migrate Alias.NickName
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'alias.nickname' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'alias.nickname' AS FieldKey,
|
||||
a.NickName AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
a.UpdatedAt AS CreatedAt,
|
||||
a.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Credentials c
|
||||
INNER JOIN Aliases a ON a.Id = c.AliasId
|
||||
WHERE a.NickName IS NOT NULL AND a.NickName != '';
|
||||
|
||||
|
||||
-- Migrate Alias.Gender
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'alias.gender' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'alias.gender' AS FieldKey,
|
||||
a.Gender AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
a.UpdatedAt AS CreatedAt,
|
||||
a.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Credentials c
|
||||
INNER JOIN Aliases a ON a.Id = c.AliasId
|
||||
WHERE a.Gender IS NOT NULL AND a.Gender != '';
|
||||
|
||||
|
||||
-- Migrate Alias.BirthDate
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'alias.birthdate' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'alias.birthdate' AS FieldKey,
|
||||
a.BirthDate AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
a.UpdatedAt AS CreatedAt,
|
||||
a.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
@@ -1129,95 +1133,7 @@ CREATE INDEX "IX_TotpCodes_ItemId" ON "TotpCodes" ("ItemId");
|
||||
COMMIT;
|
||||
|
||||
INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion")
|
||||
VALUES ('20251126211441_1.7.0-FieldBasedDataModelUpdate', '9.0.4');
|
||||
|
||||
BEGIN TRANSACTION;
|
||||
ALTER TABLE "Folders" RENAME COLUMN "DisplayOrder" TO "Weight";
|
||||
|
||||
ALTER TABLE "FieldValues" RENAME COLUMN "ValueIndex" TO "Weight";
|
||||
|
||||
DROP INDEX "IX_FieldValues_ItemId_FieldDefinitionId_ValueIndex";
|
||||
|
||||
CREATE INDEX "IX_FieldValues_ItemId_FieldDefinitionId_Weight" ON "FieldValues" ("ItemId", "FieldDefinitionId", "Weight");
|
||||
|
||||
ALTER TABLE "FieldDefinitions" RENAME COLUMN "DisplayOrder" TO "Weight";
|
||||
|
||||
ALTER TABLE "FieldDefinitions" ADD "IsHidden" INTEGER NOT NULL DEFAULT 0;
|
||||
|
||||
CREATE TABLE "ef_temp_FieldDefinitions" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_FieldDefinitions" PRIMARY KEY,
|
||||
"ApplicableToTypes" TEXT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"EnableHistory" INTEGER NOT NULL,
|
||||
"FieldKey" TEXT NULL,
|
||||
"FieldType" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL,
|
||||
"IsHidden" INTEGER NOT NULL,
|
||||
"IsMultiValue" INTEGER NOT NULL,
|
||||
"Label" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"Weight" INTEGER NOT NULL
|
||||
);
|
||||
|
||||
INSERT INTO "ef_temp_FieldDefinitions" ("Id", "ApplicableToTypes", "CreatedAt", "EnableHistory", "FieldKey", "FieldType", "IsDeleted", "IsHidden", "IsMultiValue", "Label", "UpdatedAt", "Weight")
|
||||
SELECT "Id", "ApplicableToTypes", "CreatedAt", "EnableHistory", "FieldKey", "FieldType", "IsDeleted", "IsHidden", "IsMultiValue", "Label", "UpdatedAt", "Weight"
|
||||
FROM "FieldDefinitions";
|
||||
|
||||
COMMIT;
|
||||
|
||||
PRAGMA foreign_keys = 0;
|
||||
|
||||
BEGIN TRANSACTION;
|
||||
DROP TABLE "FieldDefinitions";
|
||||
|
||||
ALTER TABLE "ef_temp_FieldDefinitions" RENAME TO "FieldDefinitions";
|
||||
|
||||
COMMIT;
|
||||
|
||||
PRAGMA foreign_keys = 1;
|
||||
|
||||
BEGIN TRANSACTION;
|
||||
CREATE INDEX "IX_FieldDefinitions_FieldKey" ON "FieldDefinitions" ("FieldKey");
|
||||
|
||||
COMMIT;
|
||||
|
||||
INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion")
|
||||
VALUES ('20251126221717_1.7.1-RenameColumns', '9.0.4');
|
||||
|
||||
BEGIN TRANSACTION;
|
||||
CREATE TABLE "Tags" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_Tags" PRIMARY KEY,
|
||||
"Name" TEXT NOT NULL,
|
||||
"Color" TEXT NULL,
|
||||
"DisplayOrder" INTEGER NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE "ItemTags" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_ItemTags" PRIMARY KEY,
|
||||
"ItemId" TEXT NOT NULL,
|
||||
"TagId" TEXT NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL,
|
||||
CONSTRAINT "FK_ItemTags_Items_ItemId" FOREIGN KEY ("ItemId") REFERENCES "Items" ("Id") ON DELETE CASCADE,
|
||||
CONSTRAINT "FK_ItemTags_Tags_TagId" FOREIGN KEY ("TagId") REFERENCES "Tags" ("Id") ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE INDEX "IX_ItemTags_ItemId" ON "ItemTags" ("ItemId");
|
||||
|
||||
CREATE UNIQUE INDEX "IX_ItemTags_ItemId_TagId" ON "ItemTags" ("ItemId", "TagId");
|
||||
|
||||
CREATE INDEX "IX_ItemTags_TagId" ON "ItemTags" ("TagId");
|
||||
|
||||
CREATE INDEX "IX_Tags_Name" ON "Tags" ("Name");
|
||||
|
||||
INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion")
|
||||
VALUES ('20251202211204_1.7.2-AddTagTables', '9.0.4');
|
||||
|
||||
COMMIT;
|
||||
VALUES ('20251203162345_1.7.0-FieldBasedDataModelUpdate', '9.0.4');
|
||||
`;
|
||||
/**
|
||||
* Individual migration SQL scripts
|
||||
@@ -1851,14 +1767,12 @@ CREATE INDEX IF NOT EXISTS "IX_Attachments_ItemId" ON "Attachments" ("ItemId");
|
||||
|
||||
CREATE TABLE "FieldDefinitions" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_FieldDefinitions" PRIMARY KEY,
|
||||
"FieldKey" TEXT NULL,
|
||||
"EntityType" TEXT NULL,
|
||||
"FieldType" TEXT NOT NULL,
|
||||
"Label" TEXT NOT NULL,
|
||||
"IsMultiValue" INTEGER NOT NULL,
|
||||
"DefaultVisibility" TEXT NULL,
|
||||
"IsHidden" INTEGER NOT NULL,
|
||||
"EnableHistory" INTEGER NOT NULL,
|
||||
"DisplayOrder" INTEGER NOT NULL,
|
||||
"Weight" INTEGER NOT NULL,
|
||||
"ApplicableToTypes" TEXT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
@@ -1869,7 +1783,7 @@ CREATE TABLE "Folders" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_Folders" PRIMARY KEY,
|
||||
"Name" TEXT NOT NULL,
|
||||
"ParentFolderId" TEXT NULL,
|
||||
"DisplayOrder" INTEGER NOT NULL,
|
||||
"Weight" INTEGER NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL,
|
||||
@@ -1887,6 +1801,16 @@ CREATE TABLE "Logos" (
|
||||
"IsDeleted" INTEGER NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE "Tags" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_Tags" PRIMARY KEY,
|
||||
"Name" TEXT NOT NULL,
|
||||
"Color" TEXT NULL,
|
||||
"DisplayOrder" INTEGER NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE "Items" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_Items" PRIMARY KEY,
|
||||
"Name" TEXT NULL,
|
||||
@@ -1916,9 +1840,10 @@ CREATE TABLE "FieldHistories" (
|
||||
CREATE TABLE "FieldValues" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_FieldValues" PRIMARY KEY,
|
||||
"ItemId" TEXT NOT NULL,
|
||||
"FieldDefinitionId" TEXT NOT NULL,
|
||||
"FieldDefinitionId" TEXT NULL,
|
||||
"FieldKey" TEXT NULL,
|
||||
"Value" TEXT NULL,
|
||||
"ValueIndex" INTEGER NOT NULL,
|
||||
"Weight" INTEGER NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL,
|
||||
@@ -1926,7 +1851,16 @@ CREATE TABLE "FieldValues" (
|
||||
CONSTRAINT "FK_FieldValues_Items_ItemId" FOREIGN KEY ("ItemId") REFERENCES "Items" ("Id") ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE INDEX "IX_FieldDefinitions_FieldKey" ON "FieldDefinitions" ("FieldKey");
|
||||
CREATE TABLE "ItemTags" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_ItemTags" PRIMARY KEY,
|
||||
"ItemId" TEXT NOT NULL,
|
||||
"TagId" TEXT NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL,
|
||||
CONSTRAINT "FK_ItemTags_Items_ItemId" FOREIGN KEY ("ItemId") REFERENCES "Items" ("Id") ON DELETE CASCADE,
|
||||
CONSTRAINT "FK_ItemTags_Tags_TagId" FOREIGN KEY ("TagId") REFERENCES "Tags" ("Id") ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE INDEX "IX_FieldHistories_FieldDefinitionId" ON "FieldHistories" ("FieldDefinitionId");
|
||||
|
||||
@@ -1934,9 +1868,13 @@ CREATE INDEX "IX_FieldHistories_ItemId" ON "FieldHistories" ("ItemId");
|
||||
|
||||
CREATE INDEX "IX_FieldValues_FieldDefinitionId" ON "FieldValues" ("FieldDefinitionId");
|
||||
|
||||
CREATE INDEX "IX_FieldValues_FieldKey" ON "FieldValues" ("FieldKey");
|
||||
|
||||
CREATE INDEX "IX_FieldValues_ItemId" ON "FieldValues" ("ItemId");
|
||||
|
||||
CREATE INDEX "IX_FieldValues_ItemId_FieldDefinitionId_ValueIndex" ON "FieldValues" ("ItemId", "FieldDefinitionId", "ValueIndex");
|
||||
CREATE INDEX "IX_FieldValues_ItemId_FieldDefinitionId_Weight" ON "FieldValues" ("ItemId", "FieldDefinitionId", "Weight");
|
||||
|
||||
CREATE INDEX "IX_FieldValues_ItemId_FieldKey" ON "FieldValues" ("ItemId", "FieldKey");
|
||||
|
||||
CREATE INDEX "IX_Folders_ParentFolderId" ON "Folders" ("ParentFolderId");
|
||||
|
||||
@@ -1944,27 +1882,15 @@ CREATE INDEX "IX_Items_FolderId" ON "Items" ("FolderId");
|
||||
|
||||
CREATE INDEX "IX_Items_LogoId" ON "Items" ("LogoId");
|
||||
|
||||
CREATE INDEX "IX_ItemTags_ItemId" ON "ItemTags" ("ItemId");
|
||||
|
||||
CREATE UNIQUE INDEX "IX_ItemTags_ItemId_TagId" ON "ItemTags" ("ItemId", "TagId");
|
||||
|
||||
CREATE INDEX "IX_ItemTags_TagId" ON "ItemTags" ("TagId");
|
||||
|
||||
CREATE UNIQUE INDEX "IX_Logos_Source" ON "Logos" ("Source");
|
||||
|
||||
|
||||
-- Login fields
|
||||
INSERT INTO FieldDefinitions (Id, FieldKey, EntityType, FieldType, Label, IsMultiValue, DefaultVisibility, EnableHistory, DisplayOrder, ApplicableToTypes, CreatedAt, UpdatedAt, IsDeleted)
|
||||
VALUES
|
||||
(lower(hex(randomblob(16))), 'login.username', 'Item', 'Text', 'Username', 0, 'Visible', 1, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'login.password', 'Item', 'Password', 'Password', 0, 'Hidden', 1, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'login.notes', 'Item', 'Text', 'Notes', 0, 'Collapsed', 0, 0, NULL, datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'login.url', 'Item', 'URL', 'Website URLs', 1, 'Visible', 0, 0, '["Login"]', datetime('now'), datetime('now'), 0);
|
||||
|
||||
-- Alias fields
|
||||
INSERT INTO FieldDefinitions (Id, FieldKey, EntityType, FieldType, Label, IsMultiValue, DefaultVisibility, EnableHistory, DisplayOrder, ApplicableToTypes, CreatedAt, UpdatedAt, IsDeleted)
|
||||
VALUES
|
||||
(lower(hex(randomblob(16))), 'alias.email', 'Item', 'Email', 'Alias Email', 0, 'Visible', 1, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'alias.first_name', 'Item', 'Text', 'First Name', 0, 'Visible', 0, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'alias.last_name', 'Item', 'Text', 'Last Name', 0, 'Visible', 0, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'alias.nickname', 'Item', 'Text', 'Nickname', 0, 'Visible', 0, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'alias.gender', 'Item', 'Text', 'Gender', 0, 'Visible', 0, 0, '["Login"]', datetime('now'), datetime('now'), 0),
|
||||
(lower(hex(randomblob(16))), 'alias.birthdate', 'Item', 'Date', 'Birth Date', 0, 'Visible', 0, 0, '["Login"]', datetime('now'), datetime('now'), 0);
|
||||
|
||||
CREATE INDEX "IX_Tags_Name" ON "Tags" ("Name");
|
||||
|
||||
|
||||
INSERT INTO Items (Id, Name, ItemType, LogoId, FolderId, CreatedAt, UpdatedAt, IsDeleted)
|
||||
@@ -2014,13 +1940,14 @@ CREATE UNIQUE INDEX "IX_Logos_Source" ON "Logos" ("Source");
|
||||
|
||||
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'login.url' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'login.url' AS FieldKey,
|
||||
s.Url AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
s.UpdatedAt AS CreatedAt,
|
||||
s.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
@@ -2030,13 +1957,14 @@ CREATE UNIQUE INDEX "IX_Logos_Source" ON "Logos" ("Source");
|
||||
|
||||
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'login.username' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'login.username' AS FieldKey,
|
||||
c.Username AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
c.UpdatedAt AS CreatedAt,
|
||||
c.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
@@ -2045,13 +1973,14 @@ CREATE UNIQUE INDEX "IX_Logos_Source" ON "Logos" ("Source");
|
||||
|
||||
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'login.notes' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'login.notes' AS FieldKey,
|
||||
c.Notes AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
c.UpdatedAt AS CreatedAt,
|
||||
c.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
@@ -2060,130 +1989,121 @@ CREATE UNIQUE INDEX "IX_Logos_Source" ON "Logos" ("Source");
|
||||
|
||||
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
p.CredentialId AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'login.password' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'login.password' AS FieldKey,
|
||||
p.Value AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
p.UpdatedAt AS CreatedAt,
|
||||
p.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Passwords p
|
||||
INNER JOIN (
|
||||
SELECT CredentialId, MAX(UpdatedAt) AS MaxUpdated
|
||||
SELECT CredentialId, MAX(UpdatedAt) AS MaxUpdated, MAX(Id) AS MaxId
|
||||
FROM Passwords
|
||||
WHERE IsDeleted = 0
|
||||
GROUP BY CredentialId
|
||||
) pm ON p.CredentialId = pm.CredentialId AND p.UpdatedAt = pm.MaxUpdated;
|
||||
) pm ON p.CredentialId = pm.CredentialId AND p.UpdatedAt = pm.MaxUpdated AND p.Id = pm.MaxId
|
||||
WHERE p.IsDeleted = 0;
|
||||
|
||||
|
||||
|
||||
INSERT INTO FieldHistories (Id, ItemId, FieldDefinitionId, ValueSnapshot, ChangedAt, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
p.CredentialId AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'login.password' LIMIT 1) AS FieldDefinitionId,
|
||||
'{"values":["' || p.Value || '"]}' AS ValueSnapshot,
|
||||
p.UpdatedAt AS ChangedAt,
|
||||
p.CreatedAt AS CreatedAt,
|
||||
p.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Passwords p
|
||||
WHERE p.Id NOT IN (
|
||||
SELECT p2.Id FROM Passwords p2
|
||||
INNER JOIN (
|
||||
SELECT CredentialId, MAX(UpdatedAt) AS MaxUpdated
|
||||
FROM Passwords
|
||||
GROUP BY CredentialId
|
||||
) pm ON p2.CredentialId = pm.CredentialId AND p2.UpdatedAt = pm.MaxUpdated
|
||||
);
|
||||
|
||||
|
||||
|
||||
-- Migrate Alias.Email
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'alias.email' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'alias.email' AS FieldKey,
|
||||
a.Email AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
a.UpdatedAt AS CreatedAt,
|
||||
a.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Credentials c
|
||||
INNER JOIN Aliases a ON a.Id = c.AliasId
|
||||
WHERE a.Email IS NOT NULL AND a.Email != '';
|
||||
|
||||
|
||||
-- Migrate Alias.FirstName
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'alias.first_name' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'alias.first_name' AS FieldKey,
|
||||
a.FirstName AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
a.UpdatedAt AS CreatedAt,
|
||||
a.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Credentials c
|
||||
INNER JOIN Aliases a ON a.Id = c.AliasId
|
||||
WHERE a.FirstName IS NOT NULL AND a.FirstName != '';
|
||||
|
||||
|
||||
-- Migrate Alias.LastName
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'alias.last_name' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'alias.last_name' AS FieldKey,
|
||||
a.LastName AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
a.UpdatedAt AS CreatedAt,
|
||||
a.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Credentials c
|
||||
INNER JOIN Aliases a ON a.Id = c.AliasId
|
||||
WHERE a.LastName IS NOT NULL AND a.LastName != '';
|
||||
|
||||
|
||||
-- Migrate Alias.NickName
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'alias.nickname' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'alias.nickname' AS FieldKey,
|
||||
a.NickName AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
a.UpdatedAt AS CreatedAt,
|
||||
a.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Credentials c
|
||||
INNER JOIN Aliases a ON a.Id = c.AliasId
|
||||
WHERE a.NickName IS NOT NULL AND a.NickName != '';
|
||||
|
||||
|
||||
-- Migrate Alias.Gender
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'alias.gender' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'alias.gender' AS FieldKey,
|
||||
a.Gender AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
a.UpdatedAt AS CreatedAt,
|
||||
a.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
FROM Credentials c
|
||||
INNER JOIN Aliases a ON a.Id = c.AliasId
|
||||
WHERE a.Gender IS NOT NULL AND a.Gender != '';
|
||||
|
||||
|
||||
-- Migrate Alias.BirthDate
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, Value, ValueIndex, CreatedAt, UpdatedAt, IsDeleted)
|
||||
|
||||
INSERT INTO FieldValues (Id, ItemId, FieldDefinitionId, FieldKey, Value, Weight, CreatedAt, UpdatedAt, IsDeleted)
|
||||
SELECT
|
||||
lower(hex(randomblob(16))) AS Id,
|
||||
c.Id AS ItemId,
|
||||
(SELECT Id FROM FieldDefinitions WHERE FieldKey = 'alias.birthdate' LIMIT 1) AS FieldDefinitionId,
|
||||
NULL AS FieldDefinitionId,
|
||||
'alias.birthdate' AS FieldKey,
|
||||
a.BirthDate AS Value,
|
||||
0 AS ValueIndex,
|
||||
0 AS Weight,
|
||||
a.UpdatedAt AS CreatedAt,
|
||||
a.UpdatedAt AS UpdatedAt,
|
||||
0 AS IsDeleted
|
||||
@@ -2283,91 +2203,5 @@ CREATE INDEX "IX_TotpCodes_ItemId" ON "TotpCodes" ("ItemId");
|
||||
COMMIT;
|
||||
|
||||
INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion")
|
||||
VALUES ('20251126211441_1.7.0-FieldBasedDataModelUpdate', '9.0.4');`,
|
||||
12: `BEGIN TRANSACTION;
|
||||
ALTER TABLE "Folders" RENAME COLUMN "DisplayOrder" TO "Weight";
|
||||
|
||||
ALTER TABLE "FieldValues" RENAME COLUMN "ValueIndex" TO "Weight";
|
||||
|
||||
DROP INDEX "IX_FieldValues_ItemId_FieldDefinitionId_ValueIndex";
|
||||
|
||||
CREATE INDEX "IX_FieldValues_ItemId_FieldDefinitionId_Weight" ON "FieldValues" ("ItemId", "FieldDefinitionId", "Weight");
|
||||
|
||||
ALTER TABLE "FieldDefinitions" RENAME COLUMN "DisplayOrder" TO "Weight";
|
||||
|
||||
ALTER TABLE "FieldDefinitions" ADD "IsHidden" INTEGER NOT NULL DEFAULT 0;
|
||||
|
||||
CREATE TABLE "ef_temp_FieldDefinitions" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_FieldDefinitions" PRIMARY KEY,
|
||||
"ApplicableToTypes" TEXT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"EnableHistory" INTEGER NOT NULL,
|
||||
"FieldKey" TEXT NULL,
|
||||
"FieldType" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL,
|
||||
"IsHidden" INTEGER NOT NULL,
|
||||
"IsMultiValue" INTEGER NOT NULL,
|
||||
"Label" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"Weight" INTEGER NOT NULL
|
||||
);
|
||||
|
||||
INSERT INTO "ef_temp_FieldDefinitions" ("Id", "ApplicableToTypes", "CreatedAt", "EnableHistory", "FieldKey", "FieldType", "IsDeleted", "IsHidden", "IsMultiValue", "Label", "UpdatedAt", "Weight")
|
||||
SELECT "Id", "ApplicableToTypes", "CreatedAt", "EnableHistory", "FieldKey", "FieldType", "IsDeleted", "IsHidden", "IsMultiValue", "Label", "UpdatedAt", "Weight"
|
||||
FROM "FieldDefinitions";
|
||||
|
||||
COMMIT;
|
||||
|
||||
PRAGMA foreign_keys = 0;
|
||||
|
||||
BEGIN TRANSACTION;
|
||||
DROP TABLE "FieldDefinitions";
|
||||
|
||||
ALTER TABLE "ef_temp_FieldDefinitions" RENAME TO "FieldDefinitions";
|
||||
|
||||
COMMIT;
|
||||
|
||||
PRAGMA foreign_keys = 1;
|
||||
|
||||
BEGIN TRANSACTION;
|
||||
CREATE INDEX "IX_FieldDefinitions_FieldKey" ON "FieldDefinitions" ("FieldKey");
|
||||
|
||||
COMMIT;
|
||||
|
||||
INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion")
|
||||
VALUES ('20251126221717_1.7.1-RenameColumns', '9.0.4');`,
|
||||
13: `BEGIN TRANSACTION;
|
||||
CREATE TABLE "Tags" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_Tags" PRIMARY KEY,
|
||||
"Name" TEXT NOT NULL,
|
||||
"Color" TEXT NULL,
|
||||
"DisplayOrder" INTEGER NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE "ItemTags" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_ItemTags" PRIMARY KEY,
|
||||
"ItemId" TEXT NOT NULL,
|
||||
"TagId" TEXT NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
"IsDeleted" INTEGER NOT NULL,
|
||||
CONSTRAINT "FK_ItemTags_Items_ItemId" FOREIGN KEY ("ItemId") REFERENCES "Items" ("Id") ON DELETE CASCADE,
|
||||
CONSTRAINT "FK_ItemTags_Tags_TagId" FOREIGN KEY ("TagId") REFERENCES "Tags" ("Id") ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE INDEX "IX_ItemTags_ItemId" ON "ItemTags" ("ItemId");
|
||||
|
||||
CREATE UNIQUE INDEX "IX_ItemTags_ItemId_TagId" ON "ItemTags" ("ItemId", "TagId");
|
||||
|
||||
CREATE INDEX "IX_ItemTags_TagId" ON "ItemTags" ("TagId");
|
||||
|
||||
CREATE INDEX "IX_Tags_Name" ON "Tags" ("Name");
|
||||
|
||||
INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion")
|
||||
VALUES ('20251202211204_1.7.2-AddTagTables', '9.0.4');
|
||||
|
||||
COMMIT;`,
|
||||
VALUES ('20251203162345_1.7.0-FieldBasedDataModelUpdate', '9.0.4');`,
|
||||
};
|
||||
|
||||
@@ -95,18 +95,4 @@ export const VAULT_VERSIONS: VaultVersion[] = [
|
||||
releaseVersion: '0.26.0',
|
||||
compatibleUpToVersion: '0.26.0',
|
||||
},
|
||||
{
|
||||
revision: 13,
|
||||
version: '1.7.1',
|
||||
description: 'Rename Columns',
|
||||
releaseVersion: '0.26.0',
|
||||
compatibleUpToVersion: '0.26.0',
|
||||
},
|
||||
{
|
||||
revision: 14,
|
||||
version: '1.8.0',
|
||||
description: 'Add Tags Tables',
|
||||
releaseVersion: '0.27.0',
|
||||
compatibleUpToVersion: '0.27.0',
|
||||
},
|
||||
];
|
||||
|
||||
Reference in New Issue
Block a user