Compare commits

...

4 Commits

10 changed files with 124 additions and 19 deletions

View File

@@ -35,6 +35,9 @@ type Repo interface {
// Get all players
GetPlayers() ([]*model.Player, error)
// Search players by a query
SearchPlayer(string) ([]*model.Player, error)
// Get all games
GetGames() ([]*model.Game, error)
}

View File

@@ -277,3 +277,30 @@ func (s *SQLRepo) GetGames() ([]*model.Game, error) {
return rtn, nil
}
func (s *SQLRepo) SearchPlayer(query string) ([]*model.Player, error) {
rows, err := s.db.Query(`
SELECT id, name, elo
FROM Players
WHERE name LIKE ?
`, query+"%")
if err != nil {
return nil, err
}
rtn := []*model.Player{}
for rows.Next() {
var player model.Player
err = rows.Scan(&player.ID, &player.Name, &player.Elo)
if err != nil {
return nil, err
}
rtn = append(rtn, &player)
}
return rtn, nil
}

View File

@@ -329,15 +329,36 @@ func createShema(repo repo.Repo) graphql.Schema {
},
},
"players": &graphql.Field{
Type: graphql.NewNonNull(graphql.NewList(player)),
Type: graphql.NewNonNull(graphql.NewList(graphql.NewNonNull(player))),
Description: "Get all players",
Args: graphql.FieldConfigArgument{
"query": &graphql.ArgumentConfig{
Type: graphql.String,
DefaultValue: "",
},
},
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
players, err := repo.GetPlayers()
if err != nil {
return nil, err
query, ok := p.Args["query"].(string)
if !ok {
log.Printf("Failed to parse query at players: %v", p.Args["query"])
return nil, nil
}
return players, nil
if query == "" {
players, err := repo.GetPlayers()
if err != nil {
return nil, err
}
return players, nil
} else {
players, err := repo.SearchPlayer(query)
if err != nil {
return nil, err
}
return players, nil
}
},
},
"games": &graphql.Field{

View File

@@ -1,4 +1,5 @@
<script lang="ts">
import Front from "./pages/Front.svelte";
import Game from "./pages/Game.svelte";
import Player from "./pages/Player.svelte";
import { RouterView } from "@dvcol/svelte-simple-router/components";
@@ -8,6 +9,11 @@
} from "@dvcol/svelte-simple-router/models";
const routes: Readonly<Route[]> = [
{
name: "front",
path: "/",
component: Front,
},
{
name: "game",
path: "/game/:{string}:id",

View File

@@ -14,6 +14,7 @@ import type { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-
* Learn more about it here: https://the-guild.dev/graphql/codegen/plugins/presets/preset-client#reducing-bundle-size
*/
const documents = {
"\n query searchPlayer($query: String!) {\n players(query: $query) {\n ID\n name\n }\n }\n ": types.SearchPlayerDocument,
"\n query getGame($gameID: ID!) {\n game(id: $gameID) {\n added\n overtime\n score\n author {\n ID\n name\n }\n team0player0 {\n ID\n name\n history(game: $gameID) {\n startElo\n delta\n }\n }\n team0player1 {\n ID\n name\n history(game: $gameID) {\n startElo\n delta\n }\n }\n team1player0 {\n ID\n name\n history(game: $gameID) {\n startElo\n delta\n }\n }\n team1player1 {\n ID\n name\n history(game: $gameID) {\n startElo\n delta\n }\n }\n }\n }\n ": types.GetGameDocument,
"\n query getPlayer($playerID: ID!) {\n player(id: $playerID) {\n ID\n name\n elo\n history {\n delta\n endElo\n game {\n id\n }\n }\n }\n }\n ": types.GetPlayerDocument,
};
@@ -32,6 +33,10 @@ const documents = {
*/
export function graphql(source: string): unknown;
/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
export function graphql(source: "\n query searchPlayer($query: String!) {\n players(query: $query) {\n ID\n name\n }\n }\n "): (typeof documents)["\n query searchPlayer($query: String!) {\n players(query: $query) {\n ID\n name\n }\n }\n "];
/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/

View File

@@ -70,7 +70,7 @@ export type Query = {
/** Get player by ID */
player?: Maybe<Player>;
/** Get all players */
players: Array<Maybe<Player>>;
players: Array<Player>;
};
@@ -88,6 +88,18 @@ export type QueryPlayerArgs = {
id: Scalars['ID']['input'];
};
export type QueryPlayersArgs = {
query?: InputMaybe<Scalars['String']['input']>;
};
export type SearchPlayerQueryVariables = Exact<{
query: Scalars['String']['input'];
}>;
export type SearchPlayerQuery = { __typename?: 'Query', players: Array<{ __typename?: 'Player', ID: string, name: string }> };
export type GetGameQueryVariables = Exact<{
gameID: Scalars['ID']['input'];
}>;
@@ -103,5 +115,6 @@ export type GetPlayerQueryVariables = Exact<{
export type GetPlayerQuery = { __typename?: 'Query', player?: { __typename?: 'Player', ID: string, name: string, elo: number, history: Array<{ __typename?: 'GameResult', delta: number, endElo: number, game: { __typename?: 'Game', id: string } } | null> } | null };
export const SearchPlayerDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"searchPlayer"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"query"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"players"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"query"},"value":{"kind":"Variable","name":{"kind":"Name","value":"query"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ID"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]} as unknown as DocumentNode<SearchPlayerQuery, SearchPlayerQueryVariables>;
export const GetGameDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"getGame"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"gameID"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"game"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"gameID"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"added"}},{"kind":"Field","name":{"kind":"Name","value":"overtime"}},{"kind":"Field","name":{"kind":"Name","value":"score"}},{"kind":"Field","name":{"kind":"Name","value":"author"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ID"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"team0player0"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ID"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"history"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"game"},"value":{"kind":"Variable","name":{"kind":"Name","value":"gameID"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"startElo"}},{"kind":"Field","name":{"kind":"Name","value":"delta"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"team0player1"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ID"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"history"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"game"},"value":{"kind":"Variable","name":{"kind":"Name","value":"gameID"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"startElo"}},{"kind":"Field","name":{"kind":"Name","value":"delta"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"team1player0"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ID"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"history"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"game"},"value":{"kind":"Variable","name":{"kind":"Name","value":"gameID"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"startElo"}},{"kind":"Field","name":{"kind":"Name","value":"delta"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"team1player1"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ID"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"history"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"game"},"value":{"kind":"Variable","name":{"kind":"Name","value":"gameID"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"startElo"}},{"kind":"Field","name":{"kind":"Name","value":"delta"}}]}}]}}]}}]}}]} as unknown as DocumentNode<GetGameQuery, GetGameQueryVariables>;
export const GetPlayerDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"getPlayer"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"playerID"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"player"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"playerID"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ID"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"elo"}},{"kind":"Field","name":{"kind":"Name","value":"history"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"delta"}},{"kind":"Field","name":{"kind":"Name","value":"endElo"}},{"kind":"Field","name":{"kind":"Name","value":"game"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]}}]}}]} as unknown as DocumentNode<GetPlayerQuery, GetPlayerQueryVariables>;

View File

@@ -0,0 +1,26 @@
<script lang="ts">
import { graphql } from "../gql";
import Search from "./Search.svelte";
import { request } from "graphql-request";
const doc = graphql(`
query searchPlayer($query: String!) {
players(query: $query) {
ID
name
}
}
`);
let suggestions: string[] = $state([]);
function findSuggestions(input: string) {
request(window.location.origin + "/graphql", doc, {
query: input,
}).then((result) => {
suggestions = result.players.map((e) => e.name);
});
}
</script>
<Search placeholder="Search player" onSuggest={findSuggestions} {suggestions} />

View File

@@ -2,18 +2,17 @@
let {
placeholder = "Search",
onSearch = () => {},
onSuggest = () => {
return [];
},
onSuggest = () => {},
suggestions = [],
}: {
placeholder?: string;
onSearch?: (input: string) => void;
onSuggest?: (input: string) => string[];
onSuggest?: (input: string) => void;
suggestions?: string[];
} = $props();
let inputText = $state("");
let showSuggestions = $derived(inputText != "");
let suggestions = $state(["One", "Two", "Three"]);
</script>
<div class="relative w-full">
@@ -26,7 +25,9 @@
onSearch(inputText);
}}
oninput={() => {
suggestions = onSuggest(inputText);
if (inputText != ""){
onSuggest(inputText);
}
}}
/>

View File

@@ -1,18 +1,13 @@
<script lang="ts">
import LastGameCard from "../lib/LastGameCard.svelte";
import PlayerSearch from "../lib/PlayerSearch.svelte";
import TopPlayerCard from "../lib/TopPlayerCard.svelte";
import Search from "../lib/Search.svelte";
</script>
<div class="flex justify-center">
<div class="flex flex-col w-3/4">
<div class="mb-7 mt-3">
<Search
placeholder="Search player"
onSuggest={(s) => {
return ["One", "Two", s];
}}
/>
<PlayerSearch />
</div>
<div class="mb-7">
<h1 class="heading">Top players</h1>

8
web/src/types.ts Normal file
View File

@@ -0,0 +1,8 @@
interface Player {
id: string
}
interface Game {
id: string,
score: number
}