2025-03-20 22:55:27 +00:00

145 lines
4.2 KiB
TypeScript

import {
species, type Species, type InsertSpecies,
searches, type Search, type InsertSearch,
apiTokens, type ApiToken, type InsertApiToken
} from "@shared/schema";
export interface IStorage {
// Species methods
getSpecies(id: number): Promise<Species | undefined>;
getSpeciesByName(scientificName: string): Promise<Species | undefined>;
getAllSpecies(): Promise<Species[]>;
saveSpecies(speciesData: InsertSpecies): Promise<Species>;
// Search methods
addSearch(search: InsertSearch): Promise<Search>;
getRecentSearches(limit?: number): Promise<Search[]>;
// API Token methods
saveApiToken(token: InsertApiToken): Promise<ApiToken>;
getActiveToken(): Promise<ApiToken | undefined>;
updateToken(id: number, token: string, iucnToken?: string): Promise<ApiToken | undefined>;
}
export class MemStorage implements IStorage {
private speciesStore: Map<number, Species>;
private searchesStore: Map<number, Search>;
private tokensStore: Map<number, ApiToken>;
private speciesId: number;
private searchId: number;
private tokenId: number;
constructor() {
this.speciesStore = new Map();
this.searchesStore = new Map();
this.tokensStore = new Map();
this.speciesId = 1;
this.searchId = 1;
this.tokenId = 1;
}
// Species methods
async getSpecies(id: number): Promise<Species | undefined> {
return this.speciesStore.get(id);
}
async getSpeciesByName(scientificName: string): Promise<Species | undefined> {
return Array.from(this.speciesStore.values()).find(
(species) => species.scientificName.toLowerCase() === scientificName.toLowerCase()
);
}
async getAllSpecies(): Promise<Species[]> {
return Array.from(this.speciesStore.values()).sort(
(a, b) => new Date(b.searchedAt!).getTime() - new Date(a.searchedAt!).getTime()
);
}
async saveSpecies(speciesData: InsertSpecies): Promise<Species> {
const existing = await this.getSpeciesByName(speciesData.scientificName);
if (existing) {
// Update existing species with new data and timestamp
const updated: Species = {
...existing,
...speciesData,
searchedAt: new Date(),
};
this.speciesStore.set(existing.id, updated);
return updated;
}
const id = this.speciesId++;
const timestamp = new Date();
const species: Species = {
...(speciesData as any), // Cast to any to avoid TypeScript errors
id,
searchedAt: timestamp
};
this.speciesStore.set(id, species);
return species;
}
// Search methods
async addSearch(searchData: InsertSearch): Promise<Search> {
const id = this.searchId++;
const search: Search = {
...searchData,
id,
timestamp: new Date()
};
this.searchesStore.set(id, search);
return search;
}
async getRecentSearches(limit: number = 10): Promise<Search[]> {
return Array.from(this.searchesStore.values())
.sort((a, b) => {
const dateA = a.timestamp ? new Date(a.timestamp).getTime() : 0;
const dateB = b.timestamp ? new Date(b.timestamp).getTime() : 0;
return dateB - dateA;
})
.slice(0, limit);
}
// API Token methods
async saveApiToken(tokenData: InsertApiToken): Promise<ApiToken> {
// Deactivate all existing tokens
this.tokensStore.forEach((token) => {
token.isActive = false;
});
const id = this.tokenId++;
// Ensure all required fields are present
const token: ApiToken = {
id,
token: tokenData.token,
iucnToken: tokenData.iucnToken || null,
isActive: tokenData.isActive || true,
createdAt: new Date()
};
this.tokensStore.set(id, token);
return token;
}
async getActiveToken(): Promise<ApiToken | undefined> {
return Array.from(this.tokensStore.values()).find(token => token.isActive);
}
async updateToken(id: number, token: string, iucnToken?: string): Promise<ApiToken | undefined> {
const existingToken = this.tokensStore.get(id);
if (!existingToken) return undefined;
const updatedToken = {
...existingToken,
token,
...(iucnToken !== undefined ? { iucnToken } : {})
};
this.tokensStore.set(id, updatedToken);
return updatedToken;
}
}
export const storage = new MemStorage();