@mindstudio-ai/agent 0.1.10 → 0.1.11
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/dist/cli.js +144 -37
- package/dist/index.d.ts +62 -3
- package/dist/index.js +139 -33
- package/dist/index.js.map +1 -1
- package/dist/postinstall.js +144 -37
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1968,8 +1968,7 @@ var init_predicate = __esm({
|
|
|
1968
1968
|
return PARSE_FAILED;
|
|
1969
1969
|
}
|
|
1970
1970
|
/**
|
|
1971
|
-
* Attempt to resolve a closure variable
|
|
1972
|
-
* with a recording Proxy and inspecting what values it compares against.
|
|
1971
|
+
* Attempt to resolve a closure variable's value.
|
|
1973
1972
|
*
|
|
1974
1973
|
* This handles the common pattern:
|
|
1975
1974
|
* ```ts
|
|
@@ -1977,40 +1976,28 @@ var init_predicate = __esm({
|
|
|
1977
1976
|
* orders.filter(o => o.requestedBy === userId)
|
|
1978
1977
|
* ```
|
|
1979
1978
|
*
|
|
1980
|
-
*
|
|
1981
|
-
*
|
|
1982
|
-
*
|
|
1983
|
-
*
|
|
1979
|
+
* Closure variable resolution is fundamentally limited in JavaScript —
|
|
1980
|
+
* we can't access another function's closure scope from outside without
|
|
1981
|
+
* `eval`. The `===` operator can't be overridden via Proxy or
|
|
1982
|
+
* Symbol.toPrimitive, so we can't intercept comparisons.
|
|
1983
|
+
*
|
|
1984
|
+
* For now, this falls back to JS execution. The predicate still works
|
|
1985
|
+
* correctly — it just scans all rows instead of generating SQL.
|
|
1986
|
+
* This is the most common reason for JS fallback in practice, since
|
|
1987
|
+
* almost every real-world filter references a variable like `userId`.
|
|
1988
|
+
*
|
|
1989
|
+
* A future improvement could accept an explicit `vars` argument:
|
|
1990
|
+
* ```ts
|
|
1991
|
+
* orders.filter(o => o.requestedBy === $userId, { $userId: auth.userId })
|
|
1992
|
+
* ```
|
|
1984
1993
|
*/
|
|
1985
1994
|
resolveClosureVariable() {
|
|
1986
|
-
|
|
1987
|
-
let closureExpr = identToken.value;
|
|
1995
|
+
this.advance();
|
|
1988
1996
|
while (this.match("dot") && this.tokens[this.pos + 1]?.type === "identifier") {
|
|
1989
1997
|
this.advance();
|
|
1990
|
-
|
|
1991
|
-
}
|
|
1992
|
-
try {
|
|
1993
|
-
const MARKER = /* @__PURE__ */ Symbol("field_access_marker");
|
|
1994
|
-
const accessed = [];
|
|
1995
|
-
const proxy = new Proxy(
|
|
1996
|
-
{},
|
|
1997
|
-
{
|
|
1998
|
-
get(_, prop) {
|
|
1999
|
-
accessed.push(prop);
|
|
2000
|
-
return new Proxy(() => MARKER, {
|
|
2001
|
-
get(_2, nestedProp) {
|
|
2002
|
-
accessed.push(nestedProp);
|
|
2003
|
-
return MARKER;
|
|
2004
|
-
}
|
|
2005
|
-
});
|
|
2006
|
-
}
|
|
2007
|
-
}
|
|
2008
|
-
);
|
|
2009
|
-
void proxy;
|
|
2010
|
-
return PARSE_FAILED;
|
|
2011
|
-
} catch {
|
|
2012
|
-
return PARSE_FAILED;
|
|
1998
|
+
this.advance();
|
|
2013
1999
|
}
|
|
2000
|
+
return PARSE_FAILED;
|
|
2014
2001
|
}
|
|
2015
2002
|
/**
|
|
2016
2003
|
* Look ahead to check if the next tokens form `.includes(`.
|
|
@@ -2169,6 +2156,76 @@ var init_query = __esm({
|
|
|
2169
2156
|
return map;
|
|
2170
2157
|
}
|
|
2171
2158
|
// -------------------------------------------------------------------------
|
|
2159
|
+
// Batch compilation — used by db.batch() to extract SQL without executing
|
|
2160
|
+
// -------------------------------------------------------------------------
|
|
2161
|
+
/**
|
|
2162
|
+
* @internal Compile this query into a SqlQuery for batch execution.
|
|
2163
|
+
*
|
|
2164
|
+
* Returns the compiled SQL query (if all predicates compile to SQL),
|
|
2165
|
+
* or null (if JS fallback is needed). In the fallback case, a bare
|
|
2166
|
+
* `SELECT *` is returned as `fallbackQuery` so the batch can fetch
|
|
2167
|
+
* all rows and this query can filter them in JS post-fetch.
|
|
2168
|
+
*/
|
|
2169
|
+
_compile() {
|
|
2170
|
+
const compiled = this._compilePredicates();
|
|
2171
|
+
const sortField = this._sortAccessor ? extractFieldName(this._sortAccessor) : void 0;
|
|
2172
|
+
if (compiled.allSql) {
|
|
2173
|
+
const query = buildSelect(this._config.tableName, {
|
|
2174
|
+
where: compiled.sqlWhere || void 0,
|
|
2175
|
+
orderBy: sortField ?? void 0,
|
|
2176
|
+
desc: this._reversed,
|
|
2177
|
+
limit: this._limit,
|
|
2178
|
+
offset: this._offset
|
|
2179
|
+
});
|
|
2180
|
+
return { query, fallbackQuery: null, config: this._config };
|
|
2181
|
+
}
|
|
2182
|
+
const fallbackQuery = buildSelect(this._config.tableName);
|
|
2183
|
+
return {
|
|
2184
|
+
query: null,
|
|
2185
|
+
fallbackQuery,
|
|
2186
|
+
config: this._config,
|
|
2187
|
+
predicates: this._predicates,
|
|
2188
|
+
sortAccessor: this._sortAccessor,
|
|
2189
|
+
reversed: this._reversed,
|
|
2190
|
+
limit: this._limit,
|
|
2191
|
+
offset: this._offset
|
|
2192
|
+
};
|
|
2193
|
+
}
|
|
2194
|
+
/**
|
|
2195
|
+
* @internal Process raw SQL results into typed rows. Used by db.batch()
|
|
2196
|
+
* after executing the compiled query.
|
|
2197
|
+
*
|
|
2198
|
+
* For SQL-compiled queries: just deserialize the rows.
|
|
2199
|
+
* For JS-fallback queries: filter, sort, and slice in JS.
|
|
2200
|
+
*/
|
|
2201
|
+
static _processResults(result, compiled) {
|
|
2202
|
+
const rows = result.rows.map(
|
|
2203
|
+
(row) => deserializeRow(
|
|
2204
|
+
row,
|
|
2205
|
+
compiled.config.columns
|
|
2206
|
+
)
|
|
2207
|
+
);
|
|
2208
|
+
if (compiled.query) return rows;
|
|
2209
|
+
let filtered = compiled.predicates ? rows.filter((row) => compiled.predicates.every((pred) => pred(row))) : rows;
|
|
2210
|
+
if (compiled.sortAccessor) {
|
|
2211
|
+
const accessor = compiled.sortAccessor;
|
|
2212
|
+
const reversed = compiled.reversed ?? false;
|
|
2213
|
+
filtered.sort((a, b) => {
|
|
2214
|
+
const aVal = accessor(a);
|
|
2215
|
+
const bVal = accessor(b);
|
|
2216
|
+
if (aVal < bVal) return reversed ? 1 : -1;
|
|
2217
|
+
if (aVal > bVal) return reversed ? -1 : 1;
|
|
2218
|
+
return 0;
|
|
2219
|
+
});
|
|
2220
|
+
}
|
|
2221
|
+
if (compiled.offset != null || compiled.limit != null) {
|
|
2222
|
+
const start = compiled.offset ?? 0;
|
|
2223
|
+
const end = compiled.limit != null ? start + compiled.limit : void 0;
|
|
2224
|
+
filtered = filtered.slice(start, end);
|
|
2225
|
+
}
|
|
2226
|
+
return filtered;
|
|
2227
|
+
}
|
|
2228
|
+
// -------------------------------------------------------------------------
|
|
2172
2229
|
// PromiseLike
|
|
2173
2230
|
// -------------------------------------------------------------------------
|
|
2174
2231
|
then(onfulfilled, onrejected) {
|
|
@@ -2418,7 +2475,49 @@ function createDb(databases, executeBatch) {
|
|
|
2418
2475
|
hours: (n) => n * 36e5,
|
|
2419
2476
|
minutes: (n) => n * 6e4,
|
|
2420
2477
|
ago: (ms) => Date.now() - ms,
|
|
2421
|
-
fromNow: (ms) => Date.now() + ms
|
|
2478
|
+
fromNow: (ms) => Date.now() + ms,
|
|
2479
|
+
// --- Batch execution ---
|
|
2480
|
+
batch: ((...queries) => {
|
|
2481
|
+
return (async () => {
|
|
2482
|
+
const compiled = queries.map((q) => {
|
|
2483
|
+
if (!(q instanceof Query)) {
|
|
2484
|
+
throw new MindStudioError(
|
|
2485
|
+
"db.batch() only accepts Query objects (from .filter(), .sortBy(), etc.)",
|
|
2486
|
+
"invalid_batch_query",
|
|
2487
|
+
400
|
|
2488
|
+
);
|
|
2489
|
+
}
|
|
2490
|
+
return q._compile();
|
|
2491
|
+
});
|
|
2492
|
+
const groups = /* @__PURE__ */ new Map();
|
|
2493
|
+
for (let i = 0; i < compiled.length; i++) {
|
|
2494
|
+
const c = compiled[i];
|
|
2495
|
+
const dbId = c.config.databaseId;
|
|
2496
|
+
const sqlQuery = c.query ?? c.fallbackQuery;
|
|
2497
|
+
if (!groups.has(dbId)) groups.set(dbId, []);
|
|
2498
|
+
groups.get(dbId).push({ index: i, sqlQuery });
|
|
2499
|
+
}
|
|
2500
|
+
const allResults = new Array(compiled.length);
|
|
2501
|
+
await Promise.all(
|
|
2502
|
+
Array.from(groups.entries()).map(async ([dbId, entries]) => {
|
|
2503
|
+
const sqlQueries = entries.map((e) => e.sqlQuery);
|
|
2504
|
+
const results = await executeBatch(dbId, sqlQueries);
|
|
2505
|
+
for (let i = 0; i < entries.length; i++) {
|
|
2506
|
+
allResults[entries[i].index] = results[i];
|
|
2507
|
+
}
|
|
2508
|
+
})
|
|
2509
|
+
);
|
|
2510
|
+
return compiled.map((c, i) => {
|
|
2511
|
+
const result = allResults[i];
|
|
2512
|
+
if (!c.query && c.predicates?.length) {
|
|
2513
|
+
console.warn(
|
|
2514
|
+
`[mindstudio] db.batch(): filter on ${c.config.tableName} could not be compiled to SQL \u2014 processing in JS`
|
|
2515
|
+
);
|
|
2516
|
+
}
|
|
2517
|
+
return Query._processResults(result, c);
|
|
2518
|
+
});
|
|
2519
|
+
})();
|
|
2520
|
+
})
|
|
2422
2521
|
};
|
|
2423
2522
|
}
|
|
2424
2523
|
function resolveTable(databases, tableName, databaseHint) {
|
|
@@ -2473,6 +2572,7 @@ var init_db = __esm({
|
|
|
2473
2572
|
"use strict";
|
|
2474
2573
|
init_errors();
|
|
2475
2574
|
init_table();
|
|
2575
|
+
init_query();
|
|
2476
2576
|
init_table();
|
|
2477
2577
|
}
|
|
2478
2578
|
});
|
|
@@ -3556,7 +3656,14 @@ var init_client = __esm({
|
|
|
3556
3656
|
hours: (n) => n * 36e5,
|
|
3557
3657
|
minutes: (n) => n * 6e4,
|
|
3558
3658
|
ago: (ms) => Date.now() - ms,
|
|
3559
|
-
fromNow: (ms) => Date.now() + ms
|
|
3659
|
+
fromNow: (ms) => Date.now() + ms,
|
|
3660
|
+
// Batch needs context — hydrate first, then delegate to real db
|
|
3661
|
+
batch: ((...queries) => {
|
|
3662
|
+
return (async () => {
|
|
3663
|
+
await agent.ensureContext();
|
|
3664
|
+
return agent._db.batch(...queries);
|
|
3665
|
+
})();
|
|
3666
|
+
})
|
|
3560
3667
|
};
|
|
3561
3668
|
}
|
|
3562
3669
|
// -------------------------------------------------------------------------
|
|
@@ -3761,7 +3868,7 @@ async function startMcpServer(options) {
|
|
|
3761
3868
|
capabilities: { tools: {} },
|
|
3762
3869
|
serverInfo: {
|
|
3763
3870
|
name: "mindstudio-agent",
|
|
3764
|
-
version: "0.1.
|
|
3871
|
+
version: "0.1.11"
|
|
3765
3872
|
},
|
|
3766
3873
|
instructions: "Welcome to MindStudio \u2014 a platform with 200+ AI models, 850+ third-party integrations, and pre-built agents.\n\nGetting started:\n1. Call `listAgents` to verify your connection and see available agents.\n2. Call `changeName` to set your display name \u2014 use your name or whatever your user calls you. This is how you'll appear in MindStudio request logs.\n3. If you have a profile picture or icon, call `uploadFile` to upload it, then `changeProfilePicture` with the returned URL. This helps users identify your requests in their logs.\n4. Call `listActions` to discover all available actions.\n\nThen use the tools to generate text, images, video, audio, search the web, work with data sources, run agents, and more.\n\nImportant:\n- AI-powered actions (text generation, image generation, video, audio, etc.) cost money. Before running these, call `estimateActionCost` and confirm with the user before proceeding \u2014 unless they've explicitly told you to go ahead.\n- Not all agents from `listAgents` are configured for API use. Do not try to run an agent just because it appears in the list \u2014 it will likely fail. Only run agents the user specifically asks you to run."
|
|
3767
3874
|
});
|
|
@@ -4669,7 +4776,7 @@ function isNewerVersion(current, latest) {
|
|
|
4669
4776
|
return false;
|
|
4670
4777
|
}
|
|
4671
4778
|
async function checkForUpdate() {
|
|
4672
|
-
const currentVersion = "0.1.
|
|
4779
|
+
const currentVersion = "0.1.11";
|
|
4673
4780
|
if (!currentVersion) return null;
|
|
4674
4781
|
try {
|
|
4675
4782
|
const { loadConfig: loadConfig2, saveConfig: saveConfig2 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
@@ -4698,7 +4805,7 @@ async function checkForUpdate() {
|
|
|
4698
4805
|
}
|
|
4699
4806
|
}
|
|
4700
4807
|
function printUpdateNotice(latestVersion) {
|
|
4701
|
-
const currentVersion = "0.1.
|
|
4808
|
+
const currentVersion = "0.1.11";
|
|
4702
4809
|
process.stderr.write(
|
|
4703
4810
|
`
|
|
4704
4811
|
${ansi.cyanBright("Update available")} ${ansi.gray(currentVersion + " \u2192")} ${ansi.cyanBold(latestVersion)}
|
|
@@ -4773,7 +4880,7 @@ async function cmdLogin(options) {
|
|
|
4773
4880
|
process.stderr.write("\n");
|
|
4774
4881
|
printLogo();
|
|
4775
4882
|
process.stderr.write("\n");
|
|
4776
|
-
const ver = "0.1.
|
|
4883
|
+
const ver = "0.1.11";
|
|
4777
4884
|
process.stderr.write(
|
|
4778
4885
|
` ${ansi.bold("MindStudio Agent")} ${ver ? " " + ansi.gray("v" + ver) : ""}
|
|
4779
4886
|
`
|
package/dist/index.d.ts
CHANGED
|
@@ -156,9 +156,7 @@ interface UserInfoResult {
|
|
|
156
156
|
* }
|
|
157
157
|
* ```
|
|
158
158
|
*/
|
|
159
|
-
type User = string
|
|
160
|
-
readonly __brand: 'User';
|
|
161
|
-
};
|
|
159
|
+
type User = string;
|
|
162
160
|
/**
|
|
163
161
|
* Resolved display info for a platform user. Returned by `resolveUser()`
|
|
164
162
|
* and `resolveUsers()`.
|
|
@@ -682,12 +680,51 @@ declare class Query<T> implements PromiseLike<T[]> {
|
|
|
682
680
|
min(accessor: Accessor<T, number>): Promise<T | null>;
|
|
683
681
|
max(accessor: Accessor<T, number>): Promise<T | null>;
|
|
684
682
|
groupBy<K extends string | number>(accessor: Accessor<T, K>): Promise<Map<K, T[]>>;
|
|
683
|
+
/**
|
|
684
|
+
* @internal Compile this query into a SqlQuery for batch execution.
|
|
685
|
+
*
|
|
686
|
+
* Returns the compiled SQL query (if all predicates compile to SQL),
|
|
687
|
+
* or null (if JS fallback is needed). In the fallback case, a bare
|
|
688
|
+
* `SELECT *` is returned as `fallbackQuery` so the batch can fetch
|
|
689
|
+
* all rows and this query can filter them in JS post-fetch.
|
|
690
|
+
*/
|
|
691
|
+
_compile(): CompiledQuery<T>;
|
|
692
|
+
/**
|
|
693
|
+
* @internal Process raw SQL results into typed rows. Used by db.batch()
|
|
694
|
+
* after executing the compiled query.
|
|
695
|
+
*
|
|
696
|
+
* For SQL-compiled queries: just deserialize the rows.
|
|
697
|
+
* For JS-fallback queries: filter, sort, and slice in JS.
|
|
698
|
+
*/
|
|
699
|
+
static _processResults<T>(result: SqlResult, compiled: CompiledQuery<T>): T[];
|
|
685
700
|
then<TResult1 = T[], TResult2 = never>(onfulfilled?: ((value: T[]) => TResult1 | PromiseLike<TResult1>) | null, onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null): Promise<TResult1 | TResult2>;
|
|
686
701
|
private _execute;
|
|
687
702
|
private _compilePredicates;
|
|
688
703
|
private _fetchAndFilterInJs;
|
|
689
704
|
private _fetchAllRows;
|
|
690
705
|
}
|
|
706
|
+
/**
|
|
707
|
+
* Result of Query._compile(). Contains either a compiled SQL query
|
|
708
|
+
* (fast path) or a fallback SELECT * with JS processing metadata.
|
|
709
|
+
*/
|
|
710
|
+
interface CompiledQuery<T> {
|
|
711
|
+
/** Compiled SQL query, or null if JS fallback needed. */
|
|
712
|
+
query: SqlQuery | null;
|
|
713
|
+
/** SELECT * fallback query, or null if SQL compiled. */
|
|
714
|
+
fallbackQuery: SqlQuery | null;
|
|
715
|
+
/** Table config for deserialization. */
|
|
716
|
+
config: TableConfig;
|
|
717
|
+
/** JS predicates (only for fallback). */
|
|
718
|
+
predicates?: Predicate<T>[];
|
|
719
|
+
/** Sort accessor (only for fallback). */
|
|
720
|
+
sortAccessor?: Accessor<T>;
|
|
721
|
+
/** Sort direction (only for fallback). */
|
|
722
|
+
reversed?: boolean;
|
|
723
|
+
/** Limit (only for fallback). */
|
|
724
|
+
limit?: number;
|
|
725
|
+
/** Offset (only for fallback). */
|
|
726
|
+
offset?: number;
|
|
727
|
+
}
|
|
691
728
|
|
|
692
729
|
/**
|
|
693
730
|
* Table<T> — a typed persistent collection backed by SQLite.
|
|
@@ -848,6 +885,28 @@ interface Db {
|
|
|
848
885
|
ago(ms: number): number;
|
|
849
886
|
/** Returns a unix timestamp for (now + duration). Use with days/hours/minutes. */
|
|
850
887
|
fromNow(ms: number): number;
|
|
888
|
+
/**
|
|
889
|
+
* Execute multiple queries in a single round trip. All queries run on
|
|
890
|
+
* the same database connection, eliminating per-query HTTP overhead.
|
|
891
|
+
*
|
|
892
|
+
* Accepts Query objects (lazy, not yet executed). Compiles them to SQL,
|
|
893
|
+
* sends all in one batch request, and returns typed results.
|
|
894
|
+
*
|
|
895
|
+
* @example
|
|
896
|
+
* ```ts
|
|
897
|
+
* const [orders, approvals, vendors] = await db.batch(
|
|
898
|
+
* Orders.filter(o => o.status === 'active').take(10),
|
|
899
|
+
* Approvals.filter(a => a.status === 'pending').take(25),
|
|
900
|
+
* Vendors.sortBy(v => v.createdAt).reverse().take(5),
|
|
901
|
+
* );
|
|
902
|
+
* ```
|
|
903
|
+
*/
|
|
904
|
+
batch<A>(q1: PromiseLike<A>): Promise<[A]>;
|
|
905
|
+
batch<A, B>(q1: PromiseLike<A>, q2: PromiseLike<B>): Promise<[A, B]>;
|
|
906
|
+
batch<A, B, C>(q1: PromiseLike<A>, q2: PromiseLike<B>, q3: PromiseLike<C>): Promise<[A, B, C]>;
|
|
907
|
+
batch<A, B, C, D>(q1: PromiseLike<A>, q2: PromiseLike<B>, q3: PromiseLike<C>, q4: PromiseLike<D>): Promise<[A, B, C, D]>;
|
|
908
|
+
batch<A, B, C, D, E>(q1: PromiseLike<A>, q2: PromiseLike<B>, q3: PromiseLike<C>, q4: PromiseLike<D>, q5: PromiseLike<E>): Promise<[A, B, C, D, E]>;
|
|
909
|
+
batch(...queries: PromiseLike<unknown>[]): Promise<unknown[]>;
|
|
851
910
|
}
|
|
852
911
|
|
|
853
912
|
/**
|
package/dist/index.js
CHANGED
|
@@ -716,8 +716,7 @@ var Parser = class {
|
|
|
716
716
|
return PARSE_FAILED;
|
|
717
717
|
}
|
|
718
718
|
/**
|
|
719
|
-
* Attempt to resolve a closure variable
|
|
720
|
-
* with a recording Proxy and inspecting what values it compares against.
|
|
719
|
+
* Attempt to resolve a closure variable's value.
|
|
721
720
|
*
|
|
722
721
|
* This handles the common pattern:
|
|
723
722
|
* ```ts
|
|
@@ -725,40 +724,28 @@ var Parser = class {
|
|
|
725
724
|
* orders.filter(o => o.requestedBy === userId)
|
|
726
725
|
* ```
|
|
727
726
|
*
|
|
728
|
-
*
|
|
729
|
-
*
|
|
730
|
-
*
|
|
731
|
-
*
|
|
727
|
+
* Closure variable resolution is fundamentally limited in JavaScript —
|
|
728
|
+
* we can't access another function's closure scope from outside without
|
|
729
|
+
* `eval`. The `===` operator can't be overridden via Proxy or
|
|
730
|
+
* Symbol.toPrimitive, so we can't intercept comparisons.
|
|
731
|
+
*
|
|
732
|
+
* For now, this falls back to JS execution. The predicate still works
|
|
733
|
+
* correctly — it just scans all rows instead of generating SQL.
|
|
734
|
+
* This is the most common reason for JS fallback in practice, since
|
|
735
|
+
* almost every real-world filter references a variable like `userId`.
|
|
736
|
+
*
|
|
737
|
+
* A future improvement could accept an explicit `vars` argument:
|
|
738
|
+
* ```ts
|
|
739
|
+
* orders.filter(o => o.requestedBy === $userId, { $userId: auth.userId })
|
|
740
|
+
* ```
|
|
732
741
|
*/
|
|
733
742
|
resolveClosureVariable() {
|
|
734
|
-
|
|
735
|
-
let closureExpr = identToken.value;
|
|
743
|
+
this.advance();
|
|
736
744
|
while (this.match("dot") && this.tokens[this.pos + 1]?.type === "identifier") {
|
|
737
745
|
this.advance();
|
|
738
|
-
|
|
739
|
-
}
|
|
740
|
-
try {
|
|
741
|
-
const MARKER = /* @__PURE__ */ Symbol("field_access_marker");
|
|
742
|
-
const accessed = [];
|
|
743
|
-
const proxy = new Proxy(
|
|
744
|
-
{},
|
|
745
|
-
{
|
|
746
|
-
get(_, prop) {
|
|
747
|
-
accessed.push(prop);
|
|
748
|
-
return new Proxy(() => MARKER, {
|
|
749
|
-
get(_2, nestedProp) {
|
|
750
|
-
accessed.push(nestedProp);
|
|
751
|
-
return MARKER;
|
|
752
|
-
}
|
|
753
|
-
});
|
|
754
|
-
}
|
|
755
|
-
}
|
|
756
|
-
);
|
|
757
|
-
void proxy;
|
|
758
|
-
return PARSE_FAILED;
|
|
759
|
-
} catch {
|
|
760
|
-
return PARSE_FAILED;
|
|
746
|
+
this.advance();
|
|
761
747
|
}
|
|
748
|
+
return PARSE_FAILED;
|
|
762
749
|
}
|
|
763
750
|
/**
|
|
764
751
|
* Look ahead to check if the next tokens form `.includes(`.
|
|
@@ -935,6 +922,76 @@ var Query = class _Query {
|
|
|
935
922
|
return map;
|
|
936
923
|
}
|
|
937
924
|
// -------------------------------------------------------------------------
|
|
925
|
+
// Batch compilation — used by db.batch() to extract SQL without executing
|
|
926
|
+
// -------------------------------------------------------------------------
|
|
927
|
+
/**
|
|
928
|
+
* @internal Compile this query into a SqlQuery for batch execution.
|
|
929
|
+
*
|
|
930
|
+
* Returns the compiled SQL query (if all predicates compile to SQL),
|
|
931
|
+
* or null (if JS fallback is needed). In the fallback case, a bare
|
|
932
|
+
* `SELECT *` is returned as `fallbackQuery` so the batch can fetch
|
|
933
|
+
* all rows and this query can filter them in JS post-fetch.
|
|
934
|
+
*/
|
|
935
|
+
_compile() {
|
|
936
|
+
const compiled = this._compilePredicates();
|
|
937
|
+
const sortField = this._sortAccessor ? extractFieldName(this._sortAccessor) : void 0;
|
|
938
|
+
if (compiled.allSql) {
|
|
939
|
+
const query = buildSelect(this._config.tableName, {
|
|
940
|
+
where: compiled.sqlWhere || void 0,
|
|
941
|
+
orderBy: sortField ?? void 0,
|
|
942
|
+
desc: this._reversed,
|
|
943
|
+
limit: this._limit,
|
|
944
|
+
offset: this._offset
|
|
945
|
+
});
|
|
946
|
+
return { query, fallbackQuery: null, config: this._config };
|
|
947
|
+
}
|
|
948
|
+
const fallbackQuery = buildSelect(this._config.tableName);
|
|
949
|
+
return {
|
|
950
|
+
query: null,
|
|
951
|
+
fallbackQuery,
|
|
952
|
+
config: this._config,
|
|
953
|
+
predicates: this._predicates,
|
|
954
|
+
sortAccessor: this._sortAccessor,
|
|
955
|
+
reversed: this._reversed,
|
|
956
|
+
limit: this._limit,
|
|
957
|
+
offset: this._offset
|
|
958
|
+
};
|
|
959
|
+
}
|
|
960
|
+
/**
|
|
961
|
+
* @internal Process raw SQL results into typed rows. Used by db.batch()
|
|
962
|
+
* after executing the compiled query.
|
|
963
|
+
*
|
|
964
|
+
* For SQL-compiled queries: just deserialize the rows.
|
|
965
|
+
* For JS-fallback queries: filter, sort, and slice in JS.
|
|
966
|
+
*/
|
|
967
|
+
static _processResults(result, compiled) {
|
|
968
|
+
const rows = result.rows.map(
|
|
969
|
+
(row) => deserializeRow(
|
|
970
|
+
row,
|
|
971
|
+
compiled.config.columns
|
|
972
|
+
)
|
|
973
|
+
);
|
|
974
|
+
if (compiled.query) return rows;
|
|
975
|
+
let filtered = compiled.predicates ? rows.filter((row) => compiled.predicates.every((pred) => pred(row))) : rows;
|
|
976
|
+
if (compiled.sortAccessor) {
|
|
977
|
+
const accessor = compiled.sortAccessor;
|
|
978
|
+
const reversed = compiled.reversed ?? false;
|
|
979
|
+
filtered.sort((a, b) => {
|
|
980
|
+
const aVal = accessor(a);
|
|
981
|
+
const bVal = accessor(b);
|
|
982
|
+
if (aVal < bVal) return reversed ? 1 : -1;
|
|
983
|
+
if (aVal > bVal) return reversed ? -1 : 1;
|
|
984
|
+
return 0;
|
|
985
|
+
});
|
|
986
|
+
}
|
|
987
|
+
if (compiled.offset != null || compiled.limit != null) {
|
|
988
|
+
const start = compiled.offset ?? 0;
|
|
989
|
+
const end = compiled.limit != null ? start + compiled.limit : void 0;
|
|
990
|
+
filtered = filtered.slice(start, end);
|
|
991
|
+
}
|
|
992
|
+
return filtered;
|
|
993
|
+
}
|
|
994
|
+
// -------------------------------------------------------------------------
|
|
938
995
|
// PromiseLike
|
|
939
996
|
// -------------------------------------------------------------------------
|
|
940
997
|
then(onfulfilled, onrejected) {
|
|
@@ -1180,7 +1237,49 @@ function createDb(databases, executeBatch) {
|
|
|
1180
1237
|
hours: (n) => n * 36e5,
|
|
1181
1238
|
minutes: (n) => n * 6e4,
|
|
1182
1239
|
ago: (ms) => Date.now() - ms,
|
|
1183
|
-
fromNow: (ms) => Date.now() + ms
|
|
1240
|
+
fromNow: (ms) => Date.now() + ms,
|
|
1241
|
+
// --- Batch execution ---
|
|
1242
|
+
batch: ((...queries) => {
|
|
1243
|
+
return (async () => {
|
|
1244
|
+
const compiled = queries.map((q) => {
|
|
1245
|
+
if (!(q instanceof Query)) {
|
|
1246
|
+
throw new MindStudioError(
|
|
1247
|
+
"db.batch() only accepts Query objects (from .filter(), .sortBy(), etc.)",
|
|
1248
|
+
"invalid_batch_query",
|
|
1249
|
+
400
|
|
1250
|
+
);
|
|
1251
|
+
}
|
|
1252
|
+
return q._compile();
|
|
1253
|
+
});
|
|
1254
|
+
const groups = /* @__PURE__ */ new Map();
|
|
1255
|
+
for (let i = 0; i < compiled.length; i++) {
|
|
1256
|
+
const c = compiled[i];
|
|
1257
|
+
const dbId = c.config.databaseId;
|
|
1258
|
+
const sqlQuery = c.query ?? c.fallbackQuery;
|
|
1259
|
+
if (!groups.has(dbId)) groups.set(dbId, []);
|
|
1260
|
+
groups.get(dbId).push({ index: i, sqlQuery });
|
|
1261
|
+
}
|
|
1262
|
+
const allResults = new Array(compiled.length);
|
|
1263
|
+
await Promise.all(
|
|
1264
|
+
Array.from(groups.entries()).map(async ([dbId, entries]) => {
|
|
1265
|
+
const sqlQueries = entries.map((e) => e.sqlQuery);
|
|
1266
|
+
const results = await executeBatch(dbId, sqlQueries);
|
|
1267
|
+
for (let i = 0; i < entries.length; i++) {
|
|
1268
|
+
allResults[entries[i].index] = results[i];
|
|
1269
|
+
}
|
|
1270
|
+
})
|
|
1271
|
+
);
|
|
1272
|
+
return compiled.map((c, i) => {
|
|
1273
|
+
const result = allResults[i];
|
|
1274
|
+
if (!c.query && c.predicates?.length) {
|
|
1275
|
+
console.warn(
|
|
1276
|
+
`[mindstudio] db.batch(): filter on ${c.config.tableName} could not be compiled to SQL \u2014 processing in JS`
|
|
1277
|
+
);
|
|
1278
|
+
}
|
|
1279
|
+
return Query._processResults(result, c);
|
|
1280
|
+
});
|
|
1281
|
+
})();
|
|
1282
|
+
})
|
|
1184
1283
|
};
|
|
1185
1284
|
}
|
|
1186
1285
|
function resolveTable(databases, tableName, databaseHint) {
|
|
@@ -2269,7 +2368,14 @@ var MindStudioAgent = class {
|
|
|
2269
2368
|
hours: (n) => n * 36e5,
|
|
2270
2369
|
minutes: (n) => n * 6e4,
|
|
2271
2370
|
ago: (ms) => Date.now() - ms,
|
|
2272
|
-
fromNow: (ms) => Date.now() + ms
|
|
2371
|
+
fromNow: (ms) => Date.now() + ms,
|
|
2372
|
+
// Batch needs context — hydrate first, then delegate to real db
|
|
2373
|
+
batch: ((...queries) => {
|
|
2374
|
+
return (async () => {
|
|
2375
|
+
await agent.ensureContext();
|
|
2376
|
+
return agent._db.batch(...queries);
|
|
2377
|
+
})();
|
|
2378
|
+
})
|
|
2273
2379
|
};
|
|
2274
2380
|
}
|
|
2275
2381
|
// -------------------------------------------------------------------------
|