@undefineds.co/drizzle-solid 0.3.1 → 0.3.2

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.
Files changed (3) hide show
  1. package/README.md +123 -163
  2. package/README.zh-CN.md +254 -0
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -1,104 +1,81 @@
1
1
  # drizzle-solid
2
2
 
3
- `drizzle-solid` is a Drizzle-aligned data layer for application-owned data in Solid Pods.
3
+ Chinese version: [`README.zh-CN.md`](README.zh-CN.md)
4
4
 
5
- 这次变化的重点不是强迫你把构造函数名字从 `drizzle()` 换成别的东西,而是把语义讲清楚:
5
+ `drizzle-solid` stores application-owned data in Solid Pods with typed schemas and a Drizzle-aligned developer experience.
6
6
 
7
- - `table` 更接近 **resource layout / collection definition**
8
- - `link` 字段更接近 **RDF link / IRI link**
9
- - 实体最终身份更接近 **IRI / @id**,而不只是本地主键
10
- - 读取和写入不再默认共享 SQL 式语义
7
+ Use it when you want:
11
8
 
12
- ## Scope
9
+ - TypeScript schemas for Pod data
10
+ - explicit Pod layout through `base` and `subjectTemplate`
11
+ - a choice between a Solid-first API (`pod()`) and a Drizzle-shaped API (`drizzle()`)
12
+ - exact entity reads and writes by IRI or locator
13
+ - SPARQL-backed reads when your backend exposes query capability
13
14
 
14
- Current v1 solves one problem well:
15
+ ## What it is good at
15
16
 
16
- - persist application-owned data into Solid Pods with typed schemas
17
- - keep Pod layout explicit through `base` and `subjectTemplate`
18
- - make full IRIs part of the public API instead of hiding them behind local-only IDs
19
- - give Drizzle users a migration-friendly surface without pretending Solid is a SQL database
20
- - support adjacent Solid flows such as discovery, notifications, and federation where they fit the Pod model
17
+ - application-owned data in your Pod or a user Pod
18
+ - typed CRUD over known resource layouts
19
+ - gradual migration from `drizzle-orm`
20
+ - Pod-native concepts such as IRIs, documents, links, discovery, notifications, and federation
21
21
 
22
- Not in v1:
22
+ ## What it is not trying to be
23
23
 
24
- - full SQL/database feature parity
25
- - raw SQL as the primary abstraction
26
- - hiding Pod boundaries, permissions, or network behavior
27
- - implicit scan-based `updateMany/deleteMany` on backends that do not support set-based mutation
28
- - universal querying over arbitrary open-world RDF as the main goal
29
-
30
- ## Constructor Choice
31
-
32
- 仓库文档与 examples 默认先用 `pod(session, config?)` 讲主线语义:
33
-
34
- - `pod(session, config?)`
35
- - `drizzle(session, config?)`
36
-
37
- 建议这样理解:
38
-
39
- - `pod()` 是语义优先的正式入口,方便把 API 组织成 `collection()` / `entity()` / `bind()`
40
- - `drizzle()` 是同一运行时上的 Drizzle-aligned 入口,适合迁移或保留 builder/query 代码形状
41
- - 重要的不是“入口名”,而是下面这些语义:`base`、`subjectTemplate`、`IRI`、exact-target mutation
42
-
43
- ## Public Surface
44
-
45
- 当前公开表面可以分成两层:
46
-
47
- ### Semantic-first surface
48
-
49
- - `pod(session, config?)`
50
- - `client.bind(schema, options)`
51
- - `client.collection(table)`
52
- - `client.entity(table, iri)`
53
- - `client.sparql(query)`
54
-
55
- ### Drizzle-aligned surface
56
-
57
- - `drizzle(session, config?)`
58
- - `podTable(name, columns, config)`
59
- - `solidSchema(...)`
60
- - `select / insert / update / delete`
61
- - `db.query.*` read facade
24
+ - a general-purpose RDF exploration toolkit
25
+ - full SQL/database parity across every Solid backend
26
+ - a library that hides Pod boundaries, permissions, or network costs
27
+ - a raw SQL-first abstraction
62
28
 
63
29
  ## Install
64
30
 
65
31
  ```bash
66
32
  yarn add @undefineds.co/drizzle-solid drizzle-orm
67
- # optional, when your app wants the default SPARQL client engine
33
+ # optional: install when your app wants the built-in SPARQL engine
68
34
  yarn add @comunica/query-sparql-solid
69
35
  ```
70
36
 
71
37
  ```bash
72
38
  npm install @undefineds.co/drizzle-solid drizzle-orm
39
+ # optional: install when your app wants the built-in SPARQL engine
73
40
  npm install @comunica/query-sparql-solid
74
41
  ```
75
42
 
76
43
  `@comunica/query-sparql-solid` is an optional peer dependency.
77
44
 
78
- Install it in the consuming app when you need built-in SPARQL query execution or direct SPARQL workflows.
45
+ Current support stance:
79
46
 
80
- Without a SPARQL endpoint or index, plain-LDP document mode is limited to exact-target access (`findByLocator` / `findByIri` and the matching update/delete APIs). Collection queries are not implicitly expanded into scans.
47
+ - supported: `@comunica/query-sparql-solid` `4.x`
48
+ - not in the current supported matrix: `3.x`
81
49
 
82
- Current public compatibility stance:
50
+ If another in-process runtime already ships Comunica, inject that engine instead of installing a second copy.
83
51
 
84
- - officially supported: `@comunica/query-sparql-solid` `4.x`
85
- - not currently in the supported matrix: `3.x`
52
+ ## Choose your API style
86
53
 
87
- If another in-process runtime already carries Comunica (for example `xpod`), inject that engine instead of forcing a second copy. See `docs/api/README.md` and `docs/guides/installation.md`.
54
+ ### `pod(session)`
88
55
 
89
- ## Quick start
56
+ Use this for new code when you want Solid concepts to be explicit in the API:
90
57
 
91
- 仓库里的主线 quick start 默认使用 `pod(session)`,因为它会把 `collection()` / `entity()` / `bind()` 语义直接写在代码里。
58
+ - `collection(table)`
59
+ - `entity(table, iri)`
60
+ - `bind(schema, options)`
61
+ - `sparql(query)`
92
62
 
93
- 如果你已有大量 Drizzle 风格代码,`drizzle(session)` 仍然是正式可用入口。
63
+ ### `drizzle(session)`
64
+
65
+ Use this when you are migrating from `drizzle-orm` or want to keep builder-shaped code:
66
+
67
+ - `select / insert / update / delete`
68
+ - `db.query.<table>`
69
+ - `findByLocator / findByIri`
70
+ - `updateByLocator / updateByIri`
71
+ - `deleteByLocator / deleteByIri`
72
+
73
+ Both styles use the same runtime. The difference is API shape, not storage behavior.
74
+
75
+ ## Quick start
94
76
 
95
77
  ```ts
96
- import {
97
- pod,
98
- podTable,
99
- string,
100
- datetime,
101
- } from '@undefineds.co/drizzle-solid';
78
+ import { pod, podTable, string, datetime } from '@undefineds.co/drizzle-solid';
102
79
 
103
80
  const posts = podTable('posts', {
104
81
  id: string('id').primaryKey(),
@@ -114,101 +91,104 @@ const posts = podTable('posts', {
114
91
  const client = pod(session);
115
92
  await client.init(posts);
116
93
 
117
- const postsCollection = client.collection(posts);
118
-
119
- const created = await postsCollection.create({
94
+ const created = await client.collection(posts).create({
120
95
  id: 'post-1',
121
96
  title: 'Hello Solid',
122
97
  content: 'Stored as RDF in a Pod document.',
123
98
  createdAt: new Date(),
124
99
  });
125
100
 
126
- const first = await postsCollection.first({
127
- where: { id: 'post-1' },
128
- });
101
+ if (!created) {
102
+ throw new Error('Create failed');
103
+ }
129
104
 
130
- const postIri = created?.['@id'] ?? postsCollection.iriFor({
131
- id: 'post-1',
132
- title: 'Hello Solid',
133
- content: 'Stored as RDF in a Pod document.',
134
- createdAt: new Date(),
135
- });
105
+ const post = client.entity(posts, created['@id']);
136
106
 
137
- const post = client.entity(posts, postIri);
107
+ console.log(await post.get());
138
108
  await post.update({ title: 'Updated title' });
139
109
  await post.delete();
140
110
  ```
141
111
 
142
- > 如果你保持 `drizzle(session)` 作为入口,语义并不会变:`base`、`subjectTemplate`、`IRI`、精确写目标这些约束仍然完全成立。
112
+ ## Drizzle-style exact operations
143
113
 
144
- ## Reusable schema + runtime binding
114
+ ```ts
115
+ import { drizzle, podTable, string } from '@undefineds.co/drizzle-solid';
145
116
 
146
- Use `solidSchema(...)` when you want to separate the reusable data shape from where that data lives in a Pod.
117
+ const posts = podTable('posts', {
118
+ id: string('id').primaryKey(),
119
+ title: string('title').predicate('http://schema.org/headline'),
120
+ }, {
121
+ base: 'https://alice.example/data/posts/',
122
+ subjectTemplate: '{id}.ttl',
123
+ type: 'http://schema.org/CreativeWork',
124
+ });
147
125
 
148
- 如果你使用 `pod()` façade:
126
+ const db = drizzle(session);
127
+ await db.init(posts);
149
128
 
150
- ```ts
151
- const client = pod(session);
152
- const profileTable = client.bind(profileSchema, {
153
- base: 'https://alice.example/profile/card',
129
+ await db.insert(posts).values({
130
+ id: 'post-1',
131
+ title: 'Hello Solid',
154
132
  });
155
- ```
156
133
 
157
- 如果你保持 `drizzle()` 入口:
134
+ const row = await db.findByLocator(posts, { id: 'post-1' });
158
135
 
159
- ```ts
160
- const db = drizzle(session);
161
- const profileTable = db.createTable(profileSchema, {
162
- base: 'https://alice.example/profile/card',
136
+ await db.updateByLocator(posts, { id: 'post-1' }, {
137
+ title: 'Updated title',
163
138
  });
139
+
140
+ await db.deleteByLocator(posts, { id: 'post-1' });
164
141
  ```
165
142
 
166
- ## Identity and placement
143
+ ## How Pod layout works
167
144
 
168
- `subjectTemplate` defines how application identity maps onto Pod resources.
145
+ Every model describes both shape and placement.
169
146
 
170
- Common patterns:
147
+ - `base` defines where documents live
148
+ - `subjectTemplate` defines how business fields map to an IRI
149
+ - `type` is the primary persisted `rdf:type`
171
150
 
172
- - `#{id}`: many entities inside one document
173
- - `{id}.ttl`: one document per entity
174
- - `{id}.ttl#it`: one document per entity with stable in-document fragment
175
- - `{chatId}/messages.ttl#{id}`: multi-variable layouts and partitioned resources
151
+ Common `subjectTemplate` patterns:
176
152
 
177
- If a layout uses multiple template variables, exact lookup is only exact when all required locator variables are present, or when you already hold the full IRI.
153
+ - `#{id}` many entities in one document
154
+ - `{id}.ttl` — one document per entity
155
+ - `{id}.ttl#it` — one document per entity with a stable fragment
156
+ - `{chatId}/messages.ttl#{id}` — partitioned layout with multiple locator variables
178
157
 
179
- 这不是命名细节,而是持久化语义本身。
158
+ If your template uses multiple variables, exact lookup requires either:
180
159
 
181
- ## Type hierarchy
160
+ - the full IRI, or
161
+ - a complete locator with every required variable
182
162
 
183
- Class hierarchy and instance typing are not the same thing.
163
+ ## Collection reads vs exact entity operations
184
164
 
185
- - `type` is the primary persisted `rdf:type` for an entity
186
- - `subClassOf` expresses schema / vocabulary hierarchy
187
- - by default, persisted instance data should keep one most-specific, authoritative `rdf:type`
188
- - do not persist both a base/table type and a business subtype on the same entity unless they carry genuinely different semantics
189
- - do not introduce parallel string-based type systems when the meaning is already carried by RDF class membership
190
- - if parent types must be materialized for no-inference environments, treat that as an explicit compatibility mode rather than the default stored shape
165
+ This is the most important runtime rule.
191
166
 
192
- ## Exact-target mutation semantics
167
+ ### Collection reads
193
168
 
194
- Reads and writes do not intentionally behave the same way.
169
+ Use collection reads when you want a list or filtered subset:
195
170
 
196
- - list / filter reads can stay collection-oriented
197
- - writes should prefer exact-target semantics
198
- - if an API path semantically requires exact-target resolution, it should remain exact or fail explicitly; do not silently widen it into scan-style execution
199
- - incomplete `where(...)` information should not silently degrade into scan + mutate
200
- - if a subject can only be resolved by multiple template variables, mutation should use an explicit IRI or provide all required variables
201
- - join on a multi-variable target should also provide all required locator variables, or join via full IRI values
202
- - do not silently degrade unresolved multi-variable joins into scan-style fallback
171
+ - `client.collection(table).list(...)`
172
+ - `db.select().from(table)...`
173
+ - `db.query.<table>.findMany(...)`
203
174
 
204
- 所以最重要的变化不是“要不要换成 `pod()`”,而是:
175
+ ### Exact entity operations
205
176
 
206
- - 什么时候你只是在做集合读取
207
- - 什么时候你已经需要一个确定的实体目标
177
+ Use exact-target helpers when you mean one concrete entity:
208
178
 
209
- ## Server support
179
+ - `client.entity(table, iri)`
180
+ - `db.findByIri(table, iri)`
181
+ - `db.findByLocator(table, locator)`
182
+ - `db.updateByIri(...)`
183
+ - `db.updateByLocator(...)`
184
+ - `db.deleteByIri(...)`
185
+ - `db.deleteByLocator(...)`
210
186
 
211
- ### Capability matrix
187
+ Do not rely on `where({ id: ... })` or `where(eq(table.id, ...))` as an exact-target shortcut.
188
+
189
+ ## SPARQL support and backend behavior
190
+
191
+ `drizzle-solid` works across different Solid runtimes, but capabilities differ.
212
192
 
213
193
  | Capability | Community Solid Server | xpod |
214
194
  | --- | --- | --- |
@@ -216,15 +196,19 @@ Reads and writes do not intentionally behave the same way.
216
196
  | Document notifications | ✅ | ✅ |
217
197
  | Drizzle-style read facade | ✅ | ✅ |
218
198
  | SPARQL pushdown | ⚠️ Limited / often client-assisted | ✅ Better in-process support |
219
- | Filter / aggregation pushdown | ❌ Mostly fallback execution | ✅ Better server-side support |
199
+ | Filter / aggregation pushdown | ❌ Mostly client-side execution | ✅ Better server-side support |
220
200
  | Federated queries | ⚠️ Client-side federation | ⚠️ Client-side federation |
221
201
  | In-process local runtime | ⚠️ External setup | ✅ via `@undefineds.co/xpod` |
222
202
 
223
- If `xpod` already ships its own Comunica stack, `drizzle-solid` can reuse that copy instead of requiring another app-level install.
203
+ Practical rule:
204
+
205
+ - if you have a SPARQL endpoint or sidecar, use it for collection queries
206
+ - if you only have plain LDP document access, exact-target reads and writes still work
207
+ - plain-LDP document mode does not silently widen exact operations into scans
224
208
 
225
- ## Verified examples
209
+ ## Examples
226
210
 
227
- The canonical examples in `examples/` are part of the real integration verification flow:
211
+ The canonical examples in `examples/` are part of the integration verification flow:
228
212
 
229
213
  - `examples/01-quick-start.ts`
230
214
  - `examples/02-relational-query.ts`
@@ -237,48 +221,24 @@ The canonical examples in `examples/` are part of the real integration verificat
237
221
  - `examples/08-schema-inheritance.ts`
238
222
  - `examples/09-multi-variable-templates.ts`
239
223
 
240
- See `examples/manifest.json` and `tests/integration/css/examples-verification.test.ts`.
224
+ ## Documentation
241
225
 
242
- ## Migration
243
-
244
- If you already know `drizzle-orm`, start here:
226
+ Start here:
245
227
 
228
+ - `docs/guides/installation.md`
229
+ - `docs/api/README.md`
246
230
  - `docs/guides/migrating-from-drizzle-orm.md`
247
-
248
- 那份指南重点解释的是:
249
-
250
- - `table/row` → `resource/document/entity/IRI`
251
- - `link` / relation fields → RDF link / IRI link
252
- - `where`-style mutation → exact-target mutation
253
- - `toSQL()` / raw SQL 主心智 → `toSPARQL()` / SPARQL 主心智
254
-
255
- 而不是要求你第一步先改掉构造函数名。
256
-
257
- ## Documentation map
258
-
259
- - `docs/api/README.md` — current public API and constructor positioning
260
- - `docs/guides/installation.md` — installation and SPARQL engine setup
261
- - `docs/guides/migrating-from-drizzle-orm.md` — migration guide for Drizzle users
262
- - `docs/guides/testing.md` — canonical testing policy, verification layers, and execution-path guardrails
263
- - `docs/guides/context7-and-skills.md` — Context7 publication scope, skills plan, and feedback flow
264
- - `docs/guides/issue-triage.md` — classify code, docs, tooling, and decision issues
265
- - `docs/guides/modeling-consensus.md` — when modeling questions require multi-AI consensus instead of a single answer
266
- - `docs/guides/decisions/README.md` — decision records and the template for stable repo-wide conclusions
267
- - `skills/README.md` — canonical public skill pack source for future Context7 Skills publishing
268
- - `examples/README.md` — curated runnable examples
269
- - `docs/guides/data-discovery.md` — discovery workflows
270
- - `docs/guides/notifications.md` — notification flows
271
- - `docs/xpod-features.md` — xpod runtime notes
272
- - `ACTION-PLAN.md` — testing/parity backlog and execution log, not the testing policy
231
+ - `docs/guides/multi-variable-templates.md`
232
+ - `docs/guides/notifications.md`
233
+ - `docs/guides/data-discovery.md`
273
234
 
274
235
  ## Contributing
275
236
 
276
237
  Before pushing:
277
238
 
278
239
  ```bash
279
- yarn build
280
- yarn lint
281
- SOLID_ENABLE_REAL_TESTS=true SOLID_SERIAL_TESTS=true yarn vitest --run --silent
240
+ yarn quality
241
+ SOLID_ENABLE_REAL_TESTS=true SOLID_SERIAL_TESTS=true yarn vitest --run tests/integration/css
282
242
  ```
283
243
 
284
244
  Examples must remain runnable and verified.
@@ -0,0 +1,254 @@
1
+ # drizzle-solid
2
+
3
+ English version: [`README.md`](README.md)
4
+
5
+ `drizzle-solid` 用类型化 schema 和 Drizzle 对齐的开发体验,把应用自有数据存进 Solid Pod。
6
+
7
+ 适合在你需要下面这些能力时使用:
8
+
9
+ - 用 TypeScript schema 描述 Pod 数据
10
+ - 用 `base` 和 `subjectTemplate` 明确声明数据布局
11
+ - 在 `pod()` 和 `drizzle()` 两种 API 风格之间选择
12
+ - 通过 IRI 或 locator 精确读写单个实体
13
+ - 在后端提供查询能力时走 SPARQL 读取
14
+
15
+ ## 它擅长什么
16
+
17
+ - 应用自有数据存储在你的 Pod 或用户 Pod 中
18
+ - 对已知资源布局做类型化 CRUD
19
+ - 从 `drizzle-orm` 逐步迁移,而不假装 Pod 就是 SQL 表
20
+ - 使用 IRI、文档、链接、发现、通知、联邦等 Pod 原生概念
21
+
22
+ ## 它不打算做什么
23
+
24
+ - 通用 RDF 图探索工具
25
+ - 所有 Solid 后端上的完整 SQL / 数据库能力对齐
26
+ - 隐藏 Pod 边界、权限或网络成本
27
+ - raw SQL 优先的抽象层
28
+
29
+ ## 安装
30
+
31
+ ```bash
32
+ yarn add @undefineds.co/drizzle-solid drizzle-orm
33
+ # 可选:当你的应用需要内置 SPARQL 引擎时再安装
34
+ yarn add @comunica/query-sparql-solid
35
+ ```
36
+
37
+ ```bash
38
+ npm install @undefineds.co/drizzle-solid drizzle-orm
39
+ # 可选:当你的应用需要内置 SPARQL 引擎时再安装
40
+ npm install @comunica/query-sparql-solid
41
+ ```
42
+
43
+ `@comunica/query-sparql-solid` 是可选 peer dependency。
44
+
45
+ 当前支持范围:
46
+
47
+ - 支持:`@comunica/query-sparql-solid` `4.x`
48
+ - 当前不在支持矩阵中:`3.x`
49
+
50
+ 如果宿主运行时已经自带 Comunica,就注入那一份,不要再装第二份。
51
+
52
+ ## 选择 API 风格
53
+
54
+ ### `pod(session)`
55
+
56
+ 适合新代码,或者你希望 API 直接体现 Solid 语义:
57
+
58
+ - `collection(table)`
59
+ - `entity(table, iri)`
60
+ - `bind(schema, options)`
61
+ - `sparql(query)`
62
+
63
+ ### `drizzle(session)`
64
+
65
+ 适合从 `drizzle-orm` 迁移,或者你想保留 builder 形状:
66
+
67
+ - `select / insert / update / delete`
68
+ - `db.query.<table>`
69
+ - `findByLocator / findByIri`
70
+ - `updateByLocator / updateByIri`
71
+ - `deleteByLocator / deleteByIri`
72
+
73
+ 两者底层是同一个运行时。区别是 API 组织方式,不是存储行为。
74
+
75
+ ## 快速开始
76
+
77
+ ```ts
78
+ import { pod, podTable, string, datetime } from '@undefineds.co/drizzle-solid';
79
+
80
+ const posts = podTable('posts', {
81
+ id: string('id').primaryKey(),
82
+ title: string('title').predicate('http://schema.org/headline'),
83
+ content: string('content').predicate('http://schema.org/text'),
84
+ createdAt: datetime('createdAt').predicate('http://schema.org/dateCreated'),
85
+ }, {
86
+ base: 'https://alice.example/data/posts/',
87
+ subjectTemplate: '{id}.ttl',
88
+ type: 'http://schema.org/CreativeWork',
89
+ });
90
+
91
+ const client = pod(session);
92
+ await client.init(posts);
93
+
94
+ const created = await client.collection(posts).create({
95
+ id: 'post-1',
96
+ title: 'Hello Solid',
97
+ content: 'Stored as RDF in a Pod document.',
98
+ createdAt: new Date(),
99
+ });
100
+
101
+ if (!created) {
102
+ throw new Error('Create failed');
103
+ }
104
+
105
+ const post = client.entity(posts, created['@id']);
106
+
107
+ console.log(await post.get());
108
+ await post.update({ title: 'Updated title' });
109
+ await post.delete();
110
+ ```
111
+
112
+ ## Drizzle 风格的精确操作
113
+
114
+ ```ts
115
+ import { drizzle, podTable, string } from '@undefineds.co/drizzle-solid';
116
+
117
+ const posts = podTable('posts', {
118
+ id: string('id').primaryKey(),
119
+ title: string('title').predicate('http://schema.org/headline'),
120
+ }, {
121
+ base: 'https://alice.example/data/posts/',
122
+ subjectTemplate: '{id}.ttl',
123
+ type: 'http://schema.org/CreativeWork',
124
+ });
125
+
126
+ const db = drizzle(session);
127
+ await db.init(posts);
128
+
129
+ await db.insert(posts).values({
130
+ id: 'post-1',
131
+ title: 'Hello Solid',
132
+ });
133
+
134
+ const row = await db.findByLocator(posts, { id: 'post-1' });
135
+
136
+ await db.updateByLocator(posts, { id: 'post-1' }, {
137
+ title: 'Updated title',
138
+ });
139
+
140
+ await db.deleteByLocator(posts, { id: 'post-1' });
141
+ ```
142
+
143
+ ## Pod 布局怎么理解
144
+
145
+ 每个模型不仅描述字段,也描述落点。
146
+
147
+ - `base` 决定文档位置
148
+ - `subjectTemplate` 决定业务字段如何映射成 IRI
149
+ - `type` 是主持久化 `rdf:type`
150
+
151
+ 常见 `subjectTemplate`:
152
+
153
+ - `#{id}`:一个文档里多个实体
154
+ - `{id}.ttl`:一个实体一个文档
155
+ - `{id}.ttl#it`:一个实体一个文档,并带稳定 fragment
156
+ - `{chatId}/messages.ttl#{id}`:多变量分区布局
157
+
158
+ 如果模板用了多个变量,精确定位就必须提供:
159
+
160
+ - 完整 IRI,或
161
+ - 完整 locator
162
+
163
+ ## 集合读取 vs 精确实体操作
164
+
165
+ 这是最重要的一条运行时规则。
166
+
167
+ ### 集合读取
168
+
169
+ 当你要拿一批数据时,用:
170
+
171
+ - `client.collection(table).list(...)`
172
+ - `db.select().from(table)...`
173
+ - `db.query.<table>.findMany(...)`
174
+
175
+ ### 精确实体操作
176
+
177
+ 当你要操作一个明确实体时,用:
178
+
179
+ - `client.entity(table, iri)`
180
+ - `db.findByIri(table, iri)`
181
+ - `db.findByLocator(table, locator)`
182
+ - `db.updateByIri(...)`
183
+ - `db.updateByLocator(...)`
184
+ - `db.deleteByIri(...)`
185
+ - `db.deleteByLocator(...)`
186
+
187
+ 不要再把 `where({ id: ... })` 或 `where(eq(table.id, ...))` 当成精确单体捷径。
188
+
189
+ ## SPARQL 支持与后端差异
190
+
191
+ `drizzle-solid` 可以跑在不同 Solid 运行时上,但能力有差异。
192
+
193
+ | 能力 | Community Solid Server | xpod |
194
+ | --- | --- | --- |
195
+ | 基础 CRUD | ✅ | ✅ |
196
+ | 文档通知 | ✅ | ✅ |
197
+ | Drizzle 风格读 facade | ✅ | ✅ |
198
+ | SPARQL 下推 | ⚠️ 有限 / 经常依赖客户端辅助 | ✅ 更好的进程内支持 |
199
+ | 过滤 / 聚合下推 | ❌ 多数走客户端执行 | ✅ 更好的服务端支持 |
200
+ | 联邦查询 | ⚠️ 客户端联邦 | ⚠️ 客户端联邦 |
201
+ | 进程内本地运行时 | ⚠️ 需要额外启动 | ✅ 通过 `@undefineds.co/xpod` |
202
+
203
+ 实用规则:
204
+
205
+ - 有 SPARQL endpoint 或 sidecar 时,集合查询优先走它
206
+ - 只有 plain LDP document access 时,精确读写仍然可用
207
+ - plain-LDP document mode 不会把精确操作静默扩成扫描
208
+
209
+ ## 示例
210
+
211
+ 仓库里的标准示例会进入集成验证:
212
+
213
+ - `examples/01-quick-start.ts`
214
+ - `examples/02-relational-query.ts`
215
+ - `examples/03-zero-config-discovery.ts`
216
+ - `examples/04-notifications.ts`
217
+ - `examples/05-data-discovery.ts`
218
+ - `examples/06-federated-query.ts`
219
+ - `examples/07-hooks-and-profile.ts`
220
+ - `examples/08-iri-based-operations.ts`
221
+ - `examples/08-schema-inheritance.ts`
222
+ - `examples/09-multi-variable-templates.ts`
223
+
224
+ ## 文档入口
225
+
226
+ 建议从这里开始:
227
+
228
+ - `docs/guides/installation.zh-CN.md`
229
+ - `docs/api/README.zh-CN.md`
230
+ - `docs/guides/migrating-from-drizzle-orm.zh-CN.md`
231
+ - `docs/guides/multi-variable-templates.zh-CN.md`
232
+ - `docs/guides/notifications.md`
233
+ - `docs/guides/data-discovery.md`
234
+
235
+ ## 贡献
236
+
237
+ 推送前运行:
238
+
239
+ ```bash
240
+ yarn quality
241
+ SOLID_ENABLE_REAL_TESTS=true SOLID_SERIAL_TESTS=true yarn vitest --run tests/integration/css
242
+ ```
243
+
244
+ 示例必须保持可运行且已验证。
245
+
246
+ ## License
247
+
248
+ MIT
249
+
250
+ ## 相关链接
251
+
252
+ - GitHub: https://github.com/undefinedsco/drizzle-solid
253
+ - npm: https://www.npmjs.com/package/@undefineds.co/drizzle-solid
254
+ - xpod: https://github.com/undefinedsco/xpod
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@undefineds.co/drizzle-solid",
3
- "version": "0.3.1",
3
+ "version": "0.3.2",
4
4
  "description": "Drizzle ORM adapter for Solid Pods",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",