Conversation
arosenan
force-pushed
the
entities-scan-free-primitives
branch
from
September 16, 2026 09:32
ddf8859 to
1296c13
Compare
arosenan
force-pushed
the
entities-scan-free-primitives
branch
from
September 16, 2026 09:33
1296c13 to
6140f95
Compare
…egate, upsert Wraps the scan-free entity routes added in base44-dev/apper#24939. Fifty apps with the deepest `skip` reads were reviewed; none paged because a user asked for page N. Every loop existed to get a number, to check whether a key already exists, to walk a table with a resume point that is not an offset, or to list a field's distinct values. - list(options) / filter(query, options): pass an options object {sort, limit, cursor, fields} instead of positional args to read one cursor page; returns {items, next_cursor, has_more}. Positional calls are unchanged. skip is documented as deprecated for loops. - count(query?): number of readable records matching a filter. - distinct(field, query?): {values, truncated}, capped at 5000 values. - aggregate(spec): group_by / date_bucket / count / sum / avg / min / max / count_distinct / having / sort / limit; returns {rows, truncated}. - upsert(records, {key}): create or update by a natural key, up to 500 records. New public types are exported and listed in types-to-expose.json. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
arosenan
force-pushed
the
entities-scan-free-primitives
branch
from
September 16, 2026 09:50
6140f95 to
c8f9b30
Compare
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…rameter Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
- aggregate spec: `query` (not `match`), camelCase keys (`groupBy`, `dateBucket`, `countDistinct`), and no rule against combining countDistinct with other measures - cursor pages default to 100 rows; the maximum stays 5,000 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
A cursor token now carries the query, sort and fields of the walk, so a later page needs only cursor and limit (same model as Wix Data cursorPaging). distinct moves out of aggregate-only usage into an option on list()/filter() that returns a page of values, matching how query APIs usually expose it. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
netanelgilad
approved these changes
Sep 17, 2026
| }, | ||
|
|
||
| // Count entities matching a query | ||
| async count(query?: EntityFilterQuery<T>): Promise<number> { |
Collaborator
| */ | ||
| cursor?: string | null; | ||
| /** Array of field names to include in each record. Defaults to all fields. */ | ||
| fields?: K[]; |
Collaborator
There was a problem hiding this comment.
why not expose it in the mongo way of 1 or 0? calling it projection to be more mongo compatible?
aggregate(stages[]) posts { pipeline } to the same route; field names are the
entity's own and the server translates them. The spec form stays the primary,
typed API; the pipeline is the escape hatch for what the spec cannot express.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
… index use" This reverts commit 8128270.
This reverts commit cd90cc1.
Contributor
Author
|
Superseded by #287, the same branch pushed to this repo so the preview-publish workflow can publish a testable package (OIDC trusted publishing is not available to PRs from forks). |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Why
Fifty apps with the deepest
skipreads on the entities cluster were reviewed. None of them pages because a user asked for page N. Every deep-skip loop exists to get something the SDK cannot give:aggregate(),count()upsert(),aggregate({ having })list()/filter()distinctoption onlist()/filter()Three apps built binary search with limit-1 probes as a substitute for
count(skips of 10.2M, 900k and 64k). Builders persistlastSkipas a resume token because nothing else exists.The server routes land in base44-dev/apper#24939. This PR is the SDK half, and its purpose right now is to settle the API shape. Version stays 0.8.x: everything is additive, so existing apps on
^0.8.xpick it up on their next install.Proposed API
Design notes:
cursorPaging: a later page needs onlycursorandlimit, and a different query or sort with a cursor is a 400 rather than silently ignored. The server re-sanitizes the query and applies scope and RLS on every page, so the token adds no new trust.distinctis an option onlist()/filter(), likedistinct()on a Wix Data or Mongo query, rather than a group-by spelled throughaggregate(). It returns the same page envelope with values as items.list()/filter()rather than a new method, matching Stripe/Firestore/Prisma. Passing an options object is what switches the return type to a page envelope; positional calls keep returning arrays, so no existing code changes.skipstays and is documented as deprecated for loops. The options form defaults to 100 rows per page (Notion-style), the positional form keeps its 5,000 default.querylikefilter(query), spec keys are camelCase like the SDK's methods; server-produced fields stay snake_case (next_cursor,has_more,sum_amount) likecreated_date.updateManyis unchanged here. Making it update every match, instead of batches the caller loops over, is a server-side change tracked in the backend PR.What
list(options)/filter(query, options)→GET /{entity}/v2/list→EntityPage<T>;EntityListOptions<T, K>typed against the schema. WithEntityDistinctOptions<T, K>({ distinct, limit, cursor }) the same route returnsEntityPage<T[K]>. Same route family as list, versioned like/conversations/v2/…in the agents module; the backend route takes this path once the API is closed.count(query?)→GET /{entity}/count?q=→number.aggregate(spec)→POST /{entity}/aggregate→EntityAggregateResult(server caps at 1000 rows);EntityAggregateSpec<T>typed against the schema. Spec keys arequery,groupBy,dateBucket,count,sum,avg,min,max,countDistinct,having,sort,limit; the spec is the wire body.upsert(records, { key })→POST /{entity}/upsert→EntityUpsertResult<T>.New types are exported from the package entry and listed in
types-to-expose.jsonfor the docs pipeline. JSDoc follows thesdk-docs-writingskill: description, params, returns, examples on every method.Tests
tests/unit/entities-primitives.test.ts: nock tests for each route, params and body; positionallist/filterstill hit the list route and return arrays.tests/types/entities-primitives.types.ts: spec and option fields are tied to the entity type; unknown fields, units, sorts and keys fail to compile.npm run build,npm run test:types,npm run test:unit(308 tests) andnpm run lintpass.No version bump, following the repo's separate
chore: bump versioncommits.🤖 Generated with Claude Code