@pgpm/inflection 0.4.0 → 0.5.0
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/Makefile
CHANGED
package/README.md
CHANGED
|
@@ -1,5 +1,465 @@
|
|
|
1
1
|
# @pgpm/inflection
|
|
2
2
|
|
|
3
|
-
String inflection utilities for PostgreSQL naming conventions
|
|
3
|
+
String inflection utilities for PostgreSQL naming conventions
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
`@pgpm/inflection` provides comprehensive string transformation functions for PostgreSQL, enabling seamless conversion between different naming conventions. This package is essential for code generation, schema introspection, and maintaining consistent naming patterns across your database. It includes pluralization, singularization, case conversion, and slugification utilities.
|
|
8
|
+
|
|
9
|
+
## Features
|
|
10
|
+
|
|
11
|
+
- **Case Conversion**: Transform between camelCase, PascalCase, snake_case, and kebab-case
|
|
12
|
+
- **Pluralization**: Convert singular words to plural forms with English grammar rules
|
|
13
|
+
- **Singularization**: Convert plural words to singular forms
|
|
14
|
+
- **Slugification**: Create URL-friendly slugs from strings
|
|
15
|
+
- **Rule-Based System**: Extensible inflection rules stored in database table
|
|
16
|
+
- **Uncountable Words**: Handles special cases like "sheep", "fish", "data"
|
|
17
|
+
- **Pure plpgsql**: No external dependencies required
|
|
18
|
+
|
|
19
|
+
## Installation
|
|
20
|
+
|
|
21
|
+
If you have `pgpm` installed:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
pgpm install @pgpm/inflection
|
|
25
|
+
pgpm deploy
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
This is a quick way to get started. The sections below provide more detailed installation options.
|
|
29
|
+
|
|
30
|
+
### Prerequisites
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
# Install pgpm globally
|
|
34
|
+
npm install -g pgpm
|
|
35
|
+
|
|
36
|
+
# Start PostgreSQL
|
|
37
|
+
pgpm docker start
|
|
38
|
+
|
|
39
|
+
# Set environment variables
|
|
40
|
+
eval "$(pgpm env)"
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Deploy
|
|
44
|
+
|
|
45
|
+
#### Option 1: Deploy by installing with pgpm
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
pgpm install @pgpm/inflection
|
|
49
|
+
pgpm deploy
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
#### Option 2: Deploy from Package Directory
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
cd packages/utils/inflection
|
|
56
|
+
pgpm deploy --createdb
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
#### Option 3: Deploy from Workspace Root
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
# Install workspace dependencies
|
|
63
|
+
pgpm install
|
|
64
|
+
|
|
65
|
+
# Deploy with dependencies
|
|
66
|
+
pgpm deploy mydb1 --yes --createdb
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Core Functions
|
|
70
|
+
|
|
71
|
+
### Case Conversion Functions
|
|
72
|
+
|
|
73
|
+
#### inflection.camel(text)
|
|
74
|
+
|
|
75
|
+
Convert string to camelCase.
|
|
76
|
+
|
|
77
|
+
```sql
|
|
78
|
+
SELECT inflection.camel('user_profile_image');
|
|
79
|
+
-- userProfileImage
|
|
80
|
+
|
|
81
|
+
SELECT inflection.camel('UserProfileImage');
|
|
82
|
+
-- userProfileImage
|
|
83
|
+
|
|
84
|
+
SELECT inflection.camel('user-profile-image');
|
|
85
|
+
-- userProfileImage
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
#### inflection.pascal(text)
|
|
89
|
+
|
|
90
|
+
Convert string to PascalCase.
|
|
91
|
+
|
|
92
|
+
```sql
|
|
93
|
+
SELECT inflection.pascal('user_profile_image');
|
|
94
|
+
-- UserProfileImage
|
|
95
|
+
|
|
96
|
+
SELECT inflection.pascal('user-profile-image');
|
|
97
|
+
-- UserProfileImage
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
#### inflection.underscore(text)
|
|
101
|
+
|
|
102
|
+
Convert string to snake_case.
|
|
103
|
+
|
|
104
|
+
```sql
|
|
105
|
+
SELECT inflection.underscore('UserProfileImage');
|
|
106
|
+
-- user_profile_image
|
|
107
|
+
|
|
108
|
+
SELECT inflection.underscore('userProfileImage');
|
|
109
|
+
-- user_profile_image
|
|
110
|
+
|
|
111
|
+
SELECT inflection.underscore('user-profile-image');
|
|
112
|
+
-- user_profile_image
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
#### inflection.dashed(text)
|
|
116
|
+
|
|
117
|
+
Convert string to kebab-case.
|
|
118
|
+
|
|
119
|
+
```sql
|
|
120
|
+
SELECT inflection.dashed('UserProfileImage');
|
|
121
|
+
-- user-profile-image
|
|
122
|
+
|
|
123
|
+
SELECT inflection.dashed('user_profile_image');
|
|
124
|
+
-- user-profile-image
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### Pluralization Functions
|
|
128
|
+
|
|
129
|
+
#### inflection.plural(text)
|
|
130
|
+
|
|
131
|
+
Convert singular word to plural form.
|
|
132
|
+
|
|
133
|
+
```sql
|
|
134
|
+
SELECT inflection.plural('user');
|
|
135
|
+
-- users
|
|
136
|
+
|
|
137
|
+
SELECT inflection.plural('person');
|
|
138
|
+
-- people
|
|
139
|
+
|
|
140
|
+
SELECT inflection.plural('child');
|
|
141
|
+
-- children
|
|
142
|
+
|
|
143
|
+
SELECT inflection.plural('category');
|
|
144
|
+
-- categories
|
|
145
|
+
|
|
146
|
+
SELECT inflection.plural('status');
|
|
147
|
+
-- statuses
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
#### inflection.singular(text)
|
|
151
|
+
|
|
152
|
+
Convert plural word to singular form.
|
|
153
|
+
|
|
154
|
+
```sql
|
|
155
|
+
SELECT inflection.singular('users');
|
|
156
|
+
-- user
|
|
157
|
+
|
|
158
|
+
SELECT inflection.singular('people');
|
|
159
|
+
-- person
|
|
160
|
+
|
|
161
|
+
SELECT inflection.singular('children');
|
|
162
|
+
-- child
|
|
163
|
+
|
|
164
|
+
SELECT inflection.singular('categories');
|
|
165
|
+
-- category
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### Slugification Functions
|
|
169
|
+
|
|
170
|
+
#### inflection.slugify(text)
|
|
171
|
+
|
|
172
|
+
Create URL-friendly slug from string.
|
|
173
|
+
|
|
174
|
+
```sql
|
|
175
|
+
SELECT inflection.slugify('Hello World!');
|
|
176
|
+
-- hello-world
|
|
177
|
+
|
|
178
|
+
SELECT inflection.slugify('User Profile & Settings');
|
|
179
|
+
-- user-profile-settings
|
|
180
|
+
|
|
181
|
+
SELECT inflection.slugify(' Multiple Spaces ');
|
|
182
|
+
-- multiple-spaces
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
## Usage Examples
|
|
186
|
+
|
|
187
|
+
### Database Schema Generation
|
|
188
|
+
|
|
189
|
+
Generate table and column names following conventions:
|
|
190
|
+
|
|
191
|
+
```sql
|
|
192
|
+
-- Convert API field names to database columns
|
|
193
|
+
CREATE TABLE users (
|
|
194
|
+
id uuid PRIMARY KEY,
|
|
195
|
+
user_name text, -- from userName
|
|
196
|
+
email_address text, -- from emailAddress
|
|
197
|
+
created_at timestamptz DEFAULT now()
|
|
198
|
+
);
|
|
199
|
+
|
|
200
|
+
-- Function to convert camelCase to snake_case
|
|
201
|
+
CREATE FUNCTION api_to_db_column(field_name text)
|
|
202
|
+
RETURNS text AS $$
|
|
203
|
+
BEGIN
|
|
204
|
+
RETURN inflection.underscore(field_name);
|
|
205
|
+
END;
|
|
206
|
+
$$ LANGUAGE plpgsql;
|
|
207
|
+
|
|
208
|
+
SELECT api_to_db_column('firstName'); -- first_name
|
|
209
|
+
SELECT api_to_db_column('emailAddress'); -- email_address
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
### GraphQL Schema Generation
|
|
213
|
+
|
|
214
|
+
Generate GraphQL type names from database tables:
|
|
215
|
+
|
|
216
|
+
```sql
|
|
217
|
+
-- Convert table names to GraphQL types
|
|
218
|
+
SELECT inflection.pascal(inflection.singular(table_name)) as graphql_type
|
|
219
|
+
FROM information_schema.tables
|
|
220
|
+
WHERE table_schema = 'public';
|
|
221
|
+
|
|
222
|
+
-- user_profiles → UserProfile
|
|
223
|
+
-- blog_posts → BlogPost
|
|
224
|
+
-- categories → Category
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
### REST API Endpoint Generation
|
|
228
|
+
|
|
229
|
+
Create consistent API endpoints:
|
|
230
|
+
|
|
231
|
+
```sql
|
|
232
|
+
-- Generate REST endpoints from table names
|
|
233
|
+
SELECT
|
|
234
|
+
'/' || inflection.dashed(inflection.plural(table_name)) as endpoint,
|
|
235
|
+
table_name
|
|
236
|
+
FROM information_schema.tables
|
|
237
|
+
WHERE table_schema = 'public';
|
|
238
|
+
|
|
239
|
+
-- users → /users
|
|
240
|
+
-- blog_posts → /blog-posts
|
|
241
|
+
-- user_profiles → /user-profiles
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
### Code Generation
|
|
245
|
+
|
|
246
|
+
Generate TypeScript interfaces from database schema:
|
|
247
|
+
|
|
248
|
+
```sql
|
|
249
|
+
-- Generate TypeScript interface names
|
|
250
|
+
CREATE FUNCTION generate_ts_interface(table_name text)
|
|
251
|
+
RETURNS text AS $$
|
|
252
|
+
BEGIN
|
|
253
|
+
RETURN 'export interface ' ||
|
|
254
|
+
inflection.pascal(inflection.singular(table_name)) ||
|
|
255
|
+
' {';
|
|
256
|
+
END;
|
|
257
|
+
$$ LANGUAGE plpgsql;
|
|
258
|
+
|
|
259
|
+
SELECT generate_ts_interface('user_profiles');
|
|
260
|
+
-- export interface UserProfile {
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
### URL Slug Generation
|
|
264
|
+
|
|
265
|
+
Create SEO-friendly URLs:
|
|
266
|
+
|
|
267
|
+
```sql
|
|
268
|
+
-- Generate slugs for blog posts
|
|
269
|
+
CREATE TABLE blog_posts (
|
|
270
|
+
id serial PRIMARY KEY,
|
|
271
|
+
title text NOT NULL,
|
|
272
|
+
slug text GENERATED ALWAYS AS (inflection.slugify(title)) STORED,
|
|
273
|
+
content text,
|
|
274
|
+
created_at timestamptz DEFAULT now()
|
|
275
|
+
);
|
|
276
|
+
|
|
277
|
+
INSERT INTO blog_posts (title, content)
|
|
278
|
+
VALUES ('How to Use PostgreSQL', 'Content here...');
|
|
279
|
+
|
|
280
|
+
SELECT slug FROM blog_posts;
|
|
281
|
+
-- how-to-use-postgresql
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
## Integration Examples
|
|
285
|
+
|
|
286
|
+
### With @pgpm/meta-db
|
|
287
|
+
|
|
288
|
+
Use inflection for schema introspection and code generation:
|
|
289
|
+
|
|
290
|
+
```sql
|
|
291
|
+
-- Generate model names from tables
|
|
292
|
+
SELECT
|
|
293
|
+
table_name,
|
|
294
|
+
inflection.pascal(inflection.singular(table_name)) as model_name,
|
|
295
|
+
inflection.camel(inflection.plural(table_name)) as collection_name
|
|
296
|
+
FROM information_schema.tables
|
|
297
|
+
WHERE table_schema = 'public';
|
|
298
|
+
|
|
299
|
+
-- user_profiles → UserProfile (model), userProfiles (collection)
|
|
300
|
+
-- blog_posts → BlogPost (model), blogPosts (collection)
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
### With @pgpm/utils
|
|
304
|
+
|
|
305
|
+
Combine with other utilities for advanced transformations:
|
|
306
|
+
|
|
307
|
+
```sql
|
|
308
|
+
-- Generate API response field names
|
|
309
|
+
SELECT
|
|
310
|
+
column_name,
|
|
311
|
+
inflection.camel(column_name) as api_field_name
|
|
312
|
+
FROM information_schema.columns
|
|
313
|
+
WHERE table_name = 'users';
|
|
314
|
+
|
|
315
|
+
-- user_name → userName
|
|
316
|
+
-- email_address → emailAddress
|
|
317
|
+
-- created_at → createdAt
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
## Inflection Rules
|
|
321
|
+
|
|
322
|
+
The package uses a rule-based system stored in the `inflection.inflection_rules` table:
|
|
323
|
+
|
|
324
|
+
```sql
|
|
325
|
+
-- View pluralization rules
|
|
326
|
+
SELECT * FROM inflection.inflection_rules WHERE type = 'plural';
|
|
327
|
+
|
|
328
|
+
-- View singularization rules
|
|
329
|
+
SELECT * FROM inflection.inflection_rules WHERE type = 'singular';
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
### Adding Custom Rules
|
|
333
|
+
|
|
334
|
+
You can extend the inflection system with custom rules:
|
|
335
|
+
|
|
336
|
+
```sql
|
|
337
|
+
-- Add custom pluralization rule
|
|
338
|
+
INSERT INTO inflection.inflection_rules (type, test, replacement)
|
|
339
|
+
VALUES ('plural', '(ox)$', '\1en');
|
|
340
|
+
|
|
341
|
+
-- Now "ox" → "oxen"
|
|
342
|
+
SELECT inflection.plural('ox');
|
|
343
|
+
-- oxen
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
### Uncountable Words
|
|
347
|
+
|
|
348
|
+
Some words don't change between singular and plural:
|
|
349
|
+
|
|
350
|
+
```sql
|
|
351
|
+
SELECT inflection.plural('sheep');
|
|
352
|
+
-- sheep
|
|
353
|
+
|
|
354
|
+
SELECT inflection.plural('fish');
|
|
355
|
+
-- fish
|
|
356
|
+
|
|
357
|
+
SELECT inflection.plural('data');
|
|
358
|
+
-- data
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
## Use Cases
|
|
362
|
+
|
|
363
|
+
- **ORM Code Generation**: Generate model classes from database tables
|
|
364
|
+
- **API Development**: Convert between database and API naming conventions
|
|
365
|
+
- **GraphQL Schema**: Generate GraphQL types from database schema
|
|
366
|
+
- **Documentation**: Create consistent naming in generated documentation
|
|
367
|
+
- **Migration Scripts**: Transform legacy naming to modern conventions
|
|
368
|
+
- **URL Generation**: Create SEO-friendly slugs for content
|
|
369
|
+
- **Multi-Language Support**: Handle naming conventions across different programming languages
|
|
370
|
+
|
|
371
|
+
## Testing
|
|
372
|
+
|
|
373
|
+
```bash
|
|
374
|
+
pnpm test
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
## Dependencies
|
|
378
|
+
|
|
379
|
+
- `@pgpm/verify`: Verification utilities
|
|
380
|
+
|
|
381
|
+
## Development
|
|
382
|
+
|
|
383
|
+
See the [Development](#development-1) section below for information on working with this package.
|
|
384
|
+
|
|
385
|
+
---
|
|
386
|
+
|
|
387
|
+
## Development
|
|
388
|
+
|
|
389
|
+
### **Before You Begin**
|
|
390
|
+
|
|
391
|
+
```bash
|
|
392
|
+
# 1. Install pgpm
|
|
393
|
+
npm install -g pgpm
|
|
394
|
+
|
|
395
|
+
# 2. Start Postgres (Docker or local)
|
|
396
|
+
pgpm docker start
|
|
397
|
+
|
|
398
|
+
# 3. Load PG* environment variables (PGHOST, PGUSER, ...)
|
|
399
|
+
eval "$(pgpm env)"
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
---
|
|
403
|
+
|
|
404
|
+
### **Starting a New Project**
|
|
405
|
+
|
|
406
|
+
```bash
|
|
407
|
+
# 1. Create a workspace
|
|
408
|
+
pgpm init --workspace
|
|
409
|
+
cd my-app
|
|
410
|
+
|
|
411
|
+
# 2. Create your first module
|
|
412
|
+
pgpm init
|
|
413
|
+
|
|
414
|
+
# 3. Add a migration
|
|
415
|
+
pgpm add some_change
|
|
416
|
+
|
|
417
|
+
# 4. Deploy (auto-creates database)
|
|
418
|
+
pgpm deploy --createdb
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
---
|
|
422
|
+
|
|
423
|
+
### **Working With an Existing Project**
|
|
424
|
+
|
|
425
|
+
```bash
|
|
426
|
+
# 1. Clone and enter the project
|
|
427
|
+
git clone <repo> && cd <project>
|
|
428
|
+
|
|
429
|
+
# 2. Install dependencies
|
|
430
|
+
pnpm install
|
|
431
|
+
|
|
432
|
+
# 3. Deploy locally
|
|
433
|
+
pgpm deploy --createdb
|
|
434
|
+
```
|
|
435
|
+
|
|
436
|
+
---
|
|
437
|
+
|
|
438
|
+
### **Testing a Module Inside a Workspace**
|
|
439
|
+
|
|
440
|
+
```bash
|
|
441
|
+
# 1. Install workspace deps
|
|
442
|
+
pnpm install
|
|
443
|
+
|
|
444
|
+
# 2. Enter the module directory
|
|
445
|
+
cd packages/<some-module>
|
|
446
|
+
|
|
447
|
+
# 3. Run tests in watch mode
|
|
448
|
+
pnpm test:watch
|
|
449
|
+
```
|
|
450
|
+
|
|
451
|
+
## Related Tooling
|
|
452
|
+
|
|
453
|
+
* [pgpm](https://github.com/launchql/launchql/tree/main/packages/pgpm): **🖥️ PostgreSQL Package Manager** for modular Postgres development. Works with database workspaces, scaffolding, migrations, seeding, and installing database packages.
|
|
454
|
+
* [pgsql-test](https://github.com/launchql/launchql/tree/main/packages/pgsql-test): **📊 Isolated testing environments** with per-test transaction rollbacks—ideal for integration tests, complex migrations, and RLS simulation.
|
|
455
|
+
* [supabase-test](https://github.com/launchql/launchql/tree/main/packages/supabase-test): **🧪 Supabase-native test harness** preconfigured for the local Supabase stack—per-test rollbacks, JWT/role context helpers, and CI/GitHub Actions ready.
|
|
456
|
+
* [graphile-test](https://github.com/launchql/launchql/tree/main/packages/graphile-test): **🔐 Authentication mocking** for Graphile-focused test helpers and emulating row-level security contexts.
|
|
457
|
+
* [pgsql-parser](https://github.com/launchql/pgsql-parser): **🔄 SQL conversion engine** that interprets and converts PostgreSQL syntax.
|
|
458
|
+
* [libpg-query-node](https://github.com/launchql/libpg-query-node): **🌉 Node.js bindings** for `libpg_query`, converting SQL into parse trees.
|
|
459
|
+
* [pg-proto-parser](https://github.com/launchql/pg-proto-parser): **📦 Protobuf parser** for parsing PostgreSQL Protocol Buffers definitions to generate TypeScript interfaces, utility functions, and JSON mappings for enums.
|
|
460
|
+
|
|
461
|
+
## Disclaimer
|
|
462
|
+
|
|
463
|
+
AS DESCRIBED IN THE LICENSES, THE SOFTWARE IS PROVIDED "AS IS", AT YOUR OWN RISK, AND WITHOUT WARRANTIES OF ANY KIND.
|
|
464
|
+
|
|
465
|
+
No developer or entity involved in creating this software will be liable for any claims or damages whatsoever associated with your use, inability to use, or your interaction with other users of the code, including any direct, indirect, incidental, special, exemplary, punitive or consequential damages, or loss of profits, cryptocurrencies, tokens, or anything else of value.
|
package/package.json
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pgpm/inflection",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "String inflection utilities for PostgreSQL naming conventions",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
8
8
|
"scripts": {
|
|
9
|
-
"bundle": "
|
|
9
|
+
"bundle": "pgpm package",
|
|
10
10
|
"test": "jest",
|
|
11
11
|
"test:watch": "jest --watch"
|
|
12
12
|
},
|
|
13
13
|
"dependencies": {
|
|
14
|
-
"@pgpm/verify": "0.
|
|
14
|
+
"@pgpm/verify": "0.5.0"
|
|
15
15
|
},
|
|
16
16
|
"devDependencies": {
|
|
17
|
-
"
|
|
17
|
+
"pgpm": "^0.2.0"
|
|
18
18
|
},
|
|
19
19
|
"repository": {
|
|
20
20
|
"type": "git",
|
|
@@ -24,5 +24,5 @@
|
|
|
24
24
|
"bugs": {
|
|
25
25
|
"url": "https://github.com/launchql/extensions/issues"
|
|
26
26
|
},
|
|
27
|
-
"gitHead": "
|
|
27
|
+
"gitHead": "d8eedbb24ad22a106634bc3b919bfb8d41976c16"
|
|
28
28
|
}
|
|
File without changes
|
|
File without changes
|