← back to jra3__mulm

Function bodies 451 total

All specs Real LLM only Function bodies
getSpeciesNeedingResync function · typescript · L243-L264 (22 LOC)
src/db/iucn.ts
export async function getSpeciesNeedingResync(
  db: Database,
  daysOld: number
): Promise<SpeciesNeedingResync[]> {
  return await db.all(
    `
    SELECT
      group_id,
      canonical_genus,
      canonical_species_name,
      iucn_redlist_category,
      iucn_last_updated,
      CAST((julianday('now') - julianday(iucn_last_updated)) AS INTEGER) as days_since_update
    FROM species_name_group
    WHERE iucn_redlist_category IS NOT NULL
      AND iucn_last_updated IS NOT NULL
      AND julianday('now') - julianday(iucn_last_updated) > ?
    ORDER BY iucn_last_updated ASC
    `,
    [daysOld]
  );
}
getIucnSyncStats function · typescript · L272-L300 (29 LOC)
src/db/iucn.ts
export async function getIucnSyncStats(db: Database): Promise<IUCNSyncStats> {
  const stats = await db.get<IUCNSyncStats>(`
    SELECT
      COUNT(*) as total_syncs,
      SUM(CASE WHEN status = 'success' THEN 1 ELSE 0 END) as successful_syncs,
      SUM(CASE WHEN status = 'not_found' THEN 1 ELSE 0 END) as not_found_count,
      SUM(CASE WHEN status IN ('api_error', 'rate_limited') THEN 1 ELSE 0 END) as error_count,
      MAX(sync_date) as last_sync_date
    FROM iucn_sync_log
  `);

  if (!stats) {
    return {
      total_syncs: 0,
      successful_syncs: 0,
      not_found_count: 0,
      error_count: 0,
      last_sync_date: null,
    };
  }

  return {
    total_syncs: stats.total_syncs || 0,
    successful_syncs: stats.successful_syncs || 0,
    not_found_count: stats.not_found_count || 0,
    error_count: stats.error_count || 0,
    last_sync_date: stats.last_sync_date || null,
  };
}
createCanonicalRecommendation function · typescript · L338-L391 (54 LOC)
src/db/iucn.ts
export async function createCanonicalRecommendation(
  db: Database,
  recommendation: {
    groupId: number;
    currentGenus: string;
    currentSpecies: string;
    suggestedGenus: string;
    suggestedSpecies: string;
    iucnTaxonId: number;
    iucnUrl?: string;
    reason: string;
  }
): Promise<number> {
  try {
    const stmt = await db.prepare(
      `INSERT INTO iucn_canonical_recommendations (
        group_id,
        current_canonical_genus,
        current_canonical_species,
        suggested_canonical_genus,
        suggested_canonical_species,
        iucn_taxon_id,
        iucn_url,
        reason
      ) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
      RETURNING id`
    );

    try {
      const result = await stmt.get<{ id: number }>(
        recommendation.groupId,
        recommendation.currentGenus,
        recommendation.currentSpecies,
        recommendation.suggestedGenus,
        recommendation.suggestedSpecies,
        recommendation.iucnTaxonId,
        recommendation
getCanonicalRecommendations function · typescript · L400-L451 (52 LOC)
src/db/iucn.ts
export async function getCanonicalRecommendations(
  db: Database,
  filters?: {
    groupId?: number;
    status?: RecommendationStatus;
    limit?: number;
  }
): Promise<CanonicalRecommendation[]> {
  let query = `
    SELECT
      id,
      group_id,
      current_canonical_genus,
      current_canonical_species,
      suggested_canonical_genus,
      suggested_canonical_species,
      iucn_taxon_id,
      iucn_url,
      reason,
      status,
      created_at,
      reviewed_at,
      reviewed_by
    FROM iucn_canonical_recommendations
  `;

  const conditions: string[] = [];
  const params: (string | number)[] = [];

  if (filters?.groupId !== undefined) {
    conditions.push("group_id = ?");
    params.push(filters.groupId);
  }

  if (filters?.status) {
    conditions.push("status = ?");
    params.push(filters.status);
  }

  if (conditions.length > 0) {
    query += " WHERE " + conditions.join(" AND ");
  }

  query += " ORDER BY created_at DESC";

  if (filters?.limit) {
   
acceptCanonicalRecommendation function · typescript · L464-L543 (80 LOC)
src/db/iucn.ts
export async function acceptCanonicalRecommendation(
  db: Database,
  recommendationId: number,
  reviewedBy: number
): Promise<boolean> {
  try {
    // Get the recommendation
    const rec = await db.get<CanonicalRecommendation>(
      `SELECT * FROM iucn_canonical_recommendations WHERE id = ? AND status = 'pending'`,
      [recommendationId]
    );

    if (!rec) {
      throw new Error(`Pending recommendation ${recommendationId} not found`);
    }

    // Perform the update in a transaction
    await db.run("BEGIN TRANSACTION");

    try {
      const now = new Date().toISOString();

      // 1. Update the canonical name in species_name_group
      const updateResult = await db.run(
        `UPDATE species_name_group
         SET canonical_genus = ?,
             canonical_species_name = ?
         WHERE group_id = ?`,
        [rec.suggested_canonical_genus, rec.suggested_canonical_species, rec.group_id]
      );

      if (!updateResult.changes || updateResult.changes === 0) {
  
rejectCanonicalRecommendation function · typescript · L554-L588 (35 LOC)
src/db/iucn.ts
export async function rejectCanonicalRecommendation(
  db: Database,
  recommendationId: number,
  reviewedBy: number
): Promise<boolean> {
  try {
    const now = new Date().toISOString();

    const result = await db.run(
      `UPDATE iucn_canonical_recommendations
       SET status = 'rejected',
           reviewed_at = ?,
           reviewed_by = ?
       WHERE id = ? AND status = 'pending'`,
      [now, reviewedBy, recommendationId]
    );

    if (!result.changes || result.changes === 0) {
      throw new Error(`Pending recommendation ${recommendationId} not found`);
    }

    return true;
  } catch (err) {
    logger.error("Failed to reject canonical recommendation", {
      recommendationId,
      reviewedBy,
      error: err,
    });
    // Re-throw our own errors with their original messages
    if (err instanceof Error && err.message.includes("not found")) {
      throw err;
    }
    throw new Error("Failed to reject canonical recommendation");
  }
}
getGoogleAccount function · typescript · L32-L42 (11 LOC)
src/db/members.ts
export async function getGoogleAccount(sub: string) {
  const members = await query<{
    google_sub: string;
    member_id: number;
    google_email: string;
  }>(
    `SELECT google_sub, member_id, google_email FROM ${googleAccountTableName} WHERE google_sub = ?`,
    [sub]
  );
  return members.pop();
}
All rows above produced by Repobility · https://repobility.com
getGoogleAccountByMemberId function · typescript · L44-L53 (10 LOC)
src/db/members.ts
export async function getGoogleAccountByMemberId(member_id: number) {
  const members = await query<{
    google_sub: string;
    member_id: number;
    google_email: string;
  }>(`SELECT google_sub, member_id, google_email FROM google_account WHERE member_id = ?`, [
    member_id,
  ]);
  return members.pop();
}
createGoogleAccount function · typescript · L55-L61 (7 LOC)
src/db/members.ts
export async function createGoogleAccount(memberId: number, sub: string, email: string) {
  return insertOne(googleAccountTableName, {
    member_id: memberId,
    google_sub: sub,
    google_email: email,
  });
}
getFacebookAccount function · typescript · L69-L79 (11 LOC)
src/db/members.ts
export async function getFacebookAccount(facebookId: string) {
  const accounts = await query<{
    facebook_id: string;
    member_id: number;
    facebook_email: string;
  }>(
    `SELECT facebook_id, member_id, facebook_email FROM ${facebookAccountTableName} WHERE facebook_id = ?`,
    [facebookId]
  );
  return accounts.pop();
}
getFacebookAccountByMemberId function · typescript · L81-L90 (10 LOC)
src/db/members.ts
export async function getFacebookAccountByMemberId(member_id: number) {
  const accounts = await query<{
    facebook_id: string;
    member_id: number;
    facebook_email: string;
  }>(`SELECT facebook_id, member_id, facebook_email FROM facebook_account WHERE member_id = ?`, [
    member_id,
  ]);
  return accounts.pop();
}
createFacebookAccount function · typescript · L92-L98 (7 LOC)
src/db/members.ts
export async function createFacebookAccount(memberId: number, facebookId: string, email: string) {
  return insertOne(facebookAccountTableName, {
    member_id: memberId,
    facebook_id: facebookId,
    facebook_email: email,
  });
}
createOrUpdatePassword function · typescript · L104-L126 (23 LOC)
src/db/members.ts
export async function createOrUpdatePassword(memberId: number, passwordEntry: ScryptPassword) {
  const conn = db(true);
  try {
    const stmt = await conn.prepare(`
			INSERT INTO password_account (member_id, N, r, p, salt, hash) VALUES (?, ?, ?, ?, ?, ?)
			ON CONFLICT(member_id) DO UPDATE SET
				N = excluded.N,
				r = excluded.r,
				p = excluded.p,
				salt = excluded.salt,
				hash = excluded.hash
			`);
    try {
      const { N, r, p, salt, hash } = passwordEntry;
      await stmt.run(memberId, N, r, p, salt, hash);
    } finally {
      await stmt.finalize();
    }
  } catch (err) {
    logger.error("Failed to set password", err);
    throw new Error("Failed to set password");
  }
}
getMemberPassword function · typescript · L128-L134 (7 LOC)
src/db/members.ts
export async function getMemberPassword(memberId: number) {
  const members = await query<ScryptPassword>(
    `SELECT * FROM password_account WHERE member_id = ?`,
    [memberId]
  );
  return members.pop();
}
createMember function · typescript · L136-L190 (55 LOC)
src/db/members.ts
export async function createMember(
  email: string,
  name: string,
  credentials: {
    password?: string;
    google_sub?: string;
  } = {},
  isAdmin: boolean = false
) {
  const conn = db(true);
  await conn.exec("BEGIN TRANSACTION;");

  try {
    const userStmt = await conn.prepare(
      "INSERT INTO members (display_name, contact_email, is_admin) VALUES (?, ?, ?)"
    );
    // is this a bug... we should return the data, not the lastID
    let memberId;
    try {
      memberId = (await userStmt.run(name, email, isAdmin ? 1 : 0)).lastID;
    } finally {
      await userStmt.finalize();
    }

    if (credentials.google_sub) {
      const googleStmt = await conn.prepare(
        "INSERT INTO google_account (google_sub, member_id, google_email) VALUES (?, ?, ?)"
      );
      try {
        await googleStmt.run(credentials.google_sub, memberId, email);
      } finally {
        await googleStmt.finalize();
      }
    }

    if (credentials.password) {
      const { N, r, p, sal
Repobility — the code-quality scanner for AI-generated software · https://repobility.com
getMemberByEmail function · typescript · L201-L206 (6 LOC)
src/db/members.ts
export async function getMemberByEmail(email: string) {
  const members = await query<MemberRecord>("SELECT * FROM members WHERE contact_email = ?", [
    email,
  ]);
  return members.pop();
}
getRosterWithPoints function · typescript · L214-L283 (70 LOC)
src/db/members.ts
export async function getRosterWithPoints() {
  return query<
    MemberRecord & {
      fishTotalPoints: number;
      plantTotalPoints: number;
      coralTotalPoints: number;
      hasPassword: number;
      hasGoogleAccount: number;
      hasFacebookAccount: number;
    }
  >(`
		SELECT
			m.*,
			COALESCE(fish_points.total, 0) as fishTotalPoints,
			COALESCE(plant_points.total, 0) as plantTotalPoints,
			COALESCE(coral_points.total, 0) as coralTotalPoints,
			CASE WHEN pa.member_id IS NOT NULL THEN 1 ELSE 0 END as hasPassword,
			CASE WHEN ga.member_id IS NOT NULL THEN 1 ELSE 0 END as hasGoogleAccount,
			CASE WHEN fa.member_id IS NOT NULL THEN 1 ELSE 0 END as hasFacebookAccount
		FROM members m
		LEFT JOIN password_account pa ON m.id = pa.member_id
		LEFT JOIN google_account ga ON m.id = ga.member_id
		LEFT JOIN facebook_account fa ON m.id = fa.member_id
		LEFT JOIN (
			SELECT
				member_id,
				SUM(
					points +
					IFNULL(article_points, 0) +
					(IFNULL(first_time_species,
getMemberWithPoints function · typescript · L289-L363 (75 LOC)
src/db/members.ts
export async function getMemberWithPoints(memberId: number) {
  const rows = await query<
    MemberRecord & {
      fishTotalPoints: number;
      plantTotalPoints: number;
      coralTotalPoints: number;
      hasPassword: number;
      hasGoogleAccount: number;
      hasFacebookAccount: number;
    }
  >(
    `
		SELECT
			m.*,
			COALESCE(fish_points.total, 0) as fishTotalPoints,
			COALESCE(plant_points.total, 0) as plantTotalPoints,
			COALESCE(coral_points.total, 0) as coralTotalPoints,
			CASE WHEN pa.member_id IS NOT NULL THEN 1 ELSE 0 END as hasPassword,
			CASE WHEN ga.member_id IS NOT NULL THEN 1 ELSE 0 END as hasGoogleAccount,
			CASE WHEN fa.member_id IS NOT NULL THEN 1 ELSE 0 END as hasFacebookAccount
		FROM members m
		LEFT JOIN password_account pa ON m.id = pa.member_id
		LEFT JOIN google_account ga ON m.id = ga.member_id
		LEFT JOIN facebook_account fa ON m.id = fa.member_id
		LEFT JOIN (
			SELECT
				member_id,
				SUM(
					points +
					IFNULL(article_points, 0) +
searchMembers function · typescript · L371-L391 (21 LOC)
src/db/members.ts
export async function searchMembers(
  searchQuery: string,
  limit: number = 10
): Promise<MemberRecord[]> {
  if (!searchQuery || searchQuery.trim().length < 2) {
    return [];
  }

  const searchPattern = `%${searchQuery.trim().toLowerCase()}%`;

  return query<MemberRecord>(
    `
		SELECT * FROM members
		WHERE LOWER(display_name) LIKE ?
		   OR LOWER(contact_email) LIKE ?
		ORDER BY display_name
		LIMIT ?
	`,
    [searchPattern, searchPattern, limit]
  );
}
getAwardsForMembers function · typescript · L401-L424 (24 LOC)
src/db/members.ts
export async function getAwardsForMembers(
  memberIds: number[]
): Promise<Map<number, AwardRecord[]>> {
  if (memberIds.length === 0) {
    return new Map();
  }

  const placeholders = memberIds.map(() => "?").join(", ");
  const allAwards = await query<AwardRecord>(
    `SELECT * FROM awards WHERE member_id IN (${placeholders}) ORDER BY member_id, date_awarded DESC`,
    memberIds
  );

  // Group awards by member_id
  const awardsByMember = new Map<number, AwardRecord[]>();
  for (const award of allAwards) {
    if (!awardsByMember.has(award.member_id)) {
      awardsByMember.set(award.member_id, []);
    }
    awardsByMember.get(award.member_id)!.push(award);
  }

  return awardsByMember;
}
getMemberWithAwards function · typescript · L426-L433 (8 LOC)
src/db/members.ts
export async function getMemberWithAwards(memberId: number) {
  const [members, awards] = await Promise.all([
    query<MemberRecord>("SELECT * FROM members WHERE id = ?", [memberId]),
    getAwardsForMember(memberId),
  ]);
  const member = members.pop();
  return { ...member, awards };
}
getSpecialtyAwardProgress function · typescript · L470-L592 (123 LOC)
src/db/members.ts
export async function getSpecialtyAwardProgress(
  memberId: number
): Promise<SpecialtyAwardProgressData> {
  // Get member's approved submissions with genus information (for catfish limitation)
  const submissions = await query<{
    species_class: string;
    species_latin_name: string;
    species_type: string;
    water_type: string;
    spawn_locations: string;
    canonical_genus: string | null;
  }>(
    `
		SELECT
			s.species_class,
			s.species_latin_name,
			s.species_type,
			s.water_type,
			s.spawn_locations,
			COALESCE(
				sng_common.canonical_genus,
				sng_scientific.canonical_genus
			) as canonical_genus
		FROM submissions s
		LEFT JOIN species_common_name cn ON s.common_name_id = cn.common_name_id
		LEFT JOIN species_name_group sng_common ON cn.group_id = sng_common.group_id
		LEFT JOIN species_scientific_name scin ON s.scientific_name_id = scin.scientific_name_id
		LEFT JOIN species_name_group sng_scientific ON scin.group_id = sng_scientific.group_id
		WHERE s.m
grantAward function · typescript · L594-L629 (36 LOC)
src/db/members.ts
export async function grantAward(
  memberId: number,
  awardName: string,
  dateAwarded: Date,
  awardType: "species" | "meta_species" | "manual" = "species"
) {
  try {
    const conn = db(true);
    const stmt = await conn.prepare(
      "INSERT INTO awards (member_id, award_name, date_awarded, award_type) VALUES (?, ?, ?, ?)"
    );
    try {
      await stmt.run(memberId, awardName, dateAwarded.toISOString(), awardType);
    } finally {
      await stmt.finalize();
    }

    // Create activity feed entry for award grant
    try {
      // Determine award type based on name
      const isMetaAward =
        awardName.includes("Senior Specialist") || awardName.includes("Expert Specialist");

      await createActivity("award_granted", memberId, awardName, {
        award_name: awardName,
        award_type: isMetaAward ? "meta" : "specialty",
      });
    } catch (activityError) {
      logger.error("Failed to create activity feed entry for award", activityError);
      // Don't f
Repobility (the analyzer behind this table) · https://repobility.com
getAdminEmails function · typescript · L632-L637 (6 LOC)
src/db/members.ts
export async function getAdminEmails(): Promise<string[]> {
  const rows = await query<{ contact_email: string }>(
    `SELECT contact_email FROM members where is_admin = 1`
  );
  return rows.map((row) => row.contact_email);
}
regenerateSessionInDB function · typescript · L6-L34 (29 LOC)
src/db/sessions.ts
export async function regenerateSessionInDB(
  oldSessionId: string | undefined,
  newSessionId: string,
  memberId: number,
  expiresOn: string
): Promise<void> {
  await withTransaction(async (db) => {
    // Delete old session if it exists
    if (oldSessionId && oldSessionId !== "undefined") {
      const deleteStmt = await db.prepare("DELETE FROM sessions WHERE session_id = ?");
      try {
        await deleteStmt.run(oldSessionId);
      } finally {
        await deleteStmt.finalize();
      }
    }

    // Create new session
    const insertStmt = await db.prepare(`
      INSERT INTO sessions (session_id, member_id, expires_on)
      VALUES (?, ?, ?);
    `);
    try {
      await insertStmt.run(newSessionId, memberId, expiresOn);
    } finally {
      await insertStmt.finalize();
    }
  });
}
updateSetting function · typescript · L27-L37 (11 LOC)
src/db/settings.ts
export async function updateSetting(key: string, value: string): Promise<void> {
  const stmt = await writeConn.prepare(
    `INSERT INTO settings (key, value, updated_at)
     VALUES (?, ?, CURRENT_TIMESTAMP)
     ON CONFLICT(key) DO UPDATE SET
       value = excluded.value,
       updated_at = CURRENT_TIMESTAMP`
  );
  await stmt.run(key, value);
  await stmt.finalize();
}
querySpeciesNames function · typescript · L34-L74 (41 LOC)
src/db/species.ts
export async function querySpeciesNames() {
  // Query split schema tables and create paired records
  const groups = await query<{
    group_id: number;
    program_class: string;
    canonical_genus: string;
    canonical_species_name: string;
  }>(
    "SELECT group_id, program_class, canonical_genus, canonical_species_name FROM species_name_group"
  );

  const results: NameSynonym[] = [];

  for (const group of groups) {
    const [commonNames, scientificNames] = await Promise.all([
      query<{ common_name: string }>(
        "SELECT common_name FROM species_common_name WHERE group_id = ? ORDER BY common_name",
        [group.group_id]
      ),
      query<{ scientific_name: string }>(
        "SELECT scientific_name FROM species_scientific_name WHERE group_id = ? ORDER BY scientific_name",
        [group.group_id]
      ),
    ]);

    // Pair common names with scientific names
    const maxLength = Math.max(commonNames.length, scientificNames.length);
    for (let i = 0; i < m
mergeSpecies function · typescript · L154-L245 (92 LOC)
src/db/species.ts
export async function mergeSpecies(
  canonicalGroupId: number,
  defunctGroupId: number
): Promise<void> {
  try {
    await withTransaction(async (db) => {
      // Get all names from defunct group
      const commonNamesDefunct = await db.all<Array<{ common_name_id: number; common_name: string }>>(
        "SELECT common_name_id, common_name FROM species_common_name WHERE group_id = ?",
        [defunctGroupId]
      );
      const scientificNamesDefunct = await db.all<Array<{ scientific_name_id: number; scientific_name: string }>>(
        "SELECT scientific_name_id, scientific_name FROM species_scientific_name WHERE group_id = ?",
        [defunctGroupId]
      );

      // For each defunct common name, update submissions and handle duplicates
      for (const defunctName of commonNamesDefunct) {
        // Find matching common name in canonical group (case-insensitive)
        const matchingCanonical = await db.all<Array<{ common_name_id: number }>>(
          "SELECT common_name
getSpeciesGroup function · typescript · L252-L268 (17 LOC)
src/db/species.ts
export async function getSpeciesGroup(groupId: number) {
  const rows = await query<{
    group_id: number;
    program_class: string;
    species_type: string;
    canonical_genus: string;
    canonical_species_name: string;
    base_points: number | null;
    is_cares_species: number;
  }>(
    `
		SELECT * FROM species_name_group WHERE group_id = ?`,
    [groupId]
  );

  return rows.pop();
}
getGroupIdFromNameId function · typescript · L276-L293 (18 LOC)
src/db/species.ts
export async function getGroupIdFromNameId(
  nameId: number,
  isCommonName: boolean
): Promise<number | undefined> {
  if (isCommonName) {
    const rows = await query<{ group_id: number }>(
      "SELECT group_id FROM species_common_name WHERE common_name_id = ?",
      [nameId]
    );
    return rows.pop()?.group_id;
  } else {
    const rows = await query<{ group_id: number }>(
      "SELECT group_id FROM species_scientific_name WHERE scientific_name_id = ?",
      [nameId]
    );
    return rows.pop()?.group_id;
  }
}
buildSpeciesSearchQuery function · typescript · L338-L345 (8 LOC)
src/db/species.ts
function buildSpeciesSearchQuery(
  search?: string,
  species_type?: string,
  species_class?: string,
  sort: "name" | "reports" | "breeders" = "reports",
  limit?: number,
  cares_only?: boolean
): { sql: string; params: unknown[] } {
Repobility · code-quality intelligence platform · https://repobility.com
searchSpeciesTypeahead function · typescript · L426-L506 (81 LOC)
src/db/species.ts
export async function searchSpeciesTypeahead(
  searchQuery: string,
  filters: Omit<SpeciesFilters, "search" | "sort"> = {},
  limit: number = 10
): Promise<SpeciesNameRecord[]> {
  if (!searchQuery || searchQuery.trim().length < 2) {
    return [];
  }

  const searchPattern = `%${searchQuery.trim().toLowerCase()}%`;
  const conditions: string[] = ["1=1"];
  const params: unknown[] = [];

  if (filters.species_type) {
    conditions.push("AND sng.species_type = ?");
    params.push(filters.species_type);
  }

  if (filters.species_class) {
    conditions.push("AND sng.program_class = ?");
    params.push(filters.species_class);
  }

  // Build WHERE clause for both queries
  const whereClause = conditions.join(" ");

  // UNION query: search both common names and scientific names
  // Each subquery joins with species_name_group for metadata
  // Uses canonical names from species_name_group as fallback for pairing
  const sql = `
    SELECT
      cn.common_name_id as name_id,
      cn
getSpeciesForExplorer function · typescript · L508-L523 (16 LOC)
src/db/species.ts
export async function getSpeciesForExplorer(
  filters: SpeciesFilters = {}
): Promise<SpeciesExplorerItem[]> {
  const { species_type, species_class, search, sort = "reports", cares_only } = filters;

  const { sql, params } = buildSpeciesSearchQuery(
    search,
    species_type,
    species_class,
    sort,
    undefined, // No limit for explorer - return all results
    cares_only
  );

  return query<SpeciesExplorerItem>(sql, params);
}
getSpeciesDetail function · typescript · L548-L611 (64 LOC)
src/db/species.ts
export async function getSpeciesDetail(groupId: number) {
  const groupRows = await query<{
    group_id: number;
    program_class: string;
    species_type: string;
    canonical_genus: string;
    canonical_species_name: string;
    base_points: number | null;
    is_cares_species: number;
    iucn_redlist_category: string | null;
    iucn_population_trend: string | null;
    iucn_last_updated: string | null;
    iucn_redlist_id: number | null;
    iucn_redlist_url: string | null;
  }>(
    `
		SELECT group_id, program_class, species_type, canonical_genus, canonical_species_name, base_points, is_cares_species, iucn_redlist_category, iucn_population_trend, iucn_last_updated, iucn_redlist_id, iucn_redlist_url
		FROM species_name_group
		WHERE group_id = ?
	`,
    [groupId]
  );

  if (groupRows.length === 0) {
    return null;
  }

  // Get all names from split schema tables
  const [commonNames, scientificNames] = await Promise.all([
    query<{ common_name_id: number; common_name: s
getBreedersForSpecies function · typescript · L635-L678 (44 LOC)
src/db/species.ts
export async function getBreedersForSpecies(groupId: number) {
  return query<SpeciesBreeder>(
    `
		SELECT
			m.id as member_id,
			m.display_name as member_name,
			COUNT(s.id) as breed_count,
			MIN(s.approved_on) as first_breed_date,
			MAX(s.approved_on) as latest_breed_date,
			GROUP_CONCAT(
				s.id || '|' ||
				s.species_common_name || '|' ||
				s.species_latin_name || '|' ||
				s.approved_on || '|' ||
				COALESCE(s.points, 0)
			) as submissions_concat
		FROM members m
		JOIN submissions s ON m.id = s.member_id
		LEFT JOIN species_common_name cn ON s.common_name_id = cn.common_name_id
		LEFT JOIN species_scientific_name scin ON s.scientific_name_id = scin.scientific_name_id
		WHERE (cn.group_id = ? OR scin.group_id = ?)
		  AND s.approved_on IS NOT NULL
		GROUP BY m.id, m.display_name
		ORDER BY breed_count DESC, latest_breed_date DESC
	`,
    [groupId, groupId]
  ).then((rows) => {
    return rows.map((row) => ({
      ...row,
      submissions: row.submissions_concat
 
getFilterOptions function · typescript · L680-L691 (12 LOC)
src/db/species.ts
export async function getFilterOptions() {
  const speciesTypes = await query<{ species_type: string }>(`
		SELECT DISTINCT species_type
		FROM submissions
		WHERE approved_on IS NOT NULL
		ORDER BY species_type
	`);

  return {
    species_types: speciesTypes.map((s) => s.species_type),
  };
}
getCommonNamesForGroup function · typescript · L727-L737 (11 LOC)
src/db/species.ts
export async function getCommonNamesForGroup(groupId: number): Promise<CommonName[]> {
  return query<CommonName>(
    `
    SELECT common_name_id, group_id, common_name
    FROM species_common_name
    WHERE group_id = ?
    ORDER BY common_name
  `,
    [groupId]
  );
}
getScientificNamesForGroup function · typescript · L744-L754 (11 LOC)
src/db/species.ts
export async function getScientificNamesForGroup(groupId: number): Promise<ScientificName[]> {
  return query<ScientificName>(
    `
    SELECT scientific_name_id, group_id, scientific_name
    FROM species_scientific_name
    WHERE group_id = ?
    ORDER BY scientific_name
  `,
    [groupId]
  );
}
getNamesForGroup function · typescript · L761-L771 (11 LOC)
src/db/species.ts
export async function getNamesForGroup(groupId: number): Promise<SpeciesNames> {
  const [common_names, scientific_names] = await Promise.all([
    getCommonNamesForGroup(groupId),
    getScientificNamesForGroup(groupId),
  ]);

  return {
    common_names,
    scientific_names,
  };
}
All rows above produced by Repobility · https://repobility.com
getSynonymsForGroup function · typescript · L779-L831 (53 LOC)
src/db/species.ts
export async function getSynonymsForGroup(groupId: number): Promise<SpeciesSynonym[]> {
  // Post-migration 030: species_name table no longer exists
  // Return data from split tables (species_common_name and species_scientific_name)

  const [commonNames, scientificNames] = await Promise.all([
    query<{ common_name_id: number; group_id: number; common_name: string }>(
      "SELECT common_name_id, group_id, common_name FROM species_common_name WHERE group_id = ? ORDER BY common_name",
      [groupId]
    ),
    query<{ scientific_name_id: number; group_id: number; scientific_name: string }>(
      "SELECT scientific_name_id, group_id, scientific_name FROM species_scientific_name WHERE group_id = ? ORDER BY scientific_name",
      [groupId]
    ),
  ]);

  // Return cross-product of common names × scientific names
  // This maintains backward compatibility with the old paired model
  const results: SpeciesSynonym[] = [];

  if (commonNames.length === 0 || scientificNames.length === 0
addCommonName function · typescript · L840-L883 (44 LOC)
src/db/species.ts
export async function addCommonName(groupId: number, commonName: string): Promise<number> {
  const trimmed = commonName.trim();

  if (!trimmed) {
    throw new Error("Common name cannot be empty");
  }

  // Verify species group exists
  const groups = await query<{ group_id: number }>(
    "SELECT group_id FROM species_name_group WHERE group_id = ?",
    [groupId]
  );

  if (groups.length === 0) {
    throw new Error(`Species group ${groupId} not found`);
  }

  try {
    const conn = writeConn;
    const stmt = await conn.prepare(`
      INSERT INTO species_common_name (group_id, common_name)
      VALUES (?, ?)
      RETURNING common_name_id
    `);

    try {
      const result = await stmt.get<{ common_name_id: number }>(groupId, trimmed);

      if (!result || !result.common_name_id) {
        throw new Error("Failed to insert common name");
      }

      return result.common_name_id;
    } finally {
      await stmt.finalize();
    }
  } catch (err) {
    if (err instanceof 
addScientificName function · typescript · L892-L935 (44 LOC)
src/db/species.ts
export async function addScientificName(groupId: number, scientificName: string): Promise<number> {
  const trimmed = scientificName.trim();

  if (!trimmed) {
    throw new Error("Scientific name cannot be empty");
  }

  // Verify species group exists
  const groups = await query<{ group_id: number }>(
    "SELECT group_id FROM species_name_group WHERE group_id = ?",
    [groupId]
  );

  if (groups.length === 0) {
    throw new Error(`Species group ${groupId} not found`);
  }

  try {
    const conn = writeConn;
    const stmt = await conn.prepare(`
      INSERT INTO species_scientific_name (group_id, scientific_name)
      VALUES (?, ?)
      RETURNING scientific_name_id
    `);

    try {
      const result = await stmt.get<{ scientific_name_id: number }>(groupId, trimmed);

      if (!result || !result.scientific_name_id) {
        throw new Error("Failed to insert scientific name");
      }

      return result.scientific_name_id;
    } finally {
      await stmt.finalize();
   
updateCommonName function · typescript · L944-L972 (29 LOC)
src/db/species.ts
export async function updateCommonName(commonNameId: number, newName: string): Promise<number> {
  const trimmed = newName.trim();

  if (!trimmed) {
    throw new Error("Common name cannot be empty");
  }

  try {
    const conn = writeConn;
    const stmt = await conn.prepare(`
      UPDATE species_common_name
      SET common_name = ?
      WHERE common_name_id = ?
    `);

    try {
      const result = await stmt.run(trimmed, commonNameId);
      return result.changes || 0;
    } finally {
      await stmt.finalize();
    }
  } catch (err) {
    if (err instanceof Error && err.message.includes("UNIQUE constraint")) {
      throw new Error("This common name already exists for this species");
    }
    logger.error("Failed to update common name", err);
    throw new Error("Failed to update common name");
  }
}
updateScientificName function · typescript · L981-L1012 (32 LOC)
src/db/species.ts
export async function updateScientificName(
  scientificNameId: number,
  newName: string
): Promise<number> {
  const trimmed = newName.trim();

  if (!trimmed) {
    throw new Error("Scientific name cannot be empty");
  }

  try {
    const conn = writeConn;
    const stmt = await conn.prepare(`
      UPDATE species_scientific_name
      SET scientific_name = ?
      WHERE scientific_name_id = ?
    `);

    try {
      const result = await stmt.run(trimmed, scientificNameId);
      return result.changes || 0;
    } finally {
      await stmt.finalize();
    }
  } catch (err) {
    if (err instanceof Error && err.message.includes("UNIQUE constraint")) {
      throw new Error("This scientific name already exists for this species");
    }
    logger.error("Failed to update scientific name", err);
    throw new Error("Failed to update scientific name");
  }
}
deleteCommonName function · typescript · L1019-L1034 (16 LOC)
src/db/species.ts
export async function deleteCommonName(commonNameId: number): Promise<number> {
  try {
    const conn = writeConn;
    const stmt = await conn.prepare("DELETE FROM species_common_name WHERE common_name_id = ?");

    try {
      const result = await stmt.run(commonNameId);
      return result.changes || 0;
    } finally {
      await stmt.finalize();
    }
  } catch (err) {
    logger.error("Failed to delete common name", err);
    throw new Error("Failed to delete common name");
  }
}
deleteScientificName function · typescript · L1041-L1058 (18 LOC)
src/db/species.ts
export async function deleteScientificName(scientificNameId: number): Promise<number> {
  try {
    const conn = writeConn;
    const stmt = await conn.prepare(
      "DELETE FROM species_scientific_name WHERE scientific_name_id = ?"
    );

    try {
      const result = await stmt.run(scientificNameId);
      return result.changes || 0;
    } finally {
      await stmt.finalize();
    }
  } catch (err) {
    logger.error("Failed to delete scientific name", err);
    throw new Error("Failed to delete scientific name");
  }
}
addSynonym function · typescript · L1066-L1113 (48 LOC)
src/db/species.ts
export async function addSynonym(
  groupId: number,
  commonName: string,
  scientificName: string
): Promise<number> {
  // Post-migration 030: Insert into both split tables
  // Returns the common_name_id as the primary identifier

  const trimmedCommon = commonName.trim();
  const trimmedScientific = scientificName.trim();

  if (!trimmedCommon || !trimmedScientific) {
    throw new Error("Common name and scientific name cannot be empty");
  }

  // Verify species group exists
  const groups = await query<{ group_id: number }>(
    "SELECT group_id FROM species_name_group WHERE group_id = ?",
    [groupId]
  );

  if (groups.length === 0) {
    throw new Error(`Species group ${groupId} not found`);
  }

  try {
    // Add common name
    const commonNameId = await addCommonName(groupId, trimmedCommon);

    // Add scientific name (ignore duplicates since it might already exist)
    try {
      await addScientificName(groupId, trimmedScientific);
    } catch (err) {
      // If scie
Repobility — the code-quality scanner for AI-generated software · https://repobility.com
updateSynonym function · typescript · L1122-L1152 (31 LOC)
src/db/species.ts
export async function updateSynonym(
  nameId: number,
  updates: {
    commonName?: string;
    scientificName?: string;
  }
): Promise<number> {
  // Post-migration 030: nameId is always a common_name_id (from getSynonymsForGroup)
  // This function only updates common names for backward compatibility

  const { commonName, scientificName } = updates;

  // At least one field must be provided
  if (commonName === undefined && scientificName === undefined) {
    throw new Error("At least one field (commonName or scientificName) must be provided");
  }

  // Only common name updates are supported via this wrapper
  // (nameId comes from getSynonymsForGroup which returns common_name_id)
  if (scientificName !== undefined) {
    throw new Error(
      "updateSynonym() only supports updating common names. Use updateScientificName() directly to update scientific names."
    );
  }

  if (commonName !== undefined) {
    return await updateCommonName(nameId, commonName);
  }

  return 0;
}
deleteSynonym function · typescript · L1161-L1193 (33 LOC)
src/db/species.ts
export async function deleteSynonym(nameId: number, force = false): Promise<number> {
  // Post-migration 030: nameId is always a common_name_id (from getSynonymsForGroup)
  // This function only deletes common names for backward compatibility

  // Verify the common name exists and get its group
  const commonNameRecords = await query<{ common_name_id: number; group_id: number }>(
    "SELECT common_name_id, group_id FROM species_common_name WHERE common_name_id = ?",
    [nameId]
  );

  if (commonNameRecords.length === 0) {
    throw new Error(`Common name ID ${nameId} not found`);
  }

  const groupId = commonNameRecords[0].group_id;

  // Check if this is the last common name for the group (only if not force)
  if (!force) {
    const groupCommonNames = await query<{ count: number }>(
      "SELECT COUNT(*) as count FROM species_common_name WHERE group_id = ?",
      [groupId]
    );

    const count = groupCommonNames[0]?.count || 0;
    if (count <= 1) {
      throw new Error(
 
getSpeciesForAdmin function · typescript · L1241-L1404 (164 LOC)
src/db/species.ts
export async function getSpeciesForAdmin(
  filters: SpeciesAdminFilters = {},
  sort: "name" | "points" | "class" = "name",
  limit = 50,
  offset = 0
): Promise<SpeciesAdminListResult> {
  const { species_type, program_class, has_base_points, is_cares_species, iucn_category, search } =
    filters;

  // Build WHERE conditions
  const conditions: string[] = ["1=1"];
  const params: unknown[] = [];

  if (species_type) {
    conditions.push("AND sng.species_type = ?");
    params.push(species_type);
  }

  if (program_class) {
    conditions.push("AND sng.program_class = ?");
    params.push(program_class);
  }

  if (has_base_points !== undefined) {
    conditions.push(
      has_base_points ? "AND sng.base_points IS NOT NULL" : "AND sng.base_points IS NULL"
    );
  }

  if (is_cares_species !== undefined) {
    conditions.push("AND sng.is_cares_species = ?");
    params.push(is_cares_species ? 1 : 0);
  }

  if (iucn_category) {
    if (iucn_category === "with_data") {
      condit
‹ prevpage 4 / 10next ›