@opprs/db-prisma 2.2.1-canary.cd8b178 → 2.2.1-canary.d2b7951

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -23,18 +23,23 @@ __export(index_exports, {
23
23
  MAX_API_KEYS_PER_USER: () => MAX_API_KEYS_PER_USER,
24
24
  applyRDDecayForInactivePlayers: () => applyRDDecayForInactivePlayers,
25
25
  connect: () => connect,
26
+ countBlogPosts: () => countBlogPosts,
27
+ countBlogTags: () => countBlogTags,
26
28
  countEntries: () => countEntries,
27
29
  countLocations: () => countLocations,
28
30
  countMatches: () => countMatches,
29
31
  countOpprPlayerRankings: () => countOpprPlayerRankings,
30
32
  countOpprRankingHistory: () => countOpprRankingHistory,
31
33
  countPlayers: () => countPlayers,
34
+ countPublishedBlogPosts: () => countPublishedBlogPosts,
32
35
  countRounds: () => countRounds,
33
36
  countStandings: () => countStandings,
34
37
  countTournaments: () => countTournaments,
35
38
  countUserApiKeys: () => countUserApiKeys,
36
39
  countUsers: () => countUsers,
37
40
  createApiKey: () => createApiKey,
41
+ createBlogPost: () => createBlogPost,
42
+ createBlogTag: () => createBlogTag,
38
43
  createEntry: () => createEntry,
39
44
  createLocation: () => createLocation,
40
45
  createManyEntries: () => createManyEntries,
@@ -51,6 +56,8 @@ __export(index_exports, {
51
56
  createUser: () => createUser,
52
57
  createUserWithPlayer: () => createUserWithPlayer,
53
58
  deleteApiKey: () => deleteApiKey,
59
+ deleteBlogPost: () => deleteBlogPost,
60
+ deleteBlogTag: () => deleteBlogTag,
54
61
  deleteEntriesByMatch: () => deleteEntriesByMatch,
55
62
  deleteEntry: () => deleteEntry,
56
63
  deleteLocation: () => deleteLocation,
@@ -69,6 +76,12 @@ __export(index_exports, {
69
76
  disconnect: () => disconnect,
70
77
  findApiKeyById: () => findApiKeyById,
71
78
  findApiKeysByPrefix: () => findApiKeysByPrefix,
79
+ findBlogPostById: () => findBlogPostById,
80
+ findBlogPostBySlug: () => findBlogPostBySlug,
81
+ findBlogPosts: () => findBlogPosts,
82
+ findBlogTagById: () => findBlogTagById,
83
+ findBlogTagBySlug: () => findBlogTagBySlug,
84
+ findBlogTags: () => findBlogTags,
72
85
  findEntries: () => findEntries,
73
86
  findEntryById: () => findEntryById,
74
87
  findEntryByMatchAndPlayer: () => findEntryByMatchAndPlayer,
@@ -85,6 +98,7 @@ __export(index_exports, {
85
98
  findPlayerByPlayerNumber: () => findPlayerByPlayerNumber,
86
99
  findPlayerByUserEmail: () => findPlayerByUserEmail,
87
100
  findPlayers: () => findPlayers,
101
+ findPublishedBlogPosts: () => findPublishedBlogPosts,
88
102
  findRoundById: () => findRoundById,
89
103
  findRoundByTournamentAndNumber: () => findRoundByTournamentAndNumber,
90
104
  findRounds: () => findRounds,
@@ -98,6 +112,8 @@ __export(index_exports, {
98
112
  findUserById: () => findUserById,
99
113
  findUsers: () => findUsers,
100
114
  generateUniquePlayerNumber: () => generateUniquePlayerNumber,
115
+ getBlogTagWithPostCount: () => getBlogTagWithPostCount,
116
+ getBlogTagsWithPostCounts: () => getBlogTagsWithPostCounts,
101
117
  getFinalsRounds: () => getFinalsRounds,
102
118
  getFinalsStandings: () => getFinalsStandings,
103
119
  getLatestOpprRankingHistory: () => getLatestOpprRankingHistory,
@@ -140,11 +156,15 @@ __export(index_exports, {
140
156
  linkPlayerToUser: () => linkPlayerToUser,
141
157
  prisma: () => prisma,
142
158
  recalculateTimeDecay: () => recalculateTimeDecay,
159
+ searchBlogPosts: () => searchBlogPosts,
160
+ searchBlogTags: () => searchBlogTags,
143
161
  searchLocations: () => searchLocations,
144
162
  searchPlayers: () => searchPlayers,
145
163
  searchTournaments: () => searchTournaments,
146
164
  testConnection: () => testConnection,
147
165
  updateApiKeyLastUsed: () => updateApiKeyLastUsed,
166
+ updateBlogPost: () => updateBlogPost,
167
+ updateBlogTag: () => updateBlogTag,
148
168
  updateEntry: () => updateEntry,
149
169
  updateLocation: () => updateLocation,
150
170
  updateMatch: () => updateMatch,
@@ -1474,23 +1494,207 @@ async function getLocationWithTournaments(id) {
1474
1494
  }
1475
1495
  });
1476
1496
  }
1497
+
1498
+ // src/blog-posts.ts
1499
+ var defaultInclude = {
1500
+ author: {
1501
+ select: { id: true, email: true }
1502
+ },
1503
+ tags: {
1504
+ select: { id: true, name: true, slug: true }
1505
+ }
1506
+ };
1507
+ async function createBlogPost(data) {
1508
+ const { tagIds, ...postData } = data;
1509
+ return prisma.blogPost.create({
1510
+ data: {
1511
+ ...postData,
1512
+ tags: tagIds?.length ? { connect: tagIds.map((id) => ({ id })) } : void 0
1513
+ },
1514
+ include: defaultInclude
1515
+ });
1516
+ }
1517
+ async function findBlogPostById(id) {
1518
+ return prisma.blogPost.findUnique({
1519
+ where: { id },
1520
+ include: defaultInclude
1521
+ });
1522
+ }
1523
+ async function findBlogPostBySlug(slug) {
1524
+ return prisma.blogPost.findUnique({
1525
+ where: { slug },
1526
+ include: defaultInclude
1527
+ });
1528
+ }
1529
+ async function findBlogPosts(options = {}) {
1530
+ return prisma.blogPost.findMany({
1531
+ take: options.take,
1532
+ skip: options.skip,
1533
+ where: options.where,
1534
+ orderBy: options.orderBy ?? { createdAt: "desc" },
1535
+ include: options.include ?? defaultInclude
1536
+ });
1537
+ }
1538
+ async function findPublishedBlogPosts(options = {}) {
1539
+ const { tagSlug, ...restOptions } = options;
1540
+ const where = {
1541
+ status: "PUBLISHED",
1542
+ publishedAt: { not: null },
1543
+ ...tagSlug && {
1544
+ tags: {
1545
+ some: { slug: tagSlug }
1546
+ }
1547
+ }
1548
+ };
1549
+ return findBlogPosts({
1550
+ ...restOptions,
1551
+ where,
1552
+ orderBy: options.orderBy ?? { publishedAt: "desc" }
1553
+ });
1554
+ }
1555
+ async function searchBlogPosts(query, limit = 20, publishedOnly = true) {
1556
+ const where = {
1557
+ OR: [
1558
+ { title: { contains: query, mode: "insensitive" } },
1559
+ { excerpt: { contains: query, mode: "insensitive" } }
1560
+ ],
1561
+ ...publishedOnly && {
1562
+ status: "PUBLISHED",
1563
+ publishedAt: { not: null }
1564
+ }
1565
+ };
1566
+ return findBlogPosts({
1567
+ take: limit,
1568
+ where,
1569
+ orderBy: { publishedAt: "desc" }
1570
+ });
1571
+ }
1572
+ async function updateBlogPost(id, data) {
1573
+ const { tagIds, ...postData } = data;
1574
+ return prisma.blogPost.update({
1575
+ where: { id },
1576
+ data: {
1577
+ ...postData,
1578
+ // If tagIds is provided, replace all tags
1579
+ ...tagIds !== void 0 && {
1580
+ tags: {
1581
+ set: tagIds.map((tagId) => ({ id: tagId }))
1582
+ }
1583
+ }
1584
+ },
1585
+ include: defaultInclude
1586
+ });
1587
+ }
1588
+ async function deleteBlogPost(id) {
1589
+ return prisma.blogPost.delete({
1590
+ where: { id }
1591
+ });
1592
+ }
1593
+ async function countBlogPosts(where) {
1594
+ return prisma.blogPost.count({ where });
1595
+ }
1596
+ async function countPublishedBlogPosts(tagSlug) {
1597
+ return countBlogPosts({
1598
+ status: "PUBLISHED",
1599
+ publishedAt: { not: null },
1600
+ ...tagSlug && {
1601
+ tags: {
1602
+ some: { slug: tagSlug }
1603
+ }
1604
+ }
1605
+ });
1606
+ }
1607
+
1608
+ // src/blog-tags.ts
1609
+ async function createBlogTag(data) {
1610
+ return prisma.blogTag.create({
1611
+ data
1612
+ });
1613
+ }
1614
+ async function findBlogTagById(id) {
1615
+ return prisma.blogTag.findUnique({
1616
+ where: { id }
1617
+ });
1618
+ }
1619
+ async function findBlogTagBySlug(slug) {
1620
+ return prisma.blogTag.findUnique({
1621
+ where: { slug }
1622
+ });
1623
+ }
1624
+ async function findBlogTags(options = {}) {
1625
+ return prisma.blogTag.findMany({
1626
+ take: options.take,
1627
+ skip: options.skip,
1628
+ where: options.where,
1629
+ orderBy: options.orderBy ?? { name: "asc" },
1630
+ include: options.include
1631
+ });
1632
+ }
1633
+ async function searchBlogTags(query, limit = 20) {
1634
+ return findBlogTags({
1635
+ take: limit,
1636
+ where: {
1637
+ name: { contains: query, mode: "insensitive" }
1638
+ },
1639
+ orderBy: { name: "asc" }
1640
+ });
1641
+ }
1642
+ async function updateBlogTag(id, data) {
1643
+ return prisma.blogTag.update({
1644
+ where: { id },
1645
+ data
1646
+ });
1647
+ }
1648
+ async function deleteBlogTag(id) {
1649
+ return prisma.blogTag.delete({
1650
+ where: { id }
1651
+ });
1652
+ }
1653
+ async function countBlogTags(where) {
1654
+ return prisma.blogTag.count({ where });
1655
+ }
1656
+ async function getBlogTagWithPostCount(id) {
1657
+ return prisma.blogTag.findUnique({
1658
+ where: { id },
1659
+ include: {
1660
+ _count: {
1661
+ select: { posts: true }
1662
+ }
1663
+ }
1664
+ });
1665
+ }
1666
+ async function getBlogTagsWithPostCounts() {
1667
+ return prisma.blogTag.findMany({
1668
+ include: {
1669
+ _count: {
1670
+ select: { posts: true }
1671
+ }
1672
+ },
1673
+ orderBy: { name: "asc" }
1674
+ });
1675
+ }
1477
1676
  // Annotate the CommonJS export names for ESM import in node:
1478
1677
  0 && (module.exports = {
1479
1678
  MAX_API_KEYS_PER_USER,
1480
1679
  applyRDDecayForInactivePlayers,
1481
1680
  connect,
1681
+ countBlogPosts,
1682
+ countBlogTags,
1482
1683
  countEntries,
1483
1684
  countLocations,
1484
1685
  countMatches,
1485
1686
  countOpprPlayerRankings,
1486
1687
  countOpprRankingHistory,
1487
1688
  countPlayers,
1689
+ countPublishedBlogPosts,
1488
1690
  countRounds,
1489
1691
  countStandings,
1490
1692
  countTournaments,
1491
1693
  countUserApiKeys,
1492
1694
  countUsers,
1493
1695
  createApiKey,
1696
+ createBlogPost,
1697
+ createBlogTag,
1494
1698
  createEntry,
1495
1699
  createLocation,
1496
1700
  createManyEntries,
@@ -1507,6 +1711,8 @@ async function getLocationWithTournaments(id) {
1507
1711
  createUser,
1508
1712
  createUserWithPlayer,
1509
1713
  deleteApiKey,
1714
+ deleteBlogPost,
1715
+ deleteBlogTag,
1510
1716
  deleteEntriesByMatch,
1511
1717
  deleteEntry,
1512
1718
  deleteLocation,
@@ -1525,6 +1731,12 @@ async function getLocationWithTournaments(id) {
1525
1731
  disconnect,
1526
1732
  findApiKeyById,
1527
1733
  findApiKeysByPrefix,
1734
+ findBlogPostById,
1735
+ findBlogPostBySlug,
1736
+ findBlogPosts,
1737
+ findBlogTagById,
1738
+ findBlogTagBySlug,
1739
+ findBlogTags,
1528
1740
  findEntries,
1529
1741
  findEntryById,
1530
1742
  findEntryByMatchAndPlayer,
@@ -1541,6 +1753,7 @@ async function getLocationWithTournaments(id) {
1541
1753
  findPlayerByPlayerNumber,
1542
1754
  findPlayerByUserEmail,
1543
1755
  findPlayers,
1756
+ findPublishedBlogPosts,
1544
1757
  findRoundById,
1545
1758
  findRoundByTournamentAndNumber,
1546
1759
  findRounds,
@@ -1554,6 +1767,8 @@ async function getLocationWithTournaments(id) {
1554
1767
  findUserById,
1555
1768
  findUsers,
1556
1769
  generateUniquePlayerNumber,
1770
+ getBlogTagWithPostCount,
1771
+ getBlogTagsWithPostCounts,
1557
1772
  getFinalsRounds,
1558
1773
  getFinalsStandings,
1559
1774
  getLatestOpprRankingHistory,
@@ -1596,11 +1811,15 @@ async function getLocationWithTournaments(id) {
1596
1811
  linkPlayerToUser,
1597
1812
  prisma,
1598
1813
  recalculateTimeDecay,
1814
+ searchBlogPosts,
1815
+ searchBlogTags,
1599
1816
  searchLocations,
1600
1817
  searchPlayers,
1601
1818
  searchTournaments,
1602
1819
  testConnection,
1603
1820
  updateApiKeyLastUsed,
1821
+ updateBlogPost,
1822
+ updateBlogTag,
1604
1823
  updateEntry,
1605
1824
  updateLocation,
1606
1825
  updateMatch,
package/dist/index.d.cts CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as _prisma_client_runtime_library from '@prisma/client/runtime/library';
2
2
  import * as _prisma_client from '@prisma/client';
3
- import { PrismaClient, Player, Prisma, OpprPlayerRanking, OpprRankingChangeType, OpprRankingHistory, EventBoosterType, Tournament, Round, Match, MatchResult, Entry, Standing, User, ApiKey, Location } from '@prisma/client';
3
+ import { PrismaClient, Player, Prisma, OpprPlayerRanking, OpprRankingChangeType, OpprRankingHistory, EventBoosterType, Tournament, Round, Match, MatchResult, Entry, Standing, User, ApiKey, Location, PostStatus, BlogPost, BlogTag } from '@prisma/client';
4
4
  export { Entry, EventBoosterType, Location, Match, MatchResult, OpprPlayerRanking, OpprRankingChangeType, OpprRankingHistory, Player, Prisma, Role, Round, Standing, Tournament, User } from '@prisma/client';
5
5
 
6
6
  declare const prisma: PrismaClient<_prisma_client.Prisma.PrismaClientOptions, never, _prisma_client_runtime_library.DefaultArgs>;
@@ -1351,6 +1351,201 @@ declare function getLocationWithTournaments(id: string): Promise<({
1351
1351
  country: string | null;
1352
1352
  }) | null>;
1353
1353
 
1354
+ /**
1355
+ * BlogPost with author and tags included
1356
+ */
1357
+ type BlogPostWithRelations = BlogPost & {
1358
+ author: {
1359
+ id: string;
1360
+ email: string;
1361
+ };
1362
+ tags: {
1363
+ id: string;
1364
+ name: string;
1365
+ slug: string;
1366
+ }[];
1367
+ };
1368
+ /**
1369
+ * Input for creating a new blog post
1370
+ */
1371
+ interface CreateBlogPostInput {
1372
+ title: string;
1373
+ slug: string;
1374
+ content: string;
1375
+ excerpt?: string;
1376
+ status?: PostStatus;
1377
+ publishedAt?: Date;
1378
+ featuredImageUrl?: string;
1379
+ featuredImageAlt?: string;
1380
+ metaTitle?: string;
1381
+ metaDescription?: string;
1382
+ ogTitle?: string;
1383
+ ogDescription?: string;
1384
+ ogImageUrl?: string;
1385
+ authorId: string;
1386
+ tagIds?: string[];
1387
+ }
1388
+ /**
1389
+ * Input for updating a blog post
1390
+ */
1391
+ interface UpdateBlogPostInput {
1392
+ title?: string;
1393
+ slug?: string;
1394
+ content?: string;
1395
+ excerpt?: string | null;
1396
+ status?: PostStatus;
1397
+ publishedAt?: Date | null;
1398
+ featuredImageUrl?: string | null;
1399
+ featuredImageAlt?: string | null;
1400
+ metaTitle?: string | null;
1401
+ metaDescription?: string | null;
1402
+ ogTitle?: string | null;
1403
+ ogDescription?: string | null;
1404
+ ogImageUrl?: string | null;
1405
+ tagIds?: string[];
1406
+ }
1407
+ /**
1408
+ * Options for querying blog posts
1409
+ */
1410
+ interface FindBlogPostsOptions {
1411
+ take?: number;
1412
+ skip?: number;
1413
+ orderBy?: Prisma.BlogPostOrderByWithRelationInput;
1414
+ where?: Prisma.BlogPostWhereInput;
1415
+ include?: Prisma.BlogPostInclude;
1416
+ }
1417
+ /**
1418
+ * Creates a new blog post
1419
+ */
1420
+ declare function createBlogPost(data: CreateBlogPostInput): Promise<BlogPostWithRelations>;
1421
+ /**
1422
+ * Finds a blog post by ID
1423
+ */
1424
+ declare function findBlogPostById(id: string): Promise<BlogPostWithRelations | null>;
1425
+ /**
1426
+ * Finds a blog post by slug
1427
+ */
1428
+ declare function findBlogPostBySlug(slug: string): Promise<BlogPostWithRelations | null>;
1429
+ /**
1430
+ * Finds multiple blog posts with optional filters
1431
+ */
1432
+ declare function findBlogPosts(options?: FindBlogPostsOptions): Promise<BlogPostWithRelations[]>;
1433
+ /**
1434
+ * Finds only published blog posts (for public access)
1435
+ */
1436
+ declare function findPublishedBlogPosts(options?: Omit<FindBlogPostsOptions, 'where'> & {
1437
+ tagSlug?: string;
1438
+ }): Promise<BlogPostWithRelations[]>;
1439
+ /**
1440
+ * Searches blog posts by title or content
1441
+ */
1442
+ declare function searchBlogPosts(query: string, limit?: number, publishedOnly?: boolean): Promise<BlogPostWithRelations[]>;
1443
+ /**
1444
+ * Updates a blog post
1445
+ */
1446
+ declare function updateBlogPost(id: string, data: UpdateBlogPostInput): Promise<BlogPostWithRelations>;
1447
+ /**
1448
+ * Deletes a blog post
1449
+ */
1450
+ declare function deleteBlogPost(id: string): Promise<BlogPost>;
1451
+ /**
1452
+ * Counts total blog posts
1453
+ */
1454
+ declare function countBlogPosts(where?: Prisma.BlogPostWhereInput): Promise<number>;
1455
+ /**
1456
+ * Counts published blog posts (for public access)
1457
+ */
1458
+ declare function countPublishedBlogPosts(tagSlug?: string): Promise<number>;
1459
+
1460
+ /**
1461
+ * Input for creating a new blog tag
1462
+ */
1463
+ interface CreateBlogTagInput {
1464
+ name: string;
1465
+ slug: string;
1466
+ description?: string;
1467
+ }
1468
+ /**
1469
+ * Input for updating a blog tag
1470
+ */
1471
+ interface UpdateBlogTagInput {
1472
+ name?: string;
1473
+ slug?: string;
1474
+ description?: string | null;
1475
+ }
1476
+ /**
1477
+ * Options for querying blog tags
1478
+ */
1479
+ interface FindBlogTagsOptions {
1480
+ take?: number;
1481
+ skip?: number;
1482
+ orderBy?: Prisma.BlogTagOrderByWithRelationInput;
1483
+ where?: Prisma.BlogTagWhereInput;
1484
+ include?: Prisma.BlogTagInclude;
1485
+ }
1486
+ /**
1487
+ * Creates a new blog tag
1488
+ */
1489
+ declare function createBlogTag(data: CreateBlogTagInput): Promise<BlogTag>;
1490
+ /**
1491
+ * Finds a blog tag by ID
1492
+ */
1493
+ declare function findBlogTagById(id: string): Promise<BlogTag | null>;
1494
+ /**
1495
+ * Finds a blog tag by slug
1496
+ */
1497
+ declare function findBlogTagBySlug(slug: string): Promise<BlogTag | null>;
1498
+ /**
1499
+ * Finds multiple blog tags with optional filters
1500
+ */
1501
+ declare function findBlogTags(options?: FindBlogTagsOptions): Promise<BlogTag[]>;
1502
+ /**
1503
+ * Searches blog tags by name
1504
+ */
1505
+ declare function searchBlogTags(query: string, limit?: number): Promise<BlogTag[]>;
1506
+ /**
1507
+ * Updates a blog tag
1508
+ */
1509
+ declare function updateBlogTag(id: string, data: UpdateBlogTagInput): Promise<BlogTag>;
1510
+ /**
1511
+ * Deletes a blog tag
1512
+ */
1513
+ declare function deleteBlogTag(id: string): Promise<BlogTag>;
1514
+ /**
1515
+ * Counts total blog tags
1516
+ */
1517
+ declare function countBlogTags(where?: Prisma.BlogTagWhereInput): Promise<number>;
1518
+ /**
1519
+ * Gets blog tag with post count
1520
+ */
1521
+ declare function getBlogTagWithPostCount(id: string): Promise<({
1522
+ _count: {
1523
+ posts: number;
1524
+ };
1525
+ } & {
1526
+ name: string;
1527
+ id: string;
1528
+ createdAt: Date;
1529
+ updatedAt: Date;
1530
+ description: string | null;
1531
+ slug: string;
1532
+ }) | null>;
1533
+ /**
1534
+ * Gets all blog tags with post counts
1535
+ */
1536
+ declare function getBlogTagsWithPostCounts(): Promise<({
1537
+ _count: {
1538
+ posts: number;
1539
+ };
1540
+ } & {
1541
+ name: string;
1542
+ id: string;
1543
+ createdAt: Date;
1544
+ updatedAt: Date;
1545
+ description: string | null;
1546
+ slug: string;
1547
+ })[]>;
1548
+
1354
1549
  /**
1355
1550
  * Re-export Prisma generated types
1356
1551
  */
@@ -1411,4 +1606,4 @@ interface ConnectionStatus {
1411
1606
  error?: string;
1412
1607
  }
1413
1608
 
1414
- export { type ApiKeyInfo, type ApiKeyWithUser, type ConnectionStatus, type CreateApiKeyInput, type CreateEntryInput, type CreateLocationInput, type CreateMatchInput, type CreateOpprPlayerRankingInput, type CreateOpprRankingHistoryInput, type CreatePlayerInput, type CreateRoundInput, type CreateStandingInput, type CreateTournamentInput, type CreateUserInput, type FindEntriesOptions, type FindLocationsOptions, type FindMatchesOptions, type FindOpprPlayerRankingsOptions, type FindPlayersOptions, type FindRoundsOptions, type FindStandingsOptions, type FindTournamentsOptions, MAX_API_KEYS_PER_USER, type MergedStanding, type PlayerStatistics, type PlayerWithResults, type StandingWithTournament, type TournamentStatistics, type UpdateEntryInput, type UpdateLocationInput, type UpdateMatchInput, type UpdateOpprPlayerRankingInput, type UpdatePlayerInput, type UpdateRoundInput, type UpdateStandingInput, type UpdateTournamentInput, type UpdateUserInput, type UserWithPlayer, applyRDDecayForInactivePlayers, connect, countEntries, countLocations, countMatches, countOpprPlayerRankings, countOpprRankingHistory, countPlayers, countRounds, countStandings, countTournaments, countUserApiKeys, countUsers, createApiKey, createEntry, createLocation, createManyEntries, createManyMatches, createManyRounds, createManyStandings, createMatch, createOpprPlayerRanking, createOpprRankingHistory, createPlayer, createRound, createStanding, createTournament, createUser, createUserWithPlayer, deleteApiKey, deleteEntriesByMatch, deleteEntry, deleteLocation, deleteMatch, deleteMatchesByRound, deleteMatchesByTournament, deleteOpprPlayerRanking, deletePlayer, deleteRound, deleteRoundsByTournament, deleteStanding, deleteStandingsByTournament, deleteTournament, deleteUser, deleteUserApiKey, disconnect, findApiKeyById, findApiKeysByPrefix, findEntries, findEntryById, findEntryByMatchAndPlayer, findLocationByExternalId, findLocationById, findLocations, findMatchById, findMatches, findOpprPlayerRankingById, findOpprPlayerRankingByPlayerId, findOpprPlayerRankings, findPlayerByExternalId, findPlayerById, findPlayerByPlayerNumber, findPlayerByUserEmail, findPlayers, findRoundById, findRoundByTournamentAndNumber, findRounds, findStandingById, findStandingByPlayerAndTournament, findStandings, findTournamentByExternalId, findTournamentById, findTournaments, findUserByEmail, findUserById, findUsers, generateUniquePlayerNumber, getFinalsRounds, getFinalsStandings, getLatestOpprRankingHistory, getLocationWithTournaments, getMajorTournaments, getMatchEntries, getMatchWithEntries, getMergedStandings, getOpprRankingHistory, getOpprRankingHistoryByDateRange, getOrCreateOpprPlayerRanking, getPlayerEntries, getPlayerEntryStats, getPlayerStandings, getPlayerStats, getPlayerTopFinishes, getPlayerTournamentEntries, getPlayerTournamentMatches, getPlayerWithResults, getQualifyingRounds, getQualifyingStandings, getRatedOpprPlayers, getRecentTournaments, getRoundMatches, getRoundWithMatches, getTopPlayersByOpprRanking, getTopPlayersByOpprRating, getTournamentMatches, getTournamentRounds, getTournamentStandings, getTournamentStats, getTournamentWithMatches, getTournamentWithResults, getTournamentsByBoosterType, getTournamentsByDateRange, getUserApiKeys, getUserByEmailWithPlayer, getUserWithPlayer, isValidPlayerNumber, linkPlayerToUser, prisma, recalculateTimeDecay, searchLocations, searchPlayers, searchTournaments, testConnection, updateApiKeyLastUsed, updateEntry, updateLocation, updateMatch, updateOpprPlayerRanking, updateOpprRatingAfterTournament, updatePlayer, updateRound, updateStanding, updateStandingPoints, updateTournament, updateUser, updateUserRefreshToken, updateWorldRankings };
1609
+ export { type ApiKeyInfo, type ApiKeyWithUser, type BlogPostWithRelations, type ConnectionStatus, type CreateApiKeyInput, type CreateBlogPostInput, type CreateBlogTagInput, type CreateEntryInput, type CreateLocationInput, type CreateMatchInput, type CreateOpprPlayerRankingInput, type CreateOpprRankingHistoryInput, type CreatePlayerInput, type CreateRoundInput, type CreateStandingInput, type CreateTournamentInput, type CreateUserInput, type FindBlogPostsOptions, type FindBlogTagsOptions, type FindEntriesOptions, type FindLocationsOptions, type FindMatchesOptions, type FindOpprPlayerRankingsOptions, type FindPlayersOptions, type FindRoundsOptions, type FindStandingsOptions, type FindTournamentsOptions, MAX_API_KEYS_PER_USER, type MergedStanding, type PlayerStatistics, type PlayerWithResults, type StandingWithTournament, type TournamentStatistics, type UpdateBlogPostInput, type UpdateBlogTagInput, type UpdateEntryInput, type UpdateLocationInput, type UpdateMatchInput, type UpdateOpprPlayerRankingInput, type UpdatePlayerInput, type UpdateRoundInput, type UpdateStandingInput, type UpdateTournamentInput, type UpdateUserInput, type UserWithPlayer, applyRDDecayForInactivePlayers, connect, countBlogPosts, countBlogTags, countEntries, countLocations, countMatches, countOpprPlayerRankings, countOpprRankingHistory, countPlayers, countPublishedBlogPosts, countRounds, countStandings, countTournaments, countUserApiKeys, countUsers, createApiKey, createBlogPost, createBlogTag, createEntry, createLocation, createManyEntries, createManyMatches, createManyRounds, createManyStandings, createMatch, createOpprPlayerRanking, createOpprRankingHistory, createPlayer, createRound, createStanding, createTournament, createUser, createUserWithPlayer, deleteApiKey, deleteBlogPost, deleteBlogTag, deleteEntriesByMatch, deleteEntry, deleteLocation, deleteMatch, deleteMatchesByRound, deleteMatchesByTournament, deleteOpprPlayerRanking, deletePlayer, deleteRound, deleteRoundsByTournament, deleteStanding, deleteStandingsByTournament, deleteTournament, deleteUser, deleteUserApiKey, disconnect, findApiKeyById, findApiKeysByPrefix, findBlogPostById, findBlogPostBySlug, findBlogPosts, findBlogTagById, findBlogTagBySlug, findBlogTags, findEntries, findEntryById, findEntryByMatchAndPlayer, findLocationByExternalId, findLocationById, findLocations, findMatchById, findMatches, findOpprPlayerRankingById, findOpprPlayerRankingByPlayerId, findOpprPlayerRankings, findPlayerByExternalId, findPlayerById, findPlayerByPlayerNumber, findPlayerByUserEmail, findPlayers, findPublishedBlogPosts, findRoundById, findRoundByTournamentAndNumber, findRounds, findStandingById, findStandingByPlayerAndTournament, findStandings, findTournamentByExternalId, findTournamentById, findTournaments, findUserByEmail, findUserById, findUsers, generateUniquePlayerNumber, getBlogTagWithPostCount, getBlogTagsWithPostCounts, getFinalsRounds, getFinalsStandings, getLatestOpprRankingHistory, getLocationWithTournaments, getMajorTournaments, getMatchEntries, getMatchWithEntries, getMergedStandings, getOpprRankingHistory, getOpprRankingHistoryByDateRange, getOrCreateOpprPlayerRanking, getPlayerEntries, getPlayerEntryStats, getPlayerStandings, getPlayerStats, getPlayerTopFinishes, getPlayerTournamentEntries, getPlayerTournamentMatches, getPlayerWithResults, getQualifyingRounds, getQualifyingStandings, getRatedOpprPlayers, getRecentTournaments, getRoundMatches, getRoundWithMatches, getTopPlayersByOpprRanking, getTopPlayersByOpprRating, getTournamentMatches, getTournamentRounds, getTournamentStandings, getTournamentStats, getTournamentWithMatches, getTournamentWithResults, getTournamentsByBoosterType, getTournamentsByDateRange, getUserApiKeys, getUserByEmailWithPlayer, getUserWithPlayer, isValidPlayerNumber, linkPlayerToUser, prisma, recalculateTimeDecay, searchBlogPosts, searchBlogTags, searchLocations, searchPlayers, searchTournaments, testConnection, updateApiKeyLastUsed, updateBlogPost, updateBlogTag, updateEntry, updateLocation, updateMatch, updateOpprPlayerRanking, updateOpprRatingAfterTournament, updatePlayer, updateRound, updateStanding, updateStandingPoints, updateTournament, updateUser, updateUserRefreshToken, updateWorldRankings };
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as _prisma_client_runtime_library from '@prisma/client/runtime/library';
2
2
  import * as _prisma_client from '@prisma/client';
3
- import { PrismaClient, Player, Prisma, OpprPlayerRanking, OpprRankingChangeType, OpprRankingHistory, EventBoosterType, Tournament, Round, Match, MatchResult, Entry, Standing, User, ApiKey, Location } from '@prisma/client';
3
+ import { PrismaClient, Player, Prisma, OpprPlayerRanking, OpprRankingChangeType, OpprRankingHistory, EventBoosterType, Tournament, Round, Match, MatchResult, Entry, Standing, User, ApiKey, Location, PostStatus, BlogPost, BlogTag } from '@prisma/client';
4
4
  export { Entry, EventBoosterType, Location, Match, MatchResult, OpprPlayerRanking, OpprRankingChangeType, OpprRankingHistory, Player, Prisma, Role, Round, Standing, Tournament, User } from '@prisma/client';
5
5
 
6
6
  declare const prisma: PrismaClient<_prisma_client.Prisma.PrismaClientOptions, never, _prisma_client_runtime_library.DefaultArgs>;
@@ -1351,6 +1351,201 @@ declare function getLocationWithTournaments(id: string): Promise<({
1351
1351
  country: string | null;
1352
1352
  }) | null>;
1353
1353
 
1354
+ /**
1355
+ * BlogPost with author and tags included
1356
+ */
1357
+ type BlogPostWithRelations = BlogPost & {
1358
+ author: {
1359
+ id: string;
1360
+ email: string;
1361
+ };
1362
+ tags: {
1363
+ id: string;
1364
+ name: string;
1365
+ slug: string;
1366
+ }[];
1367
+ };
1368
+ /**
1369
+ * Input for creating a new blog post
1370
+ */
1371
+ interface CreateBlogPostInput {
1372
+ title: string;
1373
+ slug: string;
1374
+ content: string;
1375
+ excerpt?: string;
1376
+ status?: PostStatus;
1377
+ publishedAt?: Date;
1378
+ featuredImageUrl?: string;
1379
+ featuredImageAlt?: string;
1380
+ metaTitle?: string;
1381
+ metaDescription?: string;
1382
+ ogTitle?: string;
1383
+ ogDescription?: string;
1384
+ ogImageUrl?: string;
1385
+ authorId: string;
1386
+ tagIds?: string[];
1387
+ }
1388
+ /**
1389
+ * Input for updating a blog post
1390
+ */
1391
+ interface UpdateBlogPostInput {
1392
+ title?: string;
1393
+ slug?: string;
1394
+ content?: string;
1395
+ excerpt?: string | null;
1396
+ status?: PostStatus;
1397
+ publishedAt?: Date | null;
1398
+ featuredImageUrl?: string | null;
1399
+ featuredImageAlt?: string | null;
1400
+ metaTitle?: string | null;
1401
+ metaDescription?: string | null;
1402
+ ogTitle?: string | null;
1403
+ ogDescription?: string | null;
1404
+ ogImageUrl?: string | null;
1405
+ tagIds?: string[];
1406
+ }
1407
+ /**
1408
+ * Options for querying blog posts
1409
+ */
1410
+ interface FindBlogPostsOptions {
1411
+ take?: number;
1412
+ skip?: number;
1413
+ orderBy?: Prisma.BlogPostOrderByWithRelationInput;
1414
+ where?: Prisma.BlogPostWhereInput;
1415
+ include?: Prisma.BlogPostInclude;
1416
+ }
1417
+ /**
1418
+ * Creates a new blog post
1419
+ */
1420
+ declare function createBlogPost(data: CreateBlogPostInput): Promise<BlogPostWithRelations>;
1421
+ /**
1422
+ * Finds a blog post by ID
1423
+ */
1424
+ declare function findBlogPostById(id: string): Promise<BlogPostWithRelations | null>;
1425
+ /**
1426
+ * Finds a blog post by slug
1427
+ */
1428
+ declare function findBlogPostBySlug(slug: string): Promise<BlogPostWithRelations | null>;
1429
+ /**
1430
+ * Finds multiple blog posts with optional filters
1431
+ */
1432
+ declare function findBlogPosts(options?: FindBlogPostsOptions): Promise<BlogPostWithRelations[]>;
1433
+ /**
1434
+ * Finds only published blog posts (for public access)
1435
+ */
1436
+ declare function findPublishedBlogPosts(options?: Omit<FindBlogPostsOptions, 'where'> & {
1437
+ tagSlug?: string;
1438
+ }): Promise<BlogPostWithRelations[]>;
1439
+ /**
1440
+ * Searches blog posts by title or content
1441
+ */
1442
+ declare function searchBlogPosts(query: string, limit?: number, publishedOnly?: boolean): Promise<BlogPostWithRelations[]>;
1443
+ /**
1444
+ * Updates a blog post
1445
+ */
1446
+ declare function updateBlogPost(id: string, data: UpdateBlogPostInput): Promise<BlogPostWithRelations>;
1447
+ /**
1448
+ * Deletes a blog post
1449
+ */
1450
+ declare function deleteBlogPost(id: string): Promise<BlogPost>;
1451
+ /**
1452
+ * Counts total blog posts
1453
+ */
1454
+ declare function countBlogPosts(where?: Prisma.BlogPostWhereInput): Promise<number>;
1455
+ /**
1456
+ * Counts published blog posts (for public access)
1457
+ */
1458
+ declare function countPublishedBlogPosts(tagSlug?: string): Promise<number>;
1459
+
1460
+ /**
1461
+ * Input for creating a new blog tag
1462
+ */
1463
+ interface CreateBlogTagInput {
1464
+ name: string;
1465
+ slug: string;
1466
+ description?: string;
1467
+ }
1468
+ /**
1469
+ * Input for updating a blog tag
1470
+ */
1471
+ interface UpdateBlogTagInput {
1472
+ name?: string;
1473
+ slug?: string;
1474
+ description?: string | null;
1475
+ }
1476
+ /**
1477
+ * Options for querying blog tags
1478
+ */
1479
+ interface FindBlogTagsOptions {
1480
+ take?: number;
1481
+ skip?: number;
1482
+ orderBy?: Prisma.BlogTagOrderByWithRelationInput;
1483
+ where?: Prisma.BlogTagWhereInput;
1484
+ include?: Prisma.BlogTagInclude;
1485
+ }
1486
+ /**
1487
+ * Creates a new blog tag
1488
+ */
1489
+ declare function createBlogTag(data: CreateBlogTagInput): Promise<BlogTag>;
1490
+ /**
1491
+ * Finds a blog tag by ID
1492
+ */
1493
+ declare function findBlogTagById(id: string): Promise<BlogTag | null>;
1494
+ /**
1495
+ * Finds a blog tag by slug
1496
+ */
1497
+ declare function findBlogTagBySlug(slug: string): Promise<BlogTag | null>;
1498
+ /**
1499
+ * Finds multiple blog tags with optional filters
1500
+ */
1501
+ declare function findBlogTags(options?: FindBlogTagsOptions): Promise<BlogTag[]>;
1502
+ /**
1503
+ * Searches blog tags by name
1504
+ */
1505
+ declare function searchBlogTags(query: string, limit?: number): Promise<BlogTag[]>;
1506
+ /**
1507
+ * Updates a blog tag
1508
+ */
1509
+ declare function updateBlogTag(id: string, data: UpdateBlogTagInput): Promise<BlogTag>;
1510
+ /**
1511
+ * Deletes a blog tag
1512
+ */
1513
+ declare function deleteBlogTag(id: string): Promise<BlogTag>;
1514
+ /**
1515
+ * Counts total blog tags
1516
+ */
1517
+ declare function countBlogTags(where?: Prisma.BlogTagWhereInput): Promise<number>;
1518
+ /**
1519
+ * Gets blog tag with post count
1520
+ */
1521
+ declare function getBlogTagWithPostCount(id: string): Promise<({
1522
+ _count: {
1523
+ posts: number;
1524
+ };
1525
+ } & {
1526
+ name: string;
1527
+ id: string;
1528
+ createdAt: Date;
1529
+ updatedAt: Date;
1530
+ description: string | null;
1531
+ slug: string;
1532
+ }) | null>;
1533
+ /**
1534
+ * Gets all blog tags with post counts
1535
+ */
1536
+ declare function getBlogTagsWithPostCounts(): Promise<({
1537
+ _count: {
1538
+ posts: number;
1539
+ };
1540
+ } & {
1541
+ name: string;
1542
+ id: string;
1543
+ createdAt: Date;
1544
+ updatedAt: Date;
1545
+ description: string | null;
1546
+ slug: string;
1547
+ })[]>;
1548
+
1354
1549
  /**
1355
1550
  * Re-export Prisma generated types
1356
1551
  */
@@ -1411,4 +1606,4 @@ interface ConnectionStatus {
1411
1606
  error?: string;
1412
1607
  }
1413
1608
 
1414
- export { type ApiKeyInfo, type ApiKeyWithUser, type ConnectionStatus, type CreateApiKeyInput, type CreateEntryInput, type CreateLocationInput, type CreateMatchInput, type CreateOpprPlayerRankingInput, type CreateOpprRankingHistoryInput, type CreatePlayerInput, type CreateRoundInput, type CreateStandingInput, type CreateTournamentInput, type CreateUserInput, type FindEntriesOptions, type FindLocationsOptions, type FindMatchesOptions, type FindOpprPlayerRankingsOptions, type FindPlayersOptions, type FindRoundsOptions, type FindStandingsOptions, type FindTournamentsOptions, MAX_API_KEYS_PER_USER, type MergedStanding, type PlayerStatistics, type PlayerWithResults, type StandingWithTournament, type TournamentStatistics, type UpdateEntryInput, type UpdateLocationInput, type UpdateMatchInput, type UpdateOpprPlayerRankingInput, type UpdatePlayerInput, type UpdateRoundInput, type UpdateStandingInput, type UpdateTournamentInput, type UpdateUserInput, type UserWithPlayer, applyRDDecayForInactivePlayers, connect, countEntries, countLocations, countMatches, countOpprPlayerRankings, countOpprRankingHistory, countPlayers, countRounds, countStandings, countTournaments, countUserApiKeys, countUsers, createApiKey, createEntry, createLocation, createManyEntries, createManyMatches, createManyRounds, createManyStandings, createMatch, createOpprPlayerRanking, createOpprRankingHistory, createPlayer, createRound, createStanding, createTournament, createUser, createUserWithPlayer, deleteApiKey, deleteEntriesByMatch, deleteEntry, deleteLocation, deleteMatch, deleteMatchesByRound, deleteMatchesByTournament, deleteOpprPlayerRanking, deletePlayer, deleteRound, deleteRoundsByTournament, deleteStanding, deleteStandingsByTournament, deleteTournament, deleteUser, deleteUserApiKey, disconnect, findApiKeyById, findApiKeysByPrefix, findEntries, findEntryById, findEntryByMatchAndPlayer, findLocationByExternalId, findLocationById, findLocations, findMatchById, findMatches, findOpprPlayerRankingById, findOpprPlayerRankingByPlayerId, findOpprPlayerRankings, findPlayerByExternalId, findPlayerById, findPlayerByPlayerNumber, findPlayerByUserEmail, findPlayers, findRoundById, findRoundByTournamentAndNumber, findRounds, findStandingById, findStandingByPlayerAndTournament, findStandings, findTournamentByExternalId, findTournamentById, findTournaments, findUserByEmail, findUserById, findUsers, generateUniquePlayerNumber, getFinalsRounds, getFinalsStandings, getLatestOpprRankingHistory, getLocationWithTournaments, getMajorTournaments, getMatchEntries, getMatchWithEntries, getMergedStandings, getOpprRankingHistory, getOpprRankingHistoryByDateRange, getOrCreateOpprPlayerRanking, getPlayerEntries, getPlayerEntryStats, getPlayerStandings, getPlayerStats, getPlayerTopFinishes, getPlayerTournamentEntries, getPlayerTournamentMatches, getPlayerWithResults, getQualifyingRounds, getQualifyingStandings, getRatedOpprPlayers, getRecentTournaments, getRoundMatches, getRoundWithMatches, getTopPlayersByOpprRanking, getTopPlayersByOpprRating, getTournamentMatches, getTournamentRounds, getTournamentStandings, getTournamentStats, getTournamentWithMatches, getTournamentWithResults, getTournamentsByBoosterType, getTournamentsByDateRange, getUserApiKeys, getUserByEmailWithPlayer, getUserWithPlayer, isValidPlayerNumber, linkPlayerToUser, prisma, recalculateTimeDecay, searchLocations, searchPlayers, searchTournaments, testConnection, updateApiKeyLastUsed, updateEntry, updateLocation, updateMatch, updateOpprPlayerRanking, updateOpprRatingAfterTournament, updatePlayer, updateRound, updateStanding, updateStandingPoints, updateTournament, updateUser, updateUserRefreshToken, updateWorldRankings };
1609
+ export { type ApiKeyInfo, type ApiKeyWithUser, type BlogPostWithRelations, type ConnectionStatus, type CreateApiKeyInput, type CreateBlogPostInput, type CreateBlogTagInput, type CreateEntryInput, type CreateLocationInput, type CreateMatchInput, type CreateOpprPlayerRankingInput, type CreateOpprRankingHistoryInput, type CreatePlayerInput, type CreateRoundInput, type CreateStandingInput, type CreateTournamentInput, type CreateUserInput, type FindBlogPostsOptions, type FindBlogTagsOptions, type FindEntriesOptions, type FindLocationsOptions, type FindMatchesOptions, type FindOpprPlayerRankingsOptions, type FindPlayersOptions, type FindRoundsOptions, type FindStandingsOptions, type FindTournamentsOptions, MAX_API_KEYS_PER_USER, type MergedStanding, type PlayerStatistics, type PlayerWithResults, type StandingWithTournament, type TournamentStatistics, type UpdateBlogPostInput, type UpdateBlogTagInput, type UpdateEntryInput, type UpdateLocationInput, type UpdateMatchInput, type UpdateOpprPlayerRankingInput, type UpdatePlayerInput, type UpdateRoundInput, type UpdateStandingInput, type UpdateTournamentInput, type UpdateUserInput, type UserWithPlayer, applyRDDecayForInactivePlayers, connect, countBlogPosts, countBlogTags, countEntries, countLocations, countMatches, countOpprPlayerRankings, countOpprRankingHistory, countPlayers, countPublishedBlogPosts, countRounds, countStandings, countTournaments, countUserApiKeys, countUsers, createApiKey, createBlogPost, createBlogTag, createEntry, createLocation, createManyEntries, createManyMatches, createManyRounds, createManyStandings, createMatch, createOpprPlayerRanking, createOpprRankingHistory, createPlayer, createRound, createStanding, createTournament, createUser, createUserWithPlayer, deleteApiKey, deleteBlogPost, deleteBlogTag, deleteEntriesByMatch, deleteEntry, deleteLocation, deleteMatch, deleteMatchesByRound, deleteMatchesByTournament, deleteOpprPlayerRanking, deletePlayer, deleteRound, deleteRoundsByTournament, deleteStanding, deleteStandingsByTournament, deleteTournament, deleteUser, deleteUserApiKey, disconnect, findApiKeyById, findApiKeysByPrefix, findBlogPostById, findBlogPostBySlug, findBlogPosts, findBlogTagById, findBlogTagBySlug, findBlogTags, findEntries, findEntryById, findEntryByMatchAndPlayer, findLocationByExternalId, findLocationById, findLocations, findMatchById, findMatches, findOpprPlayerRankingById, findOpprPlayerRankingByPlayerId, findOpprPlayerRankings, findPlayerByExternalId, findPlayerById, findPlayerByPlayerNumber, findPlayerByUserEmail, findPlayers, findPublishedBlogPosts, findRoundById, findRoundByTournamentAndNumber, findRounds, findStandingById, findStandingByPlayerAndTournament, findStandings, findTournamentByExternalId, findTournamentById, findTournaments, findUserByEmail, findUserById, findUsers, generateUniquePlayerNumber, getBlogTagWithPostCount, getBlogTagsWithPostCounts, getFinalsRounds, getFinalsStandings, getLatestOpprRankingHistory, getLocationWithTournaments, getMajorTournaments, getMatchEntries, getMatchWithEntries, getMergedStandings, getOpprRankingHistory, getOpprRankingHistoryByDateRange, getOrCreateOpprPlayerRanking, getPlayerEntries, getPlayerEntryStats, getPlayerStandings, getPlayerStats, getPlayerTopFinishes, getPlayerTournamentEntries, getPlayerTournamentMatches, getPlayerWithResults, getQualifyingRounds, getQualifyingStandings, getRatedOpprPlayers, getRecentTournaments, getRoundMatches, getRoundWithMatches, getTopPlayersByOpprRanking, getTopPlayersByOpprRating, getTournamentMatches, getTournamentRounds, getTournamentStandings, getTournamentStats, getTournamentWithMatches, getTournamentWithResults, getTournamentsByBoosterType, getTournamentsByDateRange, getUserApiKeys, getUserByEmailWithPlayer, getUserWithPlayer, isValidPlayerNumber, linkPlayerToUser, prisma, recalculateTimeDecay, searchBlogPosts, searchBlogTags, searchLocations, searchPlayers, searchTournaments, testConnection, updateApiKeyLastUsed, updateBlogPost, updateBlogTag, updateEntry, updateLocation, updateMatch, updateOpprPlayerRanking, updateOpprRatingAfterTournament, updatePlayer, updateRound, updateStanding, updateStandingPoints, updateTournament, updateUser, updateUserRefreshToken, updateWorldRankings };
package/dist/index.js CHANGED
@@ -1311,22 +1311,206 @@ async function getLocationWithTournaments(id) {
1311
1311
  }
1312
1312
  });
1313
1313
  }
1314
+
1315
+ // src/blog-posts.ts
1316
+ var defaultInclude = {
1317
+ author: {
1318
+ select: { id: true, email: true }
1319
+ },
1320
+ tags: {
1321
+ select: { id: true, name: true, slug: true }
1322
+ }
1323
+ };
1324
+ async function createBlogPost(data) {
1325
+ const { tagIds, ...postData } = data;
1326
+ return prisma.blogPost.create({
1327
+ data: {
1328
+ ...postData,
1329
+ tags: tagIds?.length ? { connect: tagIds.map((id) => ({ id })) } : void 0
1330
+ },
1331
+ include: defaultInclude
1332
+ });
1333
+ }
1334
+ async function findBlogPostById(id) {
1335
+ return prisma.blogPost.findUnique({
1336
+ where: { id },
1337
+ include: defaultInclude
1338
+ });
1339
+ }
1340
+ async function findBlogPostBySlug(slug) {
1341
+ return prisma.blogPost.findUnique({
1342
+ where: { slug },
1343
+ include: defaultInclude
1344
+ });
1345
+ }
1346
+ async function findBlogPosts(options = {}) {
1347
+ return prisma.blogPost.findMany({
1348
+ take: options.take,
1349
+ skip: options.skip,
1350
+ where: options.where,
1351
+ orderBy: options.orderBy ?? { createdAt: "desc" },
1352
+ include: options.include ?? defaultInclude
1353
+ });
1354
+ }
1355
+ async function findPublishedBlogPosts(options = {}) {
1356
+ const { tagSlug, ...restOptions } = options;
1357
+ const where = {
1358
+ status: "PUBLISHED",
1359
+ publishedAt: { not: null },
1360
+ ...tagSlug && {
1361
+ tags: {
1362
+ some: { slug: tagSlug }
1363
+ }
1364
+ }
1365
+ };
1366
+ return findBlogPosts({
1367
+ ...restOptions,
1368
+ where,
1369
+ orderBy: options.orderBy ?? { publishedAt: "desc" }
1370
+ });
1371
+ }
1372
+ async function searchBlogPosts(query, limit = 20, publishedOnly = true) {
1373
+ const where = {
1374
+ OR: [
1375
+ { title: { contains: query, mode: "insensitive" } },
1376
+ { excerpt: { contains: query, mode: "insensitive" } }
1377
+ ],
1378
+ ...publishedOnly && {
1379
+ status: "PUBLISHED",
1380
+ publishedAt: { not: null }
1381
+ }
1382
+ };
1383
+ return findBlogPosts({
1384
+ take: limit,
1385
+ where,
1386
+ orderBy: { publishedAt: "desc" }
1387
+ });
1388
+ }
1389
+ async function updateBlogPost(id, data) {
1390
+ const { tagIds, ...postData } = data;
1391
+ return prisma.blogPost.update({
1392
+ where: { id },
1393
+ data: {
1394
+ ...postData,
1395
+ // If tagIds is provided, replace all tags
1396
+ ...tagIds !== void 0 && {
1397
+ tags: {
1398
+ set: tagIds.map((tagId) => ({ id: tagId }))
1399
+ }
1400
+ }
1401
+ },
1402
+ include: defaultInclude
1403
+ });
1404
+ }
1405
+ async function deleteBlogPost(id) {
1406
+ return prisma.blogPost.delete({
1407
+ where: { id }
1408
+ });
1409
+ }
1410
+ async function countBlogPosts(where) {
1411
+ return prisma.blogPost.count({ where });
1412
+ }
1413
+ async function countPublishedBlogPosts(tagSlug) {
1414
+ return countBlogPosts({
1415
+ status: "PUBLISHED",
1416
+ publishedAt: { not: null },
1417
+ ...tagSlug && {
1418
+ tags: {
1419
+ some: { slug: tagSlug }
1420
+ }
1421
+ }
1422
+ });
1423
+ }
1424
+
1425
+ // src/blog-tags.ts
1426
+ async function createBlogTag(data) {
1427
+ return prisma.blogTag.create({
1428
+ data
1429
+ });
1430
+ }
1431
+ async function findBlogTagById(id) {
1432
+ return prisma.blogTag.findUnique({
1433
+ where: { id }
1434
+ });
1435
+ }
1436
+ async function findBlogTagBySlug(slug) {
1437
+ return prisma.blogTag.findUnique({
1438
+ where: { slug }
1439
+ });
1440
+ }
1441
+ async function findBlogTags(options = {}) {
1442
+ return prisma.blogTag.findMany({
1443
+ take: options.take,
1444
+ skip: options.skip,
1445
+ where: options.where,
1446
+ orderBy: options.orderBy ?? { name: "asc" },
1447
+ include: options.include
1448
+ });
1449
+ }
1450
+ async function searchBlogTags(query, limit = 20) {
1451
+ return findBlogTags({
1452
+ take: limit,
1453
+ where: {
1454
+ name: { contains: query, mode: "insensitive" }
1455
+ },
1456
+ orderBy: { name: "asc" }
1457
+ });
1458
+ }
1459
+ async function updateBlogTag(id, data) {
1460
+ return prisma.blogTag.update({
1461
+ where: { id },
1462
+ data
1463
+ });
1464
+ }
1465
+ async function deleteBlogTag(id) {
1466
+ return prisma.blogTag.delete({
1467
+ where: { id }
1468
+ });
1469
+ }
1470
+ async function countBlogTags(where) {
1471
+ return prisma.blogTag.count({ where });
1472
+ }
1473
+ async function getBlogTagWithPostCount(id) {
1474
+ return prisma.blogTag.findUnique({
1475
+ where: { id },
1476
+ include: {
1477
+ _count: {
1478
+ select: { posts: true }
1479
+ }
1480
+ }
1481
+ });
1482
+ }
1483
+ async function getBlogTagsWithPostCounts() {
1484
+ return prisma.blogTag.findMany({
1485
+ include: {
1486
+ _count: {
1487
+ select: { posts: true }
1488
+ }
1489
+ },
1490
+ orderBy: { name: "asc" }
1491
+ });
1492
+ }
1314
1493
  export {
1315
1494
  MAX_API_KEYS_PER_USER,
1316
1495
  applyRDDecayForInactivePlayers,
1317
1496
  connect,
1497
+ countBlogPosts,
1498
+ countBlogTags,
1318
1499
  countEntries,
1319
1500
  countLocations,
1320
1501
  countMatches,
1321
1502
  countOpprPlayerRankings,
1322
1503
  countOpprRankingHistory,
1323
1504
  countPlayers,
1505
+ countPublishedBlogPosts,
1324
1506
  countRounds,
1325
1507
  countStandings,
1326
1508
  countTournaments,
1327
1509
  countUserApiKeys,
1328
1510
  countUsers,
1329
1511
  createApiKey,
1512
+ createBlogPost,
1513
+ createBlogTag,
1330
1514
  createEntry,
1331
1515
  createLocation,
1332
1516
  createManyEntries,
@@ -1343,6 +1527,8 @@ export {
1343
1527
  createUser,
1344
1528
  createUserWithPlayer,
1345
1529
  deleteApiKey,
1530
+ deleteBlogPost,
1531
+ deleteBlogTag,
1346
1532
  deleteEntriesByMatch,
1347
1533
  deleteEntry,
1348
1534
  deleteLocation,
@@ -1361,6 +1547,12 @@ export {
1361
1547
  disconnect,
1362
1548
  findApiKeyById,
1363
1549
  findApiKeysByPrefix,
1550
+ findBlogPostById,
1551
+ findBlogPostBySlug,
1552
+ findBlogPosts,
1553
+ findBlogTagById,
1554
+ findBlogTagBySlug,
1555
+ findBlogTags,
1364
1556
  findEntries,
1365
1557
  findEntryById,
1366
1558
  findEntryByMatchAndPlayer,
@@ -1377,6 +1569,7 @@ export {
1377
1569
  findPlayerByPlayerNumber,
1378
1570
  findPlayerByUserEmail,
1379
1571
  findPlayers,
1572
+ findPublishedBlogPosts,
1380
1573
  findRoundById,
1381
1574
  findRoundByTournamentAndNumber,
1382
1575
  findRounds,
@@ -1390,6 +1583,8 @@ export {
1390
1583
  findUserById,
1391
1584
  findUsers,
1392
1585
  generateUniquePlayerNumber,
1586
+ getBlogTagWithPostCount,
1587
+ getBlogTagsWithPostCounts,
1393
1588
  getFinalsRounds,
1394
1589
  getFinalsStandings,
1395
1590
  getLatestOpprRankingHistory,
@@ -1432,11 +1627,15 @@ export {
1432
1627
  linkPlayerToUser,
1433
1628
  prisma,
1434
1629
  recalculateTimeDecay,
1630
+ searchBlogPosts,
1631
+ searchBlogTags,
1435
1632
  searchLocations,
1436
1633
  searchPlayers,
1437
1634
  searchTournaments,
1438
1635
  testConnection,
1439
1636
  updateApiKeyLastUsed,
1637
+ updateBlogPost,
1638
+ updateBlogTag,
1440
1639
  updateEntry,
1441
1640
  updateLocation,
1442
1641
  updateMatch,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opprs/db-prisma",
3
- "version": "2.2.1-canary.cd8b178",
3
+ "version": "2.2.1-canary.d2b7951",
4
4
  "description": "Database backend for OPPR (Open Pinball Player Ranking System) using Prisma and PostgreSQL",
5
5
  "keywords": [
6
6
  "oppr",
@@ -56,7 +56,7 @@
56
56
  "vitest": "^4.0.16"
57
57
  },
58
58
  "peerDependencies": {
59
- "@opprs/core": "^2.2.1-canary.cd8b178"
59
+ "@opprs/core": "^2.2.1-canary.d2b7951"
60
60
  },
61
61
  "engines": {
62
62
  "node": ">=20.9.0"
@@ -200,6 +200,12 @@ enum Role {
200
200
  ADMIN
201
201
  }
202
202
 
203
+ // Enum for blog post status
204
+ enum PostStatus {
205
+ DRAFT
206
+ PUBLISHED
207
+ }
208
+
203
209
  // User model - represents an authenticated user account
204
210
  model User {
205
211
  id String @id @default(cuid())
@@ -225,6 +231,9 @@ model User {
225
231
  privacyPolicyAcceptedAt DateTime?
226
232
  codeOfConductAcceptedAt DateTime?
227
233
 
234
+ // Blog posts authored by this user
235
+ blogPosts BlogPost[]
236
+
228
237
  // API Keys
229
238
  apiKeys ApiKey[]
230
239
 
@@ -275,6 +284,62 @@ model Location {
275
284
  @@index([city])
276
285
  }
277
286
 
287
+ // BlogPost model - represents a blog article
288
+ model BlogPost {
289
+ id String @id @default(cuid())
290
+ createdAt DateTime @default(now())
291
+ updatedAt DateTime @updatedAt
292
+
293
+ // Content
294
+ title String
295
+ slug String @unique
296
+ content String @db.Text
297
+ excerpt String? @db.VarChar(500)
298
+
299
+ // Status
300
+ status PostStatus @default(DRAFT)
301
+ publishedAt DateTime?
302
+
303
+ // Featured image (external URL)
304
+ featuredImageUrl String?
305
+ featuredImageAlt String?
306
+
307
+ // SEO fields
308
+ metaTitle String? @db.VarChar(60)
309
+ metaDescription String? @db.VarChar(160)
310
+ ogTitle String?
311
+ ogDescription String?
312
+ ogImageUrl String?
313
+
314
+ // Author (User who created the post)
315
+ authorId String
316
+ author User @relation(fields: [authorId], references: [id], onDelete: Restrict)
317
+
318
+ // Tags relation
319
+ tags BlogTag[]
320
+
321
+ @@index([slug])
322
+ @@index([status])
323
+ @@index([publishedAt])
324
+ @@index([authorId])
325
+ }
326
+
327
+ // BlogTag model - for categorizing blog posts
328
+ model BlogTag {
329
+ id String @id @default(cuid())
330
+ createdAt DateTime @default(now())
331
+ updatedAt DateTime @updatedAt
332
+
333
+ name String @unique
334
+ slug String @unique
335
+ description String?
336
+
337
+ // Posts with this tag
338
+ posts BlogPost[]
339
+
340
+ @@index([slug])
341
+ }
342
+
278
343
  // OPPR Player Ranking - OPPR-specific rating and ranking data
279
344
  // Separated from Player to allow for future alternative ranking systems
280
345
  model OpprPlayerRanking {