@monlite/core 0.1.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.
@@ -0,0 +1,271 @@
1
+ import { Database } from 'better-sqlite3';
2
+
3
+ /**
4
+ * Public type surface for monlite.
5
+ *
6
+ * Documents are plain objects. monlite adds three system fields to every
7
+ * stored document: `_id`, `created_at`, and `updated_at`.
8
+ */
9
+ /** A free-form document. */
10
+ type Doc = Record<string, any>;
11
+ /** System fields monlite manages on every document. */
12
+ interface SystemFields {
13
+ _id: string;
14
+ /** Unix epoch milliseconds. */
15
+ created_at: number;
16
+ /** Unix epoch milliseconds. */
17
+ updated_at: number;
18
+ }
19
+ /** A stored document: the user's shape plus monlite's system fields. */
20
+ type WithId<T> = T & SystemFields;
21
+ /** Per-field operators, Prisma-style (no `$` prefix). */
22
+ interface FieldFilter<V = any> {
23
+ equals?: V | null;
24
+ not?: V | null;
25
+ in?: V[];
26
+ notIn?: V[];
27
+ lt?: V;
28
+ lte?: V;
29
+ gt?: V;
30
+ gte?: V;
31
+ /** Substring match on strings, or element membership on arrays. */
32
+ contains?: V extends string ? string : any;
33
+ startsWith?: string;
34
+ endsWith?: string;
35
+ /** Explicit array element membership. */
36
+ has?: any;
37
+ /** Field presence. `true` requires the field to exist, `false` requires absence. */
38
+ exists?: boolean;
39
+ }
40
+ /** A value used directly as a filter is shorthand for `{ equals: value }`. */
41
+ type FilterInput<V> = V | FieldFilter<V>;
42
+ /**
43
+ * Where input. Known fields are typed from `T`; nested paths can also be
44
+ * addressed with dot notation (e.g. `"address.city"`).
45
+ */
46
+ type WhereInput<T = Doc> = {
47
+ [K in keyof T]?: FilterInput<T[K]>;
48
+ } & {
49
+ _id?: FilterInput<string>;
50
+ created_at?: FilterInput<number>;
51
+ updated_at?: FilterInput<number>;
52
+ AND?: WhereInput<T> | WhereInput<T>[];
53
+ OR?: WhereInput<T> | WhereInput<T>[];
54
+ NOT?: WhereInput<T> | WhereInput<T>[];
55
+ } & {
56
+ [path: string]: any;
57
+ };
58
+ /** Mongo-inspired update operators. */
59
+ interface UpdateOperators {
60
+ $set?: Record<string, any>;
61
+ $unset?: Record<string, true | 1>;
62
+ $inc?: Record<string, number>;
63
+ $push?: Record<string, any>;
64
+ $pull?: Record<string, any>;
65
+ }
66
+ /**
67
+ * Update payload. Either a plain object (shallow-merged into the document)
68
+ * or an object using update operators. The two forms cannot be mixed.
69
+ */
70
+ type UpdateData<T = Doc> = (Partial<T> & Record<string, any>) | UpdateOperators;
71
+ type SortOrder = "asc" | "desc";
72
+ type OrderBy<T = Doc> = ({
73
+ [K in keyof T]?: SortOrder;
74
+ } & {
75
+ [path: string]: SortOrder;
76
+ }) | Array<{
77
+ [path: string]: SortOrder;
78
+ }>;
79
+ type Select<T = Doc> = {
80
+ [K in keyof T]?: boolean;
81
+ } & {
82
+ [path: string]: boolean;
83
+ };
84
+ interface FindManyArgs<T = Doc> {
85
+ where?: WhereInput<T>;
86
+ orderBy?: OrderBy<T>;
87
+ select?: Select<T>;
88
+ skip?: number;
89
+ take?: number;
90
+ }
91
+ interface FindFirstArgs<T = Doc> {
92
+ where?: WhereInput<T>;
93
+ orderBy?: OrderBy<T>;
94
+ select?: Select<T>;
95
+ skip?: number;
96
+ }
97
+ interface CreateArgs<T = Doc> {
98
+ data: Partial<T> & Record<string, any>;
99
+ }
100
+ interface CreateManyArgs<T = Doc> {
101
+ data: Array<Partial<T> & Record<string, any>>;
102
+ }
103
+ interface UpdateArgs<T = Doc> {
104
+ where: WhereInput<T>;
105
+ data: UpdateData<T>;
106
+ }
107
+ interface UpsertArgs<T = Doc> {
108
+ where: WhereInput<T>;
109
+ create: Partial<T> & Record<string, any>;
110
+ update: UpdateData<T>;
111
+ }
112
+ interface DeleteArgs<T = Doc> {
113
+ where: WhereInput<T>;
114
+ }
115
+ interface CountArgs<T = Doc> {
116
+ where?: WhereInput<T>;
117
+ }
118
+ /** Map of `field -> true` selecting which fields an accumulator applies to. */
119
+ type FieldSelection = Record<string, boolean>;
120
+ interface AggregateArgs<T = Doc> {
121
+ where?: WhereInput<T>;
122
+ _count?: boolean;
123
+ _sum?: FieldSelection;
124
+ _avg?: FieldSelection;
125
+ _min?: FieldSelection;
126
+ _max?: FieldSelection;
127
+ }
128
+ interface AggregateResult {
129
+ _count?: number;
130
+ _sum?: Record<string, number | null>;
131
+ _avg?: Record<string, number | null>;
132
+ _min?: Record<string, any>;
133
+ _max?: Record<string, any>;
134
+ }
135
+ interface GroupByArgs<T = Doc> {
136
+ by: string[];
137
+ where?: WhereInput<T>;
138
+ _count?: boolean;
139
+ _sum?: FieldSelection;
140
+ _avg?: FieldSelection;
141
+ _min?: FieldSelection;
142
+ _max?: FieldSelection;
143
+ orderBy?: Record<string, SortOrder>;
144
+ skip?: number;
145
+ take?: number;
146
+ }
147
+ type GroupByResult = Record<string, any>;
148
+ interface MonliteOptions {
149
+ /** Auto-create indexes on frequently-queried JSON paths. Default `true`. */
150
+ autoIndex?: boolean;
151
+ /** Number of times a path must be queried before an index is created. Default `10`. */
152
+ autoIndexAfter?: number;
153
+ /** Open the database read-only. Default `false`. */
154
+ readonly?: boolean;
155
+ /** Use SQLite WAL journal mode for better concurrency. Default `true`. */
156
+ wal?: boolean;
157
+ /** Verbose logger for executed SQL (debugging). */
158
+ verbose?: (sql: string) => void;
159
+ }
160
+
161
+ /**
162
+ * A document collection. Backed by a single SQLite table whose rows store the
163
+ * document as JSON in a `data` column. Created lazily on first write/read.
164
+ */
165
+ declare class Collection<T = Doc> {
166
+ private readonly mon;
167
+ readonly name: string;
168
+ private initialized;
169
+ private readonly trackPath;
170
+ constructor(mon: Monlite, name: string);
171
+ private get db();
172
+ private ensureTable;
173
+ private rowToDoc;
174
+ private prepareInsert;
175
+ create(args: CreateArgs<T>): Promise<WithId<T>>;
176
+ createMany(args: CreateManyArgs<T>): Promise<{
177
+ count: number;
178
+ }>;
179
+ findMany(args?: FindManyArgs<T>): Promise<WithId<T>[]>;
180
+ findFirst(args?: FindFirstArgs<T>): Promise<WithId<T> | null>;
181
+ findById(id: string): Promise<WithId<T> | null>;
182
+ count(args?: CountArgs<T>): Promise<number>;
183
+ private runUpdate;
184
+ update(args: UpdateArgs<T>): Promise<WithId<T> | null>;
185
+ updateMany(args: UpdateArgs<T>): Promise<{
186
+ count: number;
187
+ }>;
188
+ upsert(args: UpsertArgs<T>): Promise<WithId<T>>;
189
+ private runDelete;
190
+ delete(args: DeleteArgs<T>): Promise<WithId<T> | null>;
191
+ deleteMany(args?: DeleteArgs<T>): Promise<{
192
+ count: number;
193
+ }>;
194
+ aggregate(args?: AggregateArgs<T>): Promise<AggregateResult>;
195
+ groupBy(args: GroupByArgs<T>): Promise<GroupByResult[]>;
196
+ }
197
+
198
+ /**
199
+ * Tracks which JSON paths are queried per collection and silently creates a
200
+ * SQLite expression index once a path crosses the configured threshold.
201
+ */
202
+ declare class AutoIndexer {
203
+ private readonly db;
204
+ private readonly enabled;
205
+ private readonly threshold;
206
+ private counts;
207
+ private created;
208
+ constructor(db: Database, enabled: boolean, threshold: number);
209
+ track(collection: string, path: string): void;
210
+ private create;
211
+ /** Forget tracking for a collection (or everything when omitted). */
212
+ reset(collection?: string): void;
213
+ }
214
+
215
+ /**
216
+ * A monlite database — a thin document layer over a single SQLite file.
217
+ * Create one with {@link createDb}.
218
+ */
219
+ declare class Monlite {
220
+ /** The underlying better-sqlite3 connection (escape hatch). */
221
+ readonly sqlite: Database;
222
+ /** @internal */
223
+ readonly autoIndexer: AutoIndexer;
224
+ private readonly collections;
225
+ private closed;
226
+ constructor(filename: string, options?: MonliteOptions);
227
+ /** Get (or lazily create) a typed collection handle. */
228
+ collection<T = Doc>(name: string): Collection<T>;
229
+ /** Tagged-template SQL query returning rows. Values are safely parameterized. */
230
+ $queryRaw<R = any>(strings: TemplateStringsArray, ...values: any[]): Promise<R[]>;
231
+ /** Like {@link $queryRaw} but takes a raw SQL string and positional params. */
232
+ $queryRawUnsafe<R = any>(sql: string, ...params: any[]): Promise<R[]>;
233
+ /** Tagged-template SQL statement returning the number of affected rows. */
234
+ $executeRaw(strings: TemplateStringsArray, ...values: any[]): Promise<number>;
235
+ /** Like {@link $executeRaw} but takes a raw SQL string and positional params. */
236
+ $executeRawUnsafe(sql: string, ...params: any[]): Promise<number>;
237
+ /**
238
+ * Run a function inside a synchronous SQLite transaction. If it throws, the
239
+ * transaction is rolled back.
240
+ */
241
+ $transaction<R>(fn: (db: this) => R): Promise<R>;
242
+ /** List all collection (table) names. */
243
+ $collections(): Promise<string[]>;
244
+ /** Drop a collection and all of its data. */
245
+ $drop(name: string): Promise<void>;
246
+ /** Drop every collection in the database. */
247
+ $dropAll(): Promise<void>;
248
+ /** Close the underlying SQLite connection. */
249
+ $disconnect(): Promise<void>;
250
+ private assertOpen;
251
+ }
252
+ /**
253
+ * Open (or create) a monlite database backed by a single SQLite file.
254
+ * Use `":memory:"` for an in-memory database.
255
+ */
256
+ declare function createDb(filename: string, options?: MonliteOptions): Monlite;
257
+
258
+ /** Base error for all monlite-originated failures. */
259
+ declare class MonliteError extends Error {
260
+ constructor(message: string);
261
+ }
262
+ /** Thrown when a query/update payload is malformed. */
263
+ declare class MonliteQueryError extends MonliteError {
264
+ constructor(message: string);
265
+ }
266
+
267
+ declare function objectId(): string;
268
+ /** True when a value looks like a monlite/ObjectId id (24 hex chars). */
269
+ declare function isObjectId(value: unknown): value is string;
270
+
271
+ export { type AggregateArgs, type AggregateResult, Collection, type CountArgs, type CreateArgs, type CreateManyArgs, Monlite as Db, type DeleteArgs, type Doc, type FieldFilter, type FieldSelection, type FilterInput, type FindFirstArgs, type FindManyArgs, type GroupByArgs, type GroupByResult, Monlite, MonliteError, type MonliteOptions, MonliteQueryError, type OrderBy, type Select, type SortOrder, type SystemFields, type UpdateArgs, type UpdateData, type UpdateOperators, type UpsertArgs, type WhereInput as WhereClause, type WhereInput, type WithId, createDb, isObjectId, objectId };