Skip to content

Commit a3206e1

Browse files
committed
refactor: Contentrain Nuxt JSON readme update and playground fix
- Playground için otomatik olarak oluşturulan tür tanımlarını kaldırma - İçe aktarılan tür tanımlarını `#build/types/contentrain` olarak güncelleme - Gereksiz bağımlılıkları `package.json` ve `pnpm-lock.yaml`'den çıkarma - Sayfa bileşenlerinde tür güvenliğini ve veri erişimini iyileştirme
1 parent 52ce715 commit a3206e1

File tree

6 files changed

+81
-270
lines changed

6 files changed

+81
-270
lines changed

packages/nuxt-json/README.md

Lines changed: 59 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,12 @@
1111
## Features
1212

1313
- 🚀 **High Performance**: Optimized query engine and caching system
14-
- 🔒 **Type Safety**: Full TypeScript integration and type support
14+
- 🔒 **Type Safety**: Full TypeScript integration and automatic type generation
1515
- 🔄 **Relational Data**: Easily manage relationships between models
1616
- 🌐 **Multilingual Support**: Complete support for localized content
1717
- 📊 **Advanced Querying**: Filtering, sorting, and pagination capabilities
1818
- 🧩 **Seamless Integration**: Effortless integration with Nuxt.js
19+
- 🔄 **Automatic Type Generation**: TypeScript interfaces generated from your content models
1920

2021
## Installation
2122

@@ -56,7 +57,8 @@ Query content in your pages or components:
5657

5758
```vue
5859
<script setup>
59-
import type { WorkItem } from '~/types'
60+
// Automatically generated types from your content models
61+
import type { WorkItem } from '#build/types/contentrain'
6062
6163
// Basic query
6264
const workQuery = useContentrainQuery<WorkItem>('work-items')
@@ -229,7 +231,27 @@ const hasMore = query.hasMore
229231

230232
## Type Safety
231233

232-
For full TypeScript integration, define your content types:
234+
### Automatic Type Generation
235+
236+
The module automatically generates TypeScript types from your content models during the build process. These types are available in your project via the `#build/types/contentrain` import path:
237+
238+
```ts
239+
// Import automatically generated types
240+
import type { Post, Author, Category } from '#build/types/contentrain'
241+
242+
// Use the types in your queries
243+
const query = useContentrainQuery<Post>('posts')
244+
```
245+
246+
The generated types include:
247+
- All model properties with correct types
248+
- Relation properties with proper typing
249+
- Multilingual support with language-specific types
250+
- Full IntelliSense support in your IDE
251+
252+
### Manual Type Definitions
253+
254+
You can also define your content types manually if needed:
233255

234256
```ts
235257
// types/content.ts
@@ -266,12 +288,12 @@ The main composable for querying content.
266288
- `modelId`: Model ID
267289

268290
**Methods:**
269-
- `where(field, operator, value)`: Adds a filter
270-
- `orderBy(field, direction)`: Adds a sort
291+
- `where(field, operator, value)`: Adds a filter with type-safe field and value checking
292+
- `orderBy(field, direction)`: Adds a sort with type-safe field checking
271293
- `limit(limit)`: Limits the number of results
272294
- `offset(offset)`: Sets the starting index
273-
- `include(relation)`: Includes a relation
274-
- `locale(locale)`: Sets the language
295+
- `include(relation)`: Includes a relation with type-safe relation checking
296+
- `locale(locale)`: Sets the language with type-safe locale checking (only accepts valid locales defined in your model)
275297
- `get()`: Executes the query and returns the results
276298
- `first()`: Returns the first result
277299
- `count()`: Returns the total count
@@ -593,6 +615,36 @@ Query parameters are invalid.
593615

594616
**Solution:** Ensure that your query parameters are in the correct format.
595617

618+
### TypeScript Errors
619+
620+
#### `Argument of type 'string' is not assignable to parameter of type 'never'`
621+
622+
This error occurs when using the `locale()` method with a locale that is not defined in your model.
623+
624+
**Solution:** Make sure you're using a locale that is defined in your model's `_lang` property. For example, if your model only supports 'en' and 'tr', you can only use these values with the `locale()` method.
625+
626+
```ts
627+
// Correct usage
628+
query.locale('en') // Works if 'en' is defined in your model
629+
query.locale('tr') // Works if 'tr' is defined in your model
630+
631+
// Incorrect usage
632+
query.locale('fr') // TypeScript error if 'fr' is not defined in your model
633+
```
634+
635+
#### `Property '_relations' does not exist on type...`
636+
637+
This error occurs when trying to access relations on a model that doesn't have any defined relations.
638+
639+
**Solution:** Make sure your model has relations defined in its schema, or check if the relation is properly included in your query using the `include()` method.
640+
641+
```ts
642+
// Make sure to include the relation before accessing it
643+
const query = useContentrainQuery<Post>('posts')
644+
.include('author')
645+
.get()
646+
```
647+
596648
## Contributing
597649

598650
We welcome your contributions! Please read our [contribution guidelines](CONTRIBUTING.md).

playground/nuxt/package.json

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,7 @@
1212
"clean": "rm -rf .output && rm -rf node_modules && rm -rf .nuxt "
1313
},
1414
"dependencies": {
15-
"@contentrain/nuxt": "workspace:*",
1615
"@contentrain/nuxt-json": "workspace:*",
17-
"@contentrain/query": "workspace:*",
18-
"@contentrain/types-generator": "workspace:*",
1916
"@nuxtjs/tailwindcss": "^6.13.1",
2017
"nuxt": "^3.15.4",
2118
"unstorage": "^1.15.0",

playground/nuxt/pages/index.vue

Lines changed: 16 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -1,60 +1,5 @@
11
<script setup lang="ts">
2-
import type { Content, LocalizedContent, QueryResult } from '@contentrain/nuxt-json';
3-
4-
interface IWorkItem extends LocalizedContent {
5-
title: string
6-
description: string
7-
image: string
8-
category: string
9-
link: string
10-
order: number
11-
_lang: 'tr' | 'en'
12-
_relations: {
13-
category: IWorkCategory
14-
}
15-
}
16-
17-
interface IWorkCategory extends LocalizedContent {
18-
category: string
19-
order: number
20-
_lang: 'tr' | 'en'
21-
}
22-
23-
interface ITabItem extends LocalizedContent {
24-
title: string
25-
description: string
26-
order: number
27-
category: string
28-
_lang: 'tr' | 'en'
29-
_relations: {
30-
category: IWorkCategory[]
31-
}
32-
}
33-
34-
interface ITestimonialItem extends LocalizedContent {
35-
'name': string
36-
'description': string
37-
'title': string
38-
'image': string
39-
'creative-work': string
40-
'_lang': 'tr' | 'en'
41-
'_relations': {
42-
'creative-work': IWorkItem
43-
}
44-
}
45-
46-
interface IFaqItem extends LocalizedContent {
47-
question: string
48-
answer: string
49-
order: number
50-
_lang: 'tr' | 'en'
51-
}
52-
53-
interface ISocialLink extends Content {
54-
icon: string
55-
link: string
56-
service: string
57-
}
2+
import type { FaqItems, SocialLinks, TabItems, TestimonialItems, WorkItems } from '#build/types/contentrain';
583
594
// Debug için
605
console.log('=== APP.VUE SETUP START ===');
@@ -80,24 +25,24 @@ const { data: pagedWorkItems } = await useAsyncData('paged-work-items', () =>
8025
8126
// === 2. İlişki Sorguları ===
8227
// 2.1 Bire-Bir İlişki
83-
const { data: testimonials } = await useAsyncData<QueryResult<ITestimonialItem>>('testimonials', () =>
84-
useContentrainQuery<ITestimonialItem>('testimonial-items')
28+
const { data: testimonials } = await useAsyncData('testimonials', () =>
29+
useContentrainQuery<TestimonialItems>('testimonial-items')
8530
.locale('tr')
8631
.include('creative-work')
8732
.get());
8833
8934
// 2.2 Bire-Çok İlişki
90-
const { data: tabItems } = await useAsyncData<QueryResult<ITabItem>>('tab-items', () =>
91-
useContentrainQuery<ITabItem>('tabitems')
35+
const { data: tabItems } = await useAsyncData('tab-items', () =>
36+
useContentrainQuery<TabItems>('tabitems')
9237
.locale('tr')
9338
.where('status', 'eq', 'publish')
9439
.include('category')
9540
.get());
9641
9742
// === 3. Gelişmiş Sorgular ===
9843
// 3.1 Çoklu Filtreler
99-
const { data: advancedFilteredItems } = await useAsyncData<QueryResult<IWorkItem>>('advanced-filtered-items', () =>
100-
useContentrainQuery<IWorkItem>('workitems')
44+
const { data: advancedFilteredItems } = await useAsyncData('advanced-filtered-items', () =>
45+
useContentrainQuery<WorkItems>('workitems')
10146
.where('status', 'eq', 'publish')
10247
.where('order', 'gt', 2)
10348
.where('order', 'lt', 6)
@@ -107,15 +52,15 @@ const { data: advancedFilteredItems } = await useAsyncData<QueryResult<IWorkItem
10752
.get());
10853
10954
// 3.2 Dizi Operatörleri
110-
const { data: arrayFilteredItems } = await useAsyncData<QueryResult<IWorkItem>>('array-filtered-items', () =>
111-
useContentrainQuery<IWorkItem>('workitems')
55+
const { data: arrayFilteredItems } = await useAsyncData('array-filtered-items', () =>
56+
useContentrainQuery<WorkItems>('workitems')
11257
.where('status', 'ne', 'draft')
11358
.locale('tr')
11459
.get());
11560
11661
// 3.3 Array Operatörü Örneği
11762
const { data: specificSocialLinks } = await useAsyncData('specific-social-links', () =>
118-
useContentrainQuery<ISocialLink>('sociallinks')
63+
useContentrainQuery<SocialLinks>('sociallinks')
11964
.where('icon', 'in', ['ri-twitter-line', 'ri-instagram-line', 'ri-linkedin-line'] as unknown as string)
12065
.where('status', 'eq', 'publish')
12166
.orderBy('icon', 'asc')
@@ -124,32 +69,32 @@ const { data: specificSocialLinks } = await useAsyncData('specific-social-links'
12469
// === 4. Çoklu Dil Desteği ===
12570
// 4.1 Farklı Dillerde İçerik
12671
const { data: trContent } = await useAsyncData('tr-content', () =>
127-
useContentrainQuery<IWorkItem>('workitems')
72+
useContentrainQuery<WorkItems>('workitems')
12873
.locale('tr')
12974
.first());
13075
13176
const { data: enContent } = await useAsyncData('en-content', () =>
132-
useContentrainQuery<IWorkItem>('workitems')
77+
useContentrainQuery<WorkItems>('workitems')
13378
.locale('en')
13479
.first());
13580
13681
// 4.2 Lokalize Olmayan Model
13782
const { data: socialLinks } = await useAsyncData('social-links', () =>
138-
useContentrainQuery<ISocialLink>('sociallinks')
83+
useContentrainQuery<SocialLinks>('sociallinks')
13984
.where('status', 'eq', 'publish')
14085
.orderBy('icon', 'asc')
14186
.get());
14287
14388
const { data: socialLinks2 } = await useAsyncData('social-links-2', () =>
144-
useContentrainQuery<ISocialLink>('sociallinks')
89+
useContentrainQuery<SocialLinks>('sociallinks')
14590
.where('icon', 'eq', 'ri-instagram-line')
14691
.orderBy('icon', 'asc')
14792
.get());
14893
14994
// === 5. Önbellek Yönetimi ===
15095
// 5.1 Önbellek Bypass
151-
const { data: bypassCacheItems } = await useAsyncData<QueryResult<IFaqItem>>('bypass-cache-items', () =>
152-
useContentrainQuery<IFaqItem>('faqitems')
96+
const { data: bypassCacheItems } = await useAsyncData('bypass-cache-items', () =>
97+
useContentrainQuery<FaqItems>('faqitems')
15398
.locale('tr')
15499
.get());
155100
</script>

playground/nuxt/pages/works/[id].vue

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
<script setup lang="ts">
2+
import type { WorkItems } from '#build/types/contentrain';
3+
24
const route = useRoute();
35
const slug = computed(() => route.params.id);
4-
const { data: workItem } = await useAsyncData('work-item', async () => {
5-
const result = await useContentrainQuery<any>('workitems').where('ID', 'eq', slug.value).locale('tr').first();
6-
return result;
7-
});
6+
const { data: workItem } = await useAsyncData('work-item', () =>
7+
useContentrainQuery<WorkItems>('workitems').where('ID', 'eq', slug.value as string).locale('tr').first());
88
</script>
99

1010
<template>
1111
<div class="container mx-auto p-4">
12-
<h1 class="text-2xl font-bold">{{ workItem.title }}</h1>
13-
<p class="text-gray-600">{{ workItem.description }}</p>
12+
<h1 class="text-2xl font-bold">{{ workItem.data.title }}</h1>
13+
<p class="text-gray-600">{{ workItem.data.description }}</p>
1414
</div>
1515
</template>
1616

0 commit comments

Comments
 (0)