Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 9 additions & 4 deletions scripts/generate-query-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ async function main(): Promise<void> {
// Install and load level_pivot
console.log("Installing level_pivot...");
await connection.run(
"FORCE INSTALL level_pivot FROM 'https://halgari.github.io/duckdb-level-pivot/current_release'",
"FORCE INSTALL level_pivot FROM 'https://nexus-mods.github.io/duckdb-level-pivot/current_release'",
);
await connection.run("LOAD level_pivot");
const tmpDbPath = path.join(tmpDir, "gen.db");
Expand Down Expand Up @@ -259,6 +259,9 @@ function generateTypeScript(
lines.push("// AUTO-GENERATED by scripts/generate-query-types.ts — DO NOT EDIT");
lines.push("");
lines.push('import type { Table } from "../Table";');
if (selectTypeInfos.some(({ query }) => query.params.length === 0)) {
lines.push('import type { View } from "../View";');
}
lines.push('import type { Database } from "../Database";');
lines.push("");

Expand Down Expand Up @@ -291,12 +294,14 @@ function generateTypeScript(
}
lines.push("");

// Emitted as a type alias (not an interface) so the row satisfies the
// Record<string, unknown> constraint on View<T>.
lines.push(`/** Result row for the '${query.name}' query */`);
lines.push(`export interface ${pascal}Row {`);
lines.push(`export type ${pascal}Row = {`);
for (const col of columns) {
lines.push(` ${col.name}: ${col.tsType};`);
}
lines.push("}");
lines.push("};");
lines.push("");
}

Expand Down Expand Up @@ -330,7 +335,7 @@ function generateTypeScript(
lines.push(` ${propName}: db.createView("${query.name}"),`);
}
}
lines.push(" } as Models;");
lines.push(" };");
lines.push("}");
lines.push("");

Expand Down
49 changes: 47 additions & 2 deletions src/main/src/store/generated/queryTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import type { Database } from "../Database";
import type { Table } from "../Table";
import type { View } from "../View";

/** Row type for the 'mods_pivot' pivot table */
export type ModsPivotRow = {
Expand All @@ -19,37 +20,81 @@ export type ProfilesPivotRow = {
lastActivated: bigint;
};

/** Row type for the 'profile_settings_pivot' pivot table */
export type ProfileSettingsPivotRow = {
section: string;
activeProfileId: string;
};

/** Row type for the 'mod_attributes_pivot' pivot table */
export type ModAttributesPivotRow = {
game_id: string;
vortex_mod_id: string;
source: string;
modId: bigint;
fileId: bigint;
downloadGame: string;
};

/** Row type for the 'mod_state_pivot' pivot table */
export type ModStatePivotRow = {
game_id: string;
vortex_mod_id: string;
state: string;
};

/** Parameters for the 'active_profile_nexus_files' query (no parameters) */
export type ActiveProfileNexusFilesParams = Record<string, never>;

/** Result row for the 'active_profile_nexus_files' query */
export type ActiveProfileNexusFilesRow = {
game_id: string;
mod_id: bigint;
file_id: bigint;
vortex_mod_id: string;
};

/** Parameters for the 'recently_managed_games' query */
export interface RecentlyManagedGamesParams {
current_game_id: string;
}

/** Result row for the 'recently_managed_games' query */
export interface RecentlyManagedGamesRow {
export type RecentlyManagedGamesRow = {
game_id: string;
}
};

/** Typed model accessors — generated from SQL definitions */
export interface Models {
mods: Table<ModsPivotRow>;
profiles: Table<ProfilesPivotRow>;
profileSettings: Table<ProfileSettingsPivotRow>;
modAttributes: Table<ModAttributesPivotRow>;
modState: Table<ModStatePivotRow>;
activeProfileNexusFiles: View<ActiveProfileNexusFilesRow>;
}

/** Create typed model accessors from a Database instance */
export function createModels(db: Database): Models {
return {
mods: db.createTable("mods_pivot"),
profiles: db.createTable("profiles_pivot"),
profileSettings: db.createTable("profile_settings_pivot"),
modAttributes: db.createTable("mod_attributes_pivot"),
modState: db.createTable("mod_state_pivot"),
activeProfileNexusFiles: db.createView("active_profile_nexus_files"),
};
}

/** Maps query names to their parameter types */
export interface QueryParamsMap {
active_profile_nexus_files: ActiveProfileNexusFilesParams;
recently_managed_games: RecentlyManagedGamesParams;
}

/** Maps query names to their result row types */
export interface QueryResultMap {
active_profile_nexus_files: ActiveProfileNexusFilesRow;
recently_managed_games: RecentlyManagedGamesRow;
}

Expand Down
18 changes: 18 additions & 0 deletions src/queries/select/nexus_files.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
-- @type select

-- @name active_profile_nexus_files
-- @description Lists gameId/modId/fileId for every installed Nexus mod file of the currently active profile's game
SELECT
coalesce(ma.downloadGame, ma.game_id) AS game_id,
ma.modId AS mod_id,
ma.fileId AS file_id,
ma.vortex_mod_id
FROM db.profile_settings_pivot ps
JOIN db.profiles_pivot pr ON pr.profile_id = ps.activeProfileId
JOIN db.mod_attributes_pivot ma ON ma.game_id = pr.gameId
JOIN db.mod_state_pivot ms ON ms.game_id = ma.game_id
AND ms.vortex_mod_id = ma.vortex_mod_id
WHERE ps.section = 'profiles'
AND ma.source = 'nexus'
AND ms.state = 'installed'
ORDER BY game_id, mod_id, file_id;
27 changes: 27 additions & 0 deletions src/queries/setup/tables.sql
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,30 @@ CALL level_pivot_create_table(
['profile_id', 'name', 'gameId', 'lastActivated'],
column_types := ['VARCHAR', 'JSON VARCHAR', 'JSON VARCHAR', 'JSON BIGINT']
);

-- @name profile_settings_pivot
-- @description Creates the profile-settings pivot table (activeProfileId lives at settings###profiles###activeProfileId)
CALL level_pivot_create_table(
'db', 'profile_settings_pivot',
'settings###{section}###{attr}',
['section', 'activeProfileId'],
column_types := ['VARCHAR', 'JSON VARCHAR']
);

-- @name mod_attributes_pivot
-- @description Creates the mod-attributes pivot table (mod attributes live under persistent###mods###<game>###<mod>###attributes###*)
CALL level_pivot_create_table(
'db', 'mod_attributes_pivot',
'persistent###mods###{game_id}###{vortex_mod_id}###attributes###{attr}',
['game_id', 'vortex_mod_id', 'source', 'modId', 'fileId', 'downloadGame'],
column_types := ['VARCHAR', 'VARCHAR', 'JSON VARCHAR', 'JSON BIGINT', 'JSON BIGINT', 'JSON VARCHAR']
);

-- @name mod_state_pivot
-- @description Creates the mod-state pivot table (state is a top-level mod field, not an attribute)
CALL level_pivot_create_table(
'db', 'mod_state_pivot',
'persistent###mods###{game_id}###{vortex_mod_id}###{attr}',
['game_id', 'vortex_mod_id', 'state'],
column_types := ['VARCHAR', 'VARCHAR', 'JSON VARCHAR']
);