@newcms/database 0.0.1 → 0.0.2

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.
Files changed (2) hide show
  1. package/README.md +168 -0
  2. package/package.json +3 -2
package/README.md ADDED
@@ -0,0 +1,168 @@
1
+ # @newcms/database
2
+
3
+ Database schema, Redis object cache, and repositories for [NewCMS](https://github.com/durvs/newcms) — a modern, TypeScript-first content management system.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @newcms/database
9
+ ```
10
+
11
+ **Requirements:** PostgreSQL 17+ and Redis 7+.
12
+
13
+ ## Database Schema
14
+
15
+ Type-safe [Drizzle ORM](https://orm.drizzle.team/) schema with 14 tables covering the full CMS data model:
16
+
17
+ ```typescript
18
+ import {
19
+ posts, postmeta,
20
+ users, usermeta,
21
+ comments, commentmeta,
22
+ terms, termTaxonomy, termRelationships, termmeta,
23
+ options,
24
+ links,
25
+ sessions,
26
+ scheduledEvents,
27
+ } from '@newcms/database/schema';
28
+ ```
29
+
30
+ ### Tables
31
+
32
+ | Table | Purpose |
33
+ |-------|---------|
34
+ | `posts` | All content types (posts, pages, attachments, custom types) |
35
+ | `postmeta` | Post metadata (EAV with JSONB support) |
36
+ | `users` | User accounts |
37
+ | `usermeta` | User metadata |
38
+ | `comments` | Threaded comments |
39
+ | `commentmeta` | Comment metadata |
40
+ | `terms` | Taxonomy terms |
41
+ | `term_taxonomy` | Term-taxonomy relationships with hierarchy |
42
+ | `term_relationships` | Object-term assignments |
43
+ | `termmeta` | Term metadata |
44
+ | `options` | Site settings (with autoload and JSONB) |
45
+ | `links` | Blogroll / link manager |
46
+ | `sessions` | User sessions (Redis-backed with DB fallback) |
47
+ | `scheduled_events` | Cron-like scheduled tasks (BullMQ-backed) |
48
+
49
+ ### Key Design Decisions
50
+
51
+ - **JSONB columns** on all meta tables — queryable structured data instead of opaque serialized text
52
+ - **GIN indexes** on JSONB columns for efficient structured queries
53
+ - **Composite indexes** on frequently queried combinations (e.g., `post_type + status + date`)
54
+ - **Dedicated tables** for sessions and scheduled events (instead of serialized blobs in options/usermeta)
55
+
56
+ ## Connection
57
+
58
+ ```typescript
59
+ import { createConnection } from '@newcms/database';
60
+
61
+ // From environment variables (DB_HOST, DB_PORT, DB_NAME, DB_USER, DB_PASSWORD)
62
+ const { db, client } = createConnection();
63
+
64
+ // Or with explicit config
65
+ const { db, client } = createConnection({
66
+ host: 'localhost',
67
+ port: 5432,
68
+ database: 'newcms',
69
+ user: 'newcms',
70
+ password: 'your-secure-password',
71
+ });
72
+
73
+ // Use Drizzle query builder
74
+ const allPosts = await db.select().from(posts);
75
+ ```
76
+
77
+ **Note:** `DB_PASSWORD` is required — there is no default. Set it in your environment or `.env` file.
78
+
79
+ ## Object Cache
80
+
81
+ Redis-backed object cache with group isolation, TTL, and multisite support:
82
+
83
+ ```typescript
84
+ import { ObjectCache } from '@newcms/database';
85
+
86
+ const cache = new ObjectCache({
87
+ host: 'localhost',
88
+ port: 6379,
89
+ });
90
+ await cache.connect();
91
+
92
+ // Basic get/set
93
+ await cache.set('my_key', { hello: 'world' }, 'my_group');
94
+ const value = await cache.get('my_key', 'my_group');
95
+
96
+ // TTL (in seconds)
97
+ await cache.set('temp', 'data', 'default', 300); // expires in 5 min
98
+
99
+ // Batch operations (uses Redis pipeline)
100
+ await cache.setMultiple({ a: 1, b: 2, c: 3 }, 'counters');
101
+ const results = await cache.getMultiple(['a', 'b', 'c'], 'counters');
102
+
103
+ // Increment/decrement
104
+ await cache.set('views', 0);
105
+ await cache.incr('views'); // => 1
106
+
107
+ // Group-level TTL
108
+ cache.setGroupTtl('transients', 3600); // 1 hour for all transients
109
+
110
+ // Multisite: global groups shared across sites
111
+ cache.addGlobalGroups(['users', 'site-options']);
112
+ cache.setSiteId(2); // switch site context
113
+
114
+ // Flush
115
+ await cache.flushGroup('posts'); // flush one group
116
+ await cache.flushAll(); // flush everything
117
+ ```
118
+
119
+ ## Options Repository
120
+
121
+ CRUD for site options with integrated Redis cache:
122
+
123
+ ```typescript
124
+ import { createConnection, ObjectCache, OptionsRepository } from '@newcms/database';
125
+
126
+ const { db } = createConnection();
127
+ const cache = new ObjectCache({ host: 'localhost', port: 6379 });
128
+ await cache.connect();
129
+
130
+ const options = new OptionsRepository(db, cache);
131
+
132
+ // Read (with cache — hits DB only on first read)
133
+ const siteName = await options.getOption('blogname');
134
+ const perPage = await options.getOption('posts_per_page', 10); // with default
135
+
136
+ // Write (invalidates cache automatically)
137
+ await options.updateOption('blogname', 'My New Site');
138
+ await options.addOption('custom_setting', { enabled: true, threshold: 50 });
139
+
140
+ // Delete
141
+ await options.deleteOption('old_setting');
142
+
143
+ // Bootstrap: pre-load all autoloaded options into cache
144
+ const allOptions = await options.loadAutoloadedOptions();
145
+ ```
146
+
147
+ ### Cache Behavior
148
+
149
+ - **Autoloaded options** are bulk-loaded into Redis on bootstrap
150
+ - **Cache-aside pattern** — reads check cache first, fall back to DB
151
+ - **Not-found caching** — missing keys are cached to prevent repeated DB misses
152
+ - **Granular invalidation** — writes invalidate only the affected key
153
+ - **JSONB** — complex values (objects, arrays) stored in queryable JSONB column
154
+
155
+ ## Environment Variables
156
+
157
+ | Variable | Required | Default | Description |
158
+ |----------|----------|---------|-------------|
159
+ | `DB_HOST` | No | `localhost` | PostgreSQL host |
160
+ | `DB_PORT` | No | `5432` | PostgreSQL port |
161
+ | `DB_NAME` | No | `newcms` | Database name |
162
+ | `DB_USER` | No | `newcms` | Database user |
163
+ | `DB_PASSWORD` | **Yes** | — | Database password |
164
+ | `DB_MAX_CONNECTIONS` | No | `10` | Connection pool size |
165
+
166
+ ## License
167
+
168
+ GPL-2.0-or-later
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@newcms/database",
3
- "version": "0.0.1",
3
+ "version": "0.0.2",
4
4
  "type": "module",
5
5
  "description": "Database schema, object cache, and repositories for NewCMS",
6
6
  "license": "GPL-2.0-or-later",
@@ -29,7 +29,8 @@
29
29
  }
30
30
  },
31
31
  "files": [
32
- "dist"
32
+ "dist",
33
+ "README.md"
33
34
  ],
34
35
  "dependencies": {
35
36
  "drizzle-orm": "^0.44.2",