@contentrain/nuxt
Advanced tools
Comparing version
import * as _nuxt_schema from '@nuxt/schema'; | ||
interface ModuleOptions { | ||
contentDir: string; | ||
defaultLocale?: string; | ||
databasePath?: string; | ||
cache: boolean; | ||
@@ -7,0 +6,0 @@ ttl: number; |
@@ -7,3 +7,3 @@ { | ||
}, | ||
"version": "2.2.3", | ||
"version": "3.0.0", | ||
"builder": { | ||
@@ -10,0 +10,0 @@ "@nuxt/module-builder": "0.8.4", |
@@ -1,10 +0,16 @@ | ||
import type { BaseContentrainType, Filter, Include, LoaderResult, Operator, QueryConfig, QueryResult, Sort } from '@contentrain/query'; | ||
export interface QueryState<M extends BaseContentrainType, L extends string = string, R extends Record<string, BaseContentrainType> = Record<string, BaseContentrainType>> { | ||
import type { Filter, IDBRecord, Operator, QueryResult, Sort, SQLiteOptions } from '@contentrain/query'; | ||
type ContentrainRecord = IDBRecord; | ||
export interface IncludeOptions<M extends ContentrainRecord, L extends string = string> { | ||
relation: keyof M['_relations']; | ||
locale?: L; | ||
} | ||
export type ContentrainInclude<M extends ContentrainRecord, L extends string = string> = keyof M['_relations'] | IncludeOptions<M, L> | Array<keyof M['_relations'] | IncludeOptions<M, L>>; | ||
export interface QueryState<M extends ContentrainRecord, L extends string = string> { | ||
model: string; | ||
filters: Array<Omit<Filter, 'field'> & { | ||
field: keyof M | keyof BaseContentrainType; | ||
filters: Array<Filter & { | ||
field: keyof M; | ||
}>; | ||
includes: Record<keyof R, Include>; | ||
sorting: Array<Omit<Sort, 'field'> & { | ||
field: keyof M | keyof BaseContentrainType; | ||
includes: Array<IncludeOptions<M, L>>; | ||
sorting: Array<Sort & { | ||
field: keyof M; | ||
}>; | ||
@@ -15,3 +21,3 @@ pagination: { | ||
}; | ||
options: { | ||
options: SQLiteOptions & { | ||
locale?: L; | ||
@@ -22,14 +28,12 @@ cache?: boolean; | ||
} | ||
export declare class QueryBuilder<M extends BaseContentrainType, L extends string = string, R extends Record<string, BaseContentrainType> = Record<string, BaseContentrainType>> { | ||
export declare class QueryBuilder<M extends ContentrainRecord, L extends string = string> { | ||
private defaultLocale; | ||
private state; | ||
constructor(model: string, defaultLocale: string); | ||
where<K extends keyof M | keyof BaseContentrainType, O extends Operator>(field: K, operator: O, value: O extends 'in' | 'nin' ? K extends keyof M ? M[K][] : any[] : K extends keyof M ? M[K] : any): this; | ||
include<K extends M extends { | ||
_relations?: infer R; | ||
} ? keyof R : never>(relation: K | K[]): this; | ||
orderBy<K extends keyof M | keyof BaseContentrainType>(field: K, direction?: 'asc' | 'desc'): this; | ||
limit(count: number): this; | ||
offset(count: number): this; | ||
locale(code: L): this; | ||
where<K extends keyof M & string, V = M[K], O extends Operator = Operator>(field: K, operator: O, value: V extends Array<infer U> ? O extends 'in' | 'nin' ? U[] : V : V): this; | ||
include(options: ContentrainInclude<M, L>): this; | ||
orderBy<K extends keyof M & string>(field: K, direction?: 'asc' | 'desc'): this; | ||
limit(limit: number): this; | ||
offset(offset: number): this; | ||
locale(locale: L): this; | ||
cache(ttl?: number): this; | ||
@@ -42,6 +46,7 @@ noCache(): this; | ||
export interface ContentrainComposable { | ||
query: <T extends QueryConfig<BaseContentrainType, string, Record<string, BaseContentrainType>>>(model: string) => QueryBuilder<T['fields'], T['locales'], T['relations']>; | ||
load: <T extends BaseContentrainType>(model: string) => Promise<LoaderResult<T>>; | ||
query: <M extends ContentrainRecord, L extends string = string>(model: string) => QueryBuilder<M, L>; | ||
load: <T extends ContentrainRecord>(model: string) => Promise<T>; | ||
clearCache: (model?: string) => Promise<void>; | ||
} | ||
export declare function useContentrain(): ContentrainComposable; | ||
export {}; |
@@ -8,3 +8,3 @@ import { useRuntimeConfig } from "#imports"; | ||
filters: [], | ||
includes: {}, | ||
includes: [], | ||
sorting: [], | ||
@@ -24,9 +24,27 @@ pagination: {}, | ||
} | ||
include(relation) { | ||
if (typeof relation === "string") { | ||
this.state.includes[relation] = {}; | ||
} else if (Array.isArray(relation)) { | ||
relation.forEach((r) => { | ||
this.state.includes[r] = {}; | ||
include(options) { | ||
if (typeof options === "string") { | ||
this.state.includes.push({ | ||
relation: options, | ||
locale: this.state.options.locale | ||
}); | ||
} else if (Array.isArray(options)) { | ||
options.forEach((item) => { | ||
if (typeof item === "string") { | ||
this.state.includes.push({ | ||
relation: item, | ||
locale: this.state.options.locale | ||
}); | ||
} else if (typeof item === "object" && "relation" in item) { | ||
this.state.includes.push({ | ||
relation: item.relation, | ||
locale: item.locale || this.state.options.locale | ||
}); | ||
} | ||
}); | ||
} else if (typeof options === "object" && "relation" in options) { | ||
this.state.includes.push({ | ||
relation: options.relation, | ||
locale: options.locale || this.state.options.locale | ||
}); | ||
} | ||
@@ -42,12 +60,12 @@ return this; | ||
} | ||
limit(count) { | ||
this.state.pagination.limit = count; | ||
limit(limit) { | ||
this.state.pagination.limit = limit; | ||
return this; | ||
} | ||
offset(count) { | ||
this.state.pagination.offset = count; | ||
offset(offset) { | ||
this.state.pagination.offset = offset; | ||
return this; | ||
} | ||
locale(code) { | ||
this.state.options.locale = code; | ||
locale(locale) { | ||
this.state.options.locale = locale; | ||
return this; | ||
@@ -67,17 +85,26 @@ } | ||
const { model, options, filters, sorting, includes, pagination } = this.state; | ||
const formattedIncludes = Object.keys(includes).length > 0 ? Object.keys(includes).map((key) => key.toString()) : void 0; | ||
return $fetch("/api/_contentrain/query", { | ||
method: "POST", | ||
body: { | ||
model, | ||
locale: options.locale || this.defaultLocale, | ||
where: filters.map((filter) => [filter.field, filter.operator, filter.value]), | ||
orderBy: sorting.map((sort) => [sort.field, sort.direction]), | ||
include: formattedIncludes, | ||
limit: pagination.limit, | ||
offset: pagination.offset, | ||
cache: options.cache, | ||
ttl: options.ttl | ||
} | ||
}); | ||
const requestBody = { | ||
model, | ||
locale: options.locale || this.defaultLocale, | ||
where: filters.map((filter) => [filter.field, filter.operator, filter.value]), | ||
orderBy: sorting.map((sort) => [sort.field, sort.direction]), | ||
include: includes.map((include) => ({ | ||
relation: include.relation, | ||
locale: include.locale || options.locale || this.defaultLocale | ||
})), | ||
limit: pagination.limit, | ||
offset: pagination.offset, | ||
cache: options.cache, | ||
ttl: options.ttl | ||
}; | ||
try { | ||
const result = await $fetch("/api/_contentrain/query", { | ||
method: "POST", | ||
body: requestBody | ||
}); | ||
return result; | ||
} catch (error) { | ||
console.error("Query Error:", error); | ||
throw error; | ||
} | ||
} | ||
@@ -84,0 +111,0 @@ async first() { |
@@ -1,3 +0,3 @@ | ||
import type { BaseContentrainType, QueryResult } from '@contentrain/query'; | ||
declare const _default: import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<QueryResult<BaseContentrainType>>>; | ||
import type { IDBRecord, QueryResult } from '@contentrain/query'; | ||
declare const _default: import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<QueryResult<IDBRecord>>>; | ||
export default _default; |
import { useRuntimeConfig } from "#imports"; | ||
import { QueryFactory } from "@contentrain/query"; | ||
import { createError, defineEventHandler, readBody } from "h3"; | ||
@@ -69,32 +70,28 @@ import { getSDK } from "../utils/sdk.js"; | ||
if (body.include) { | ||
if (Array.isArray(body.include)) { | ||
body.include.forEach((relation) => { | ||
if (typeof relation !== "string") { | ||
throw createError({ | ||
statusCode: 400, | ||
message: "include items must be strings" | ||
}); | ||
} | ||
}); | ||
} else if (typeof body.include === "object") { | ||
Object.entries(body.include).forEach(([relation, config]) => { | ||
if (typeof relation !== "string") { | ||
throw createError({ | ||
statusCode: 400, | ||
message: "include relation must be a string" | ||
}); | ||
} | ||
if (config.fields && !Array.isArray(config.fields)) { | ||
throw createError({ | ||
statusCode: 400, | ||
message: "include fields must be an array" | ||
}); | ||
} | ||
}); | ||
} else { | ||
if (!Array.isArray(body.include)) { | ||
throw createError({ | ||
statusCode: 400, | ||
message: "include must be an array or an object" | ||
message: "include must be an array" | ||
}); | ||
} | ||
body.include.forEach((include) => { | ||
if (!include || typeof include !== "object") { | ||
throw createError({ | ||
statusCode: 400, | ||
message: "Each include must be an object with relation property" | ||
}); | ||
} | ||
if (typeof include.relation !== "string") { | ||
throw createError({ | ||
statusCode: 400, | ||
message: "include relation must be a string" | ||
}); | ||
} | ||
if (include.locale !== void 0 && typeof include.locale !== "string") { | ||
throw createError({ | ||
statusCode: 400, | ||
message: "include locale must be a string when provided" | ||
}); | ||
} | ||
}); | ||
} | ||
@@ -147,3 +144,3 @@ if (body.limit !== void 0 && (typeof body.limit !== "number" || body.limit < 0)) { | ||
const sdk = getSDK(config); | ||
const query = sdk.query(body.model); | ||
const query = QueryFactory.createSQLiteBuilder(body.model, sdk); | ||
if (body.where) { | ||
@@ -155,19 +152,8 @@ body.where.forEach(([field, operator, value]) => { | ||
if (body.include) { | ||
if (Array.isArray(body.include)) { | ||
body.include.forEach((relation) => { | ||
query.include(relation); | ||
body.include.forEach((include) => { | ||
query.include({ | ||
relation: include.relation, | ||
locale: include.locale || body.locale | ||
}); | ||
} else if (typeof body.include === "string") { | ||
query.include(body.include); | ||
} else { | ||
Object.entries(body.include).forEach(([relation, config2]) => { | ||
query.include(relation); | ||
if (config2.fields) { | ||
console.warn("fields property in include is not supported yet"); | ||
} | ||
if (config2.include) { | ||
console.warn("nested includes are not supported yet"); | ||
} | ||
}); | ||
} | ||
}); | ||
} | ||
@@ -174,0 +160,0 @@ if (body.orderBy) { |
@@ -0,3 +1,3 @@ | ||
import type { SQLiteLoader } from '@contentrain/query'; | ||
import type { RuntimeConfig } from '@nuxt/schema'; | ||
import { ContentrainSDK } from '@contentrain/query'; | ||
export declare function getSDK(config: RuntimeConfig): ContentrainSDK; | ||
export declare function getSDK(config: RuntimeConfig): SQLiteLoader; |
@@ -1,20 +0,25 @@ | ||
import { ContentrainSDK } from "@contentrain/query"; | ||
import { QueryFactory, SQLiteLoader as SQLiteLoaderImpl } from "@contentrain/query"; | ||
let _sdk = null; | ||
export function getSDK(config) { | ||
if (!config.contentrain) { | ||
throw new Error("Contentrain config is missing"); | ||
} | ||
if (!_sdk) { | ||
if (!config.contentrain?.contentDir) { | ||
throw new Error("contentDir is required in contentrain config"); | ||
if (!config.contentrain.databasePath) { | ||
throw new Error("databasePath is required for SQLite loader"); | ||
} | ||
_sdk = new ContentrainSDK({ | ||
contentDir: config.contentrain.contentDir, | ||
defaultLocale: config.contentrain.defaultLocale || "en", | ||
const loader = new SQLiteLoaderImpl({ | ||
databasePath: config.contentrain.databasePath, | ||
cache: config.contentrain.cache !== false, | ||
ttl: config.contentrain.ttl || 60 * 1e3, | ||
// default 1 minute | ||
maxCacheSize: config.contentrain.maxCacheSize || 100, | ||
// default 100MB | ||
defaultLocale: config.contentrain.defaultLocale, | ||
modelTTL: config.contentrain.modelTTL || {} | ||
}); | ||
QueryFactory.setLoader(loader); | ||
_sdk = loader; | ||
} | ||
if (!_sdk) { | ||
throw new Error("Failed to initialize SDK"); | ||
} | ||
return _sdk; | ||
} |
{ | ||
"name": "@contentrain/nuxt", | ||
"version": "2.2.3", | ||
"version": "3.0.0", | ||
"description": "Official Nuxt module for Contentrain SDK, providing seamless integration with Contentrain CMS", | ||
@@ -5,0 +5,0 @@ "author": "Contentrain Inc.", |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
24877
1.83%541
4.64%