@newcms/database 0.0.2 → 0.1.1

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.d.ts CHANGED
@@ -4,4 +4,11 @@ export * from './schema/index.js';
4
4
  export { ObjectCache } from './cache/index.js';
5
5
  export type { ObjectCacheConfig, CacheGroupConfig } from './cache/index.js';
6
6
  export { OptionsRepository } from './repositories/options-repository.js';
7
+ export { PostRepository } from './repositories/post-repository.js';
8
+ export type { CreatePostInput, UpdatePostInput, PostRow } from './repositories/post-repository.js';
9
+ export { MetaRepository } from './repositories/meta-repository.js';
10
+ export type { MetaTableColumns, MetaColumnNames, MetaEntry } from './repositories/meta-repository.js';
11
+ export { TaxonomyRepository } from './repositories/taxonomy-repository.js';
12
+ export type { CreateTermInput, TermRow } from './repositories/taxonomy-repository.js';
13
+ export { RevisionRepository } from './repositories/revision-repository.js';
7
14
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnD,YAAY,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAChE,cAAc,mBAAmB,CAAC;AAClC,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,YAAY,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAC5E,OAAO,EAAE,iBAAiB,EAAE,MAAM,sCAAsC,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnD,YAAY,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAChE,cAAc,mBAAmB,CAAC;AAClC,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,YAAY,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAC5E,OAAO,EAAE,iBAAiB,EAAE,MAAM,sCAAsC,CAAC;AACzE,OAAO,EAAE,cAAc,EAAE,MAAM,mCAAmC,CAAC;AACnE,YAAY,EAAE,eAAe,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,mCAAmC,CAAC;AACnG,OAAO,EAAE,cAAc,EAAE,MAAM,mCAAmC,CAAC;AACnE,YAAY,EAAE,gBAAgB,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,mCAAmC,CAAC;AACtG,OAAO,EAAE,kBAAkB,EAAE,MAAM,uCAAuC,CAAC;AAC3E,YAAY,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,uCAAuC,CAAC;AACtF,OAAO,EAAE,kBAAkB,EAAE,MAAM,uCAAuC,CAAC"}
package/dist/index.js CHANGED
@@ -2,4 +2,8 @@ export { createConnection } from './connection.js';
2
2
  export * from './schema/index.js';
3
3
  export { ObjectCache } from './cache/index.js';
4
4
  export { OptionsRepository } from './repositories/options-repository.js';
5
+ export { PostRepository } from './repositories/post-repository.js';
6
+ export { MetaRepository } from './repositories/meta-repository.js';
7
+ export { TaxonomyRepository } from './repositories/taxonomy-repository.js';
8
+ export { RevisionRepository } from './repositories/revision-repository.js';
5
9
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAEnD,cAAc,mBAAmB,CAAC;AAClC,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAE/C,OAAO,EAAE,iBAAiB,EAAE,MAAM,sCAAsC,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAEnD,cAAc,mBAAmB,CAAC;AAClC,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAE/C,OAAO,EAAE,iBAAiB,EAAE,MAAM,sCAAsC,CAAC;AACzE,OAAO,EAAE,cAAc,EAAE,MAAM,mCAAmC,CAAC;AAEnE,OAAO,EAAE,cAAc,EAAE,MAAM,mCAAmC,CAAC;AAEnE,OAAO,EAAE,kBAAkB,EAAE,MAAM,uCAAuC,CAAC;AAE3E,OAAO,EAAE,kBAAkB,EAAE,MAAM,uCAAuC,CAAC"}
@@ -0,0 +1,71 @@
1
+ import type { PgTable, PgColumn } from 'drizzle-orm/pg-core';
2
+ import type { Database } from '../connection.js';
3
+ /**
4
+ * Column references needed for a meta table.
5
+ */
6
+ export interface MetaTableColumns {
7
+ metaId: PgColumn;
8
+ objectId: PgColumn;
9
+ metaKey: PgColumn;
10
+ metaValue: PgColumn;
11
+ metaValueJson: PgColumn;
12
+ }
13
+ /**
14
+ * Column name mapping for raw SQL operations and result parsing.
15
+ *
16
+ * `sql` = names as in the database (for INSERT/UPDATE raw SQL)
17
+ * `ts` = names as in the Drizzle schema definition (for reading select results)
18
+ */
19
+ export interface MetaColumnNames {
20
+ table: string;
21
+ /** SQL column names (for raw queries) */
22
+ sql: {
23
+ metaId: string;
24
+ objectId: string;
25
+ metaKey: string;
26
+ metaValue: string;
27
+ metaValueJson: string;
28
+ };
29
+ /** TypeScript property names (for reading Drizzle select results) */
30
+ ts: {
31
+ metaId: string;
32
+ objectId: string;
33
+ metaKey: string;
34
+ metaValue: string;
35
+ metaValueJson: string;
36
+ };
37
+ }
38
+ export interface MetaEntry {
39
+ metaId: number;
40
+ objectId: number;
41
+ metaKey: string | null;
42
+ metaValue: string | null;
43
+ metaValueJson: unknown;
44
+ }
45
+ /**
46
+ * Generic metadata repository — works with any meta table (postmeta, usermeta,
47
+ * commentmeta, termmeta). Follows the entity-attribute-value pattern with
48
+ * JSONB support for structured queries.
49
+ */
50
+ export declare class MetaRepository {
51
+ private db;
52
+ private table;
53
+ private columns;
54
+ private colNames;
55
+ constructor(db: Database, table: PgTable, columns: MetaTableColumns, colNames: MetaColumnNames);
56
+ get<T = unknown>(objectId: number, key: string): Promise<T | undefined>;
57
+ getAll<T = unknown>(objectId: number, key: string): Promise<T[]>;
58
+ getAllForObject(objectId: number): Promise<Map<string, unknown[]>>;
59
+ batchLoad(objectIds: number[]): Promise<Map<number, Map<string, unknown[]>>>;
60
+ add(objectId: number, key: string, value: unknown): Promise<number>;
61
+ update(objectId: number, key: string, value: unknown): Promise<boolean>;
62
+ delete(objectId: number, key: string, value?: unknown): Promise<number>;
63
+ deleteAllForObject(objectId: number): Promise<number>;
64
+ /**
65
+ * Convert a raw DB row to MetaEntry using column name mapping.
66
+ */
67
+ private toMetaEntry;
68
+ private serialize;
69
+ private deserialize;
70
+ }
71
+ //# sourceMappingURL=meta-repository.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"meta-repository.d.ts","sourceRoot":"","sources":["../../src/repositories/meta-repository.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAC7D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAEjD;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAChC,MAAM,EAAE,QAAQ,CAAC;IACjB,QAAQ,EAAE,QAAQ,CAAC;IACnB,OAAO,EAAE,QAAQ,CAAC;IAClB,SAAS,EAAE,QAAQ,CAAC;IACpB,aAAa,EAAE,QAAQ,CAAC;CACxB;AAED;;;;;GAKG;AACH,MAAM,WAAW,eAAe;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,yCAAyC;IACzC,GAAG,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,MAAM,CAAA;KAAE,CAAC;IACrG,qEAAqE;IACrE,EAAE,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,MAAM,CAAA;KAAE,CAAC;CACpG;AAED,MAAM,WAAW,SAAS;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,aAAa,EAAE,OAAO,CAAC;CACvB;AAED;;;;GAIG;AACH,qBAAa,cAAc;IAIzB,OAAO,CAAC,EAAE;IACV,OAAO,CAAC,KAAK;IACb,OAAO,CAAC,OAAO;IALhB,OAAO,CAAC,QAAQ,CAAkB;gBAGzB,EAAE,EAAE,QAAQ,EACZ,KAAK,EAAE,OAAO,EACd,OAAO,EAAE,gBAAgB,EACjC,QAAQ,EAAE,eAAe;IAKpB,GAAG,CAAC,CAAC,GAAG,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC;IAWvE,MAAM,CAAC,CAAC,GAAG,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC;IAShE,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC;IAiBlE,SAAS,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC;IAwB5E,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC;IAgBnE,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;IA4BvE,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC;IAwBvE,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAQ3D;;OAEG;IACH,OAAO,CAAC,WAAW;IAWnB,OAAO,CAAC,SAAS;IAoBjB,OAAO,CAAC,WAAW;CAWnB"}
@@ -0,0 +1,176 @@
1
+ import { eq, and, inArray, sql } from 'drizzle-orm';
2
+ /**
3
+ * Generic metadata repository — works with any meta table (postmeta, usermeta,
4
+ * commentmeta, termmeta). Follows the entity-attribute-value pattern with
5
+ * JSONB support for structured queries.
6
+ */
7
+ export class MetaRepository {
8
+ db;
9
+ table;
10
+ columns;
11
+ colNames;
12
+ constructor(db, table, columns, colNames) {
13
+ this.db = db;
14
+ this.table = table;
15
+ this.columns = columns;
16
+ this.colNames = colNames;
17
+ }
18
+ async get(objectId, key) {
19
+ const rows = await this.db
20
+ .select()
21
+ .from(this.table)
22
+ .where(and(eq(this.columns.objectId, objectId), eq(this.columns.metaKey, key)))
23
+ .limit(1);
24
+ if (rows.length === 0)
25
+ return undefined;
26
+ return this.deserialize(this.toMetaEntry(rows[0]));
27
+ }
28
+ async getAll(objectId, key) {
29
+ const rows = await this.db
30
+ .select()
31
+ .from(this.table)
32
+ .where(and(eq(this.columns.objectId, objectId), eq(this.columns.metaKey, key)));
33
+ return rows.map((r) => this.deserialize(this.toMetaEntry(r)));
34
+ }
35
+ async getAllForObject(objectId) {
36
+ const rows = await this.db
37
+ .select()
38
+ .from(this.table)
39
+ .where(eq(this.columns.objectId, objectId));
40
+ const result = new Map();
41
+ for (const row of rows) {
42
+ const entry = this.toMetaEntry(row);
43
+ const key = entry.metaKey ?? '';
44
+ const values = result.get(key) ?? [];
45
+ values.push(this.deserialize(entry));
46
+ result.set(key, values);
47
+ }
48
+ return result;
49
+ }
50
+ async batchLoad(objectIds) {
51
+ if (objectIds.length === 0)
52
+ return new Map();
53
+ const rows = await this.db
54
+ .select()
55
+ .from(this.table)
56
+ .where(inArray(this.columns.objectId, objectIds));
57
+ const result = new Map();
58
+ for (const row of rows) {
59
+ const rawRow = row;
60
+ const entry = this.toMetaEntry(rawRow);
61
+ if (!result.has(entry.objectId)) {
62
+ result.set(entry.objectId, new Map());
63
+ }
64
+ const objectMeta = result.get(entry.objectId);
65
+ const key = entry.metaKey ?? '';
66
+ const values = objectMeta.get(key) ?? [];
67
+ values.push(this.deserialize(entry));
68
+ objectMeta.set(key, values);
69
+ }
70
+ return result;
71
+ }
72
+ async add(objectId, key, value) {
73
+ const { textValue, jsonValue } = this.serialize(value);
74
+ const jsonStr = jsonValue !== null ? JSON.stringify(jsonValue) : null;
75
+ const s = this.colNames.sql;
76
+ const t = this.colNames.table;
77
+ const rows = await this.db.execute(sql `
78
+ INSERT INTO ${sql.raw(`"${t}"`)} (${sql.raw(`"${s.objectId}"`)}, ${sql.raw(`"${s.metaKey}"`)}, ${sql.raw(`"${s.metaValue}"`)}, ${sql.raw(`"${s.metaValueJson}"`)})
79
+ VALUES (${objectId}, ${key}, ${textValue}, ${jsonStr}::jsonb)
80
+ RETURNING ${sql.raw(`"${s.metaId}"`)}
81
+ `);
82
+ const returnedRows = rows;
83
+ return returnedRows[0][s.metaId];
84
+ }
85
+ async update(objectId, key, value) {
86
+ const { textValue, jsonValue } = this.serialize(value);
87
+ const existing = await this.db
88
+ .select({ metaId: this.columns.metaId })
89
+ .from(this.table)
90
+ .where(and(eq(this.columns.objectId, objectId), eq(this.columns.metaKey, key)))
91
+ .limit(1);
92
+ if (existing.length === 0) {
93
+ await this.add(objectId, key, value);
94
+ return true;
95
+ }
96
+ const metaId = existing[0].metaId;
97
+ const jsonStr = jsonValue !== null ? JSON.stringify(jsonValue) : null;
98
+ const s = this.colNames.sql;
99
+ const t = this.colNames.table;
100
+ await this.db.execute(sql `
101
+ UPDATE ${sql.raw(`"${t}"`)}
102
+ SET ${sql.raw(`"${s.metaValue}"`)} = ${textValue}, ${sql.raw(`"${s.metaValueJson}"`)} = ${jsonStr}::jsonb
103
+ WHERE ${sql.raw(`"${s.metaId}"`)} = ${metaId}
104
+ `);
105
+ return true;
106
+ }
107
+ async delete(objectId, key, value) {
108
+ if (value !== undefined) {
109
+ const { textValue } = this.serialize(value);
110
+ const result = await this.db
111
+ .delete(this.table)
112
+ .where(and(eq(this.columns.objectId, objectId), eq(this.columns.metaKey, key), eq(this.columns.metaValue, textValue)))
113
+ .returning({ metaId: this.columns.metaId });
114
+ return result.length;
115
+ }
116
+ const result = await this.db
117
+ .delete(this.table)
118
+ .where(and(eq(this.columns.objectId, objectId), eq(this.columns.metaKey, key)))
119
+ .returning({ metaId: this.columns.metaId });
120
+ return result.length;
121
+ }
122
+ async deleteAllForObject(objectId) {
123
+ const result = await this.db
124
+ .delete(this.table)
125
+ .where(eq(this.columns.objectId, objectId))
126
+ .returning({ metaId: this.columns.metaId });
127
+ return result.length;
128
+ }
129
+ /**
130
+ * Convert a raw DB row to MetaEntry using column name mapping.
131
+ */
132
+ toMetaEntry(row) {
133
+ const ts = this.colNames.ts;
134
+ return {
135
+ metaId: row[ts.metaId],
136
+ objectId: row[ts.objectId],
137
+ metaKey: row[ts.metaKey],
138
+ metaValue: row[ts.metaValue],
139
+ metaValueJson: row[ts.metaValueJson],
140
+ };
141
+ }
142
+ serialize(value) {
143
+ if (value === null || value === undefined) {
144
+ return { textValue: '', jsonValue: null };
145
+ }
146
+ if (typeof value === 'string') {
147
+ try {
148
+ const parsed = JSON.parse(value);
149
+ if (typeof parsed === 'object' && parsed !== null) {
150
+ return { textValue: value, jsonValue: parsed };
151
+ }
152
+ }
153
+ catch { /* plain string */ }
154
+ return { textValue: value, jsonValue: null };
155
+ }
156
+ if (typeof value === 'number' || typeof value === 'boolean') {
157
+ return { textValue: String(value), jsonValue: null };
158
+ }
159
+ const textValue = JSON.stringify(value);
160
+ return { textValue, jsonValue: value };
161
+ }
162
+ deserialize(entry) {
163
+ if (entry.metaValueJson !== null && entry.metaValueJson !== undefined) {
164
+ return entry.metaValueJson;
165
+ }
166
+ if (entry.metaValue === null)
167
+ return '';
168
+ try {
169
+ return JSON.parse(entry.metaValue);
170
+ }
171
+ catch {
172
+ return entry.metaValue;
173
+ }
174
+ }
175
+ }
176
+ //# sourceMappingURL=meta-repository.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"meta-repository.js","sourceRoot":"","sources":["../../src/repositories/meta-repository.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,121 @@
1
+ import type { Database } from '../connection.js';
2
+ import { MetaRepository } from './meta-repository.js';
3
+ export interface CreatePostInput {
4
+ postAuthor: number;
5
+ postTitle: string;
6
+ postContent?: string;
7
+ postExcerpt?: string;
8
+ postStatus?: string;
9
+ postName?: string;
10
+ postType?: string;
11
+ postParent?: number;
12
+ postPassword?: string;
13
+ commentStatus?: string;
14
+ pingStatus?: string;
15
+ postMimeType?: string;
16
+ menuOrder?: number;
17
+ guid?: string;
18
+ }
19
+ export interface UpdatePostInput {
20
+ postTitle?: string;
21
+ postContent?: string;
22
+ postExcerpt?: string;
23
+ postStatus?: string;
24
+ postName?: string;
25
+ postType?: string;
26
+ postParent?: number;
27
+ postPassword?: string;
28
+ commentStatus?: string;
29
+ pingStatus?: string;
30
+ menuOrder?: number;
31
+ }
32
+ export interface PostRow {
33
+ id: number;
34
+ postAuthor: number;
35
+ postDate: Date;
36
+ postDateGmt: Date;
37
+ postContent: string;
38
+ postTitle: string;
39
+ postExcerpt: string;
40
+ postStatus: string;
41
+ commentStatus: string;
42
+ pingStatus: string;
43
+ postPassword: string;
44
+ postName: string;
45
+ toPing: string;
46
+ pinged: string;
47
+ postModified: Date;
48
+ postModifiedGmt: Date;
49
+ postContentFiltered: string;
50
+ postParent: number;
51
+ guid: string;
52
+ menuOrder: number;
53
+ postType: string;
54
+ postMimeType: string;
55
+ commentCount: number;
56
+ }
57
+ /**
58
+ * Repository for posts (all content types).
59
+ *
60
+ * Handles CRUD, slug generation, sticky posts, and provides
61
+ * a MetaRepository instance for post metadata operations.
62
+ */
63
+ export declare class PostRepository {
64
+ private db;
65
+ readonly meta: MetaRepository;
66
+ constructor(db: Database);
67
+ /**
68
+ * Create a new post.
69
+ */
70
+ create(input: CreatePostInput): Promise<PostRow>;
71
+ /**
72
+ * Get a post by ID.
73
+ */
74
+ getById(id: number): Promise<PostRow | undefined>;
75
+ /**
76
+ * Get a post by slug and type.
77
+ */
78
+ getBySlug(slug: string, postType?: string): Promise<PostRow | undefined>;
79
+ /**
80
+ * Update a post. Returns the updated row or undefined if not found.
81
+ */
82
+ update(id: number, input: UpdatePostInput): Promise<PostRow | undefined>;
83
+ /**
84
+ * Trash a post (move to trash status, preserving original status in meta).
85
+ */
86
+ trash(id: number): Promise<PostRow | undefined>;
87
+ /**
88
+ * Restore a trashed post to its original status.
89
+ */
90
+ untrash(id: number): Promise<PostRow | undefined>;
91
+ /**
92
+ * Permanently delete a post and all its metadata.
93
+ */
94
+ deletePermanently(id: number): Promise<boolean>;
95
+ /**
96
+ * Get sticky post IDs.
97
+ */
98
+ getStickyIds(): Promise<number[]>;
99
+ /**
100
+ * Set a post as sticky or not.
101
+ */
102
+ setSticky(id: number, sticky: boolean): Promise<void>;
103
+ /**
104
+ * Check if a post is sticky.
105
+ */
106
+ isSticky(id: number): Promise<boolean>;
107
+ /**
108
+ * Count posts by type and status.
109
+ */
110
+ countByStatus(postType?: string): Promise<Record<string, number>>;
111
+ /**
112
+ * Generate a URL-safe slug from a title.
113
+ */
114
+ private generateSlug;
115
+ /**
116
+ * Ensure a slug is unique within a post type.
117
+ * Appends -2, -3, etc. if needed.
118
+ */
119
+ private ensureUniqueSlug;
120
+ }
121
+ //# sourceMappingURL=post-repository.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"post-repository.d.ts","sourceRoot":"","sources":["../../src/repositories/post-repository.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,241 @@
1
+ import { eq, and, sql } from 'drizzle-orm';
2
+ import { posts, postmeta } from '../schema/index.js';
3
+ import { MetaRepository } from './meta-repository.js';
4
+ /**
5
+ * Repository for posts (all content types).
6
+ *
7
+ * Handles CRUD, slug generation, sticky posts, and provides
8
+ * a MetaRepository instance for post metadata operations.
9
+ */
10
+ export class PostRepository {
11
+ db;
12
+ meta;
13
+ constructor(db) {
14
+ this.db = db;
15
+ const metaCols = {
16
+ metaId: postmeta.metaId,
17
+ objectId: postmeta.postId,
18
+ metaKey: postmeta.metaKey,
19
+ metaValue: postmeta.metaValue,
20
+ metaValueJson: postmeta.metaValueJson,
21
+ };
22
+ const colNames = {
23
+ table: 'postmeta',
24
+ sql: { metaId: 'meta_id', objectId: 'post_id', metaKey: 'meta_key', metaValue: 'meta_value', metaValueJson: 'meta_value_json' },
25
+ ts: { metaId: 'metaId', objectId: 'postId', metaKey: 'metaKey', metaValue: 'metaValue', metaValueJson: 'metaValueJson' },
26
+ };
27
+ this.meta = new MetaRepository(db, postmeta, metaCols, colNames);
28
+ }
29
+ /**
30
+ * Create a new post.
31
+ */
32
+ async create(input) {
33
+ const postName = input.postName || this.generateSlug(input.postTitle);
34
+ const uniqueSlug = await this.ensureUniqueSlug(postName, input.postType ?? 'post');
35
+ const now = new Date();
36
+ const [row] = await this.db
37
+ .insert(posts)
38
+ .values({
39
+ postAuthor: input.postAuthor,
40
+ postTitle: input.postTitle,
41
+ postContent: input.postContent ?? '',
42
+ postExcerpt: input.postExcerpt ?? '',
43
+ postStatus: input.postStatus ?? 'draft',
44
+ postName: uniqueSlug,
45
+ postType: input.postType ?? 'post',
46
+ postParent: input.postParent ?? 0,
47
+ postPassword: input.postPassword ?? '',
48
+ commentStatus: input.commentStatus ?? 'open',
49
+ pingStatus: input.pingStatus ?? 'open',
50
+ postMimeType: input.postMimeType ?? '',
51
+ menuOrder: input.menuOrder ?? 0,
52
+ guid: input.guid ?? '',
53
+ postDate: now,
54
+ postDateGmt: now,
55
+ postModified: now,
56
+ postModifiedGmt: now,
57
+ })
58
+ .returning();
59
+ return row;
60
+ }
61
+ /**
62
+ * Get a post by ID.
63
+ */
64
+ async getById(id) {
65
+ const rows = await this.db.select().from(posts).where(eq(posts.id, id)).limit(1);
66
+ return rows[0];
67
+ }
68
+ /**
69
+ * Get a post by slug and type.
70
+ */
71
+ async getBySlug(slug, postType = 'post') {
72
+ const rows = await this.db
73
+ .select()
74
+ .from(posts)
75
+ .where(and(eq(posts.postName, slug), eq(posts.postType, postType)))
76
+ .limit(1);
77
+ return rows[0];
78
+ }
79
+ /**
80
+ * Update a post. Returns the updated row or undefined if not found.
81
+ */
82
+ async update(id, input) {
83
+ const existing = await this.getById(id);
84
+ if (!existing)
85
+ return undefined;
86
+ const now = new Date();
87
+ const updateData = {
88
+ postModified: now,
89
+ postModifiedGmt: now,
90
+ };
91
+ if (input.postTitle !== undefined)
92
+ updateData['postTitle'] = input.postTitle;
93
+ if (input.postContent !== undefined)
94
+ updateData['postContent'] = input.postContent;
95
+ if (input.postExcerpt !== undefined)
96
+ updateData['postExcerpt'] = input.postExcerpt;
97
+ if (input.postStatus !== undefined)
98
+ updateData['postStatus'] = input.postStatus;
99
+ if (input.postType !== undefined)
100
+ updateData['postType'] = input.postType;
101
+ if (input.postParent !== undefined)
102
+ updateData['postParent'] = input.postParent;
103
+ if (input.postPassword !== undefined)
104
+ updateData['postPassword'] = input.postPassword;
105
+ if (input.commentStatus !== undefined)
106
+ updateData['commentStatus'] = input.commentStatus;
107
+ if (input.pingStatus !== undefined)
108
+ updateData['pingStatus'] = input.pingStatus;
109
+ if (input.menuOrder !== undefined)
110
+ updateData['menuOrder'] = input.menuOrder;
111
+ if (input.postName !== undefined) {
112
+ updateData['postName'] = await this.ensureUniqueSlug(input.postName, input.postType ?? existing.postType, id);
113
+ }
114
+ const [row] = await this.db
115
+ .update(posts)
116
+ .set(updateData)
117
+ .where(eq(posts.id, id))
118
+ .returning();
119
+ return row;
120
+ }
121
+ /**
122
+ * Trash a post (move to trash status, preserving original status in meta).
123
+ */
124
+ async trash(id) {
125
+ const existing = await this.getById(id);
126
+ if (!existing)
127
+ return undefined;
128
+ if (existing.postStatus === 'trash')
129
+ return existing;
130
+ // Save original status so it can be restored
131
+ await this.meta.update(id, '_trash_meta_status', existing.postStatus);
132
+ return this.update(id, { postStatus: 'trash' });
133
+ }
134
+ /**
135
+ * Restore a trashed post to its original status.
136
+ */
137
+ async untrash(id) {
138
+ const existing = await this.getById(id);
139
+ if (!existing || existing.postStatus !== 'trash')
140
+ return existing;
141
+ const originalStatus = await this.meta.get(id, '_trash_meta_status');
142
+ await this.meta.delete(id, '_trash_meta_status');
143
+ return this.update(id, { postStatus: originalStatus ?? 'draft' });
144
+ }
145
+ /**
146
+ * Permanently delete a post and all its metadata.
147
+ */
148
+ async deletePermanently(id) {
149
+ // Delete meta first (cascade should handle it but be explicit)
150
+ await this.meta.deleteAllForObject(id);
151
+ const result = await this.db
152
+ .delete(posts)
153
+ .where(eq(posts.id, id))
154
+ .returning({ id: posts.id });
155
+ return result.length > 0;
156
+ }
157
+ /**
158
+ * Get sticky post IDs.
159
+ */
160
+ async getStickyIds() {
161
+ const rows = await this.db
162
+ .select({ postId: postmeta.postId })
163
+ .from(postmeta)
164
+ .where(and(eq(postmeta.metaKey, '_sticky'), eq(postmeta.metaValue, '1')));
165
+ return rows.map((r) => r.postId);
166
+ }
167
+ /**
168
+ * Set a post as sticky or not.
169
+ */
170
+ async setSticky(id, sticky) {
171
+ if (sticky) {
172
+ await this.meta.update(id, '_sticky', '1');
173
+ }
174
+ else {
175
+ await this.meta.delete(id, '_sticky');
176
+ }
177
+ }
178
+ /**
179
+ * Check if a post is sticky.
180
+ */
181
+ async isSticky(id) {
182
+ const value = await this.meta.get(id, '_sticky');
183
+ return value === '1' || value === 1;
184
+ }
185
+ /**
186
+ * Count posts by type and status.
187
+ */
188
+ async countByStatus(postType = 'post') {
189
+ const rows = await this.db
190
+ .select({
191
+ status: posts.postStatus,
192
+ count: sql `count(*)::int`,
193
+ })
194
+ .from(posts)
195
+ .where(eq(posts.postType, postType))
196
+ .groupBy(posts.postStatus);
197
+ const result = {};
198
+ for (const row of rows) {
199
+ result[row.status] = row.count;
200
+ }
201
+ return result;
202
+ }
203
+ /**
204
+ * Generate a URL-safe slug from a title.
205
+ */
206
+ generateSlug(title) {
207
+ return title
208
+ .toLowerCase()
209
+ .normalize('NFD')
210
+ .replace(/[\u0300-\u036f]/g, '') // remove diacritics
211
+ .replace(/[^a-z0-9_\s-]/g, '')
212
+ .replace(/\s+/g, '-')
213
+ .replace(/-+/g, '-')
214
+ .replace(/^-|-$/g, '')
215
+ .substring(0, 200);
216
+ }
217
+ /**
218
+ * Ensure a slug is unique within a post type.
219
+ * Appends -2, -3, etc. if needed.
220
+ */
221
+ async ensureUniqueSlug(slug, postType, excludeId) {
222
+ let candidate = slug;
223
+ let suffix = 2;
224
+ while (true) {
225
+ const conditions = [eq(posts.postName, candidate), eq(posts.postType, postType)];
226
+ if (excludeId !== undefined) {
227
+ conditions.push(sql `${posts.id} != ${excludeId}`);
228
+ }
229
+ const existing = await this.db
230
+ .select({ id: posts.id })
231
+ .from(posts)
232
+ .where(and(...conditions))
233
+ .limit(1);
234
+ if (existing.length === 0)
235
+ return candidate;
236
+ candidate = `${slug}-${suffix}`;
237
+ suffix++;
238
+ }
239
+ }
240
+ }
241
+ //# sourceMappingURL=post-repository.js.map