Skip to content

Commit d1bbb5a

Browse files
committed
chore(libs): add development notes
1 parent 2642765 commit d1bbb5a

1 file changed

Lines changed: 352 additions & 0 deletions

File tree

Lines changed: 352 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,352 @@
1+
# Property & Tag Idents
2+
3+
## What is an Ident?
4+
5+
An **ident** is a unique keyword identifier for a property or tag in the database. It's distinct from:
6+
- **name**: Human-readable display name (e.g., "Created At")
7+
- **uuid**: Universal unique identifier for the entity
8+
- **ident**: Internal database identifier (e.g., `:logseq.property/created-at`)
9+
10+
**Key characteristics:**
11+
- Idents use kebab-case with namespace prefixes
12+
- System properties use `:logseq.property/` namespace
13+
- System class properties use `:logseq.class/` namespace
14+
- Plugin created class use `:plugin.class.xxx-plugin-id/` namespace
15+
- Plugin created property use `:plugin.property.xxx-plugin-id/` namespace
16+
- Custom properties typically don't have explicit idents (auto-generated)
17+
18+
## When to Use Idents
19+
20+
Use idents when:
21+
1. Working with **built-in system properties**
22+
2. Setting **special behaviors** for properties
23+
3. Querying the database directly with datascript
24+
4. Creating **stable references** that survive renames
25+
26+
**Example:**
27+
```typescript
28+
// Using ident for system property
29+
await logseq.Editor. upsertBlockProperty(
30+
blockId,
31+
':logseq. property/created-at', // ident
32+
new Date().getTime()
33+
)
34+
35+
// Using regular property name
36+
await logseq.Editor. upsertBlockProperty(
37+
blockId,
38+
'author', // regular name
39+
'John Doe'
40+
)
41+
```
42+
43+
---
44+
45+
## Built-in System Properties
46+
47+
### Common System Properties
48+
49+
#### `:logseq.property/created-at`
50+
Timestamp when the block/page was created.
51+
52+
```typescript
53+
await logseq.Editor.upsertBlockProperty(
54+
page.uuid,
55+
':logseq.property/created-at',
56+
Date.now()
57+
)
58+
```
59+
60+
#### `:logseq.property/updated-at`
61+
Timestamp when the block/page was last updated.
62+
63+
```typescript
64+
await logseq.Editor.upsertBlockProperty(
65+
block.uuid,
66+
':logseq.property/updated-at',
67+
Date.now()
68+
)
69+
```
70+
71+
#### `:logseq.property/icon`
72+
Icon for a page or block (set via `setBlockIcon` API).
73+
74+
```typescript
75+
// Don't set directly, use API:
76+
await logseq.Editor. setBlockIcon(page.uuid, 'emoji', 'book')
77+
78+
// Behind the scenes, this sets:
79+
// :logseq.property/icon {: type "emoji", :id "book"}
80+
```
81+
82+
#### `:logseq.property/hide-empty-value`
83+
Hide property when value is empty.
84+
85+
```typescript
86+
const prop = await logseq.Editor.upsertProperty('optional-field', {
87+
type: 'default'
88+
})
89+
90+
await logseq.Editor.upsertBlockProperty(
91+
prop. id, // Apply to property entity itself
92+
':logseq.property/hide-empty-value',
93+
true
94+
)
95+
```
96+
97+
#### `:logseq.property/closed-value-mode`
98+
Property only accepts predefined values (enum-like).
99+
100+
```typescript
101+
const prop = await logseq.Editor. upsertProperty('status', { type: 'default' })
102+
103+
await logseq.Editor.upsertBlockProperty(
104+
prop.id,
105+
':logseq.property/closed-value-mode',
106+
true
107+
)
108+
109+
// Define allowed values
110+
await logseq.Editor.upsertBlockProperty(
111+
prop. id,
112+
':logseq.property/closed-values',
113+
['todo', 'in-progress', 'done']
114+
)
115+
```
116+
117+
#### `:logseq.property/schema`
118+
Property schema definition (type, cardinality, etc.).
119+
120+
```typescript
121+
// Automatically set by upsertProperty, don't set manually
122+
await logseq.Editor. upsertProperty('tags', {
123+
type: 'node',
124+
cardinality: 'many'
125+
})
126+
127+
// Behind the scenes sets:
128+
// :logseq. property/schema {:type "node", :cardinality "many"}
129+
```
130+
131+
---
132+
133+
## Built-in Class (Tag) Properties
134+
135+
### Tag Inheritance & Schema
136+
137+
#### `:logseq.property. class/extends`
138+
Define parent classes (tag inheritance).
139+
140+
```typescript
141+
const mediaTag = await logseq.Editor.createTag('Media')
142+
const bookTag = await logseq. Editor.createTag('book')
143+
144+
// Use addTagExtends API (recommended)
145+
await logseq.Editor. addTagExtends(bookTag. uuid, mediaTag.uuid)
146+
147+
// Or set directly:
148+
await logseq.Editor. upsertBlockProperty(
149+
bookTag.uuid,
150+
': logseq.property.class/extends',
151+
[mediaTag.id] // Array of parent tag IDs
152+
)
153+
```
154+
155+
#### `:logseq.property.class/properties`
156+
Properties available for this class.
157+
158+
```typescript
159+
// Use addTagProperty API (recommended)
160+
await logseq.Editor.addTagProperty(bookTag.uuid, 'author')
161+
162+
// Or set directly:
163+
const authorProp = await logseq.Editor.getProperty('author')
164+
await logseq.Editor.upsertBlockProperty(
165+
bookTag.uuid,
166+
':logseq.property. class/properties',
167+
[authorProp.id]
168+
)
169+
```
170+
171+
---
172+
173+
## Working with Idents
174+
175+
### Pattern 1: Query by Ident
176+
177+
```typescript
178+
// Get property entity by ident
179+
const createdAtProp = await logseq. DB.datascriptQuery(`
180+
[: find (pull ?p [*])
181+
:where
182+
[?p :block/type "property"]
183+
[?p :block/ident : logseq.property/created-at]]
184+
`)
185+
186+
console.log(createdAtProp)
187+
```
188+
189+
### Pattern 2: Check if Property Has Ident
190+
191+
```typescript
192+
async function getPropertyIdent(propertyName: string) {
193+
const prop = await logseq.Editor. getProperty(propertyName)
194+
return prop?.ident || null
195+
}
196+
197+
const ident = await getPropertyIdent('created-at')
198+
// Returns: ": logseq.property/created-at" or null
199+
```
200+
201+
### Pattern 3: Create Custom Namespaced Property
202+
203+
```typescript
204+
// For plugin-specific properties, use your own namespace
205+
const pluginNamespace = 'myplugin'
206+
207+
async function createPluginProperty(name: string, schema: any) {
208+
// Note: Custom idents are not directly settable via API
209+
// They're auto-generated, but you can query by name
210+
211+
const prop = await logseq.Editor.upsertProperty(name, schema)
212+
213+
// Custom properties won't have idents unless they're system properties
214+
return prop
215+
}
216+
```
217+
218+
### Pattern 4: Set Multiple System Properties
219+
220+
```typescript
221+
async function setupPageMetadata(pageUUID: string, metadata: any) {
222+
const now = Date.now()
223+
224+
// Set creation timestamp
225+
await logseq. Editor.upsertBlockProperty(
226+
pageUUID,
227+
':logseq.property/created-at',
228+
metadata.createdAt || now
229+
)
230+
231+
// Set update timestamp
232+
await logseq. Editor.upsertBlockProperty(
233+
pageUUID,
234+
':logseq.property/updated-at',
235+
now
236+
)
237+
238+
// Set custom properties
239+
await logseq. Editor.upsertBlockProperty(pageUUID, 'author', metadata.author)
240+
await logseq.Editor.upsertBlockProperty(pageUUID, 'source', metadata.source)
241+
}
242+
```
243+
244+
### Pattern 5: Configure Property Behavior
245+
246+
```typescript
247+
async function createEnumProperty(name: string, allowedValues: string[]) {
248+
// 1. Create property
249+
const prop = await logseq.Editor.upsertProperty(name, { type: 'default' })
250+
251+
// 2. Enable closed-value mode
252+
await logseq.Editor.upsertBlockProperty(
253+
prop.id,
254+
':logseq.property/closed-value-mode',
255+
true
256+
)
257+
258+
// 3. Set allowed values
259+
await logseq.Editor. upsertBlockProperty(
260+
prop.id,
261+
':logseq.property/closed-values',
262+
allowedValues
263+
)
264+
265+
// 4. Optionally hide when empty
266+
await logseq. Editor.upsertBlockProperty(
267+
prop.id,
268+
':logseq.property/hide-empty-value',
269+
true
270+
)
271+
272+
return prop
273+
}
274+
275+
// Usage
276+
await createEnumProperty('priority', ['high', 'medium', 'low'])
277+
```
278+
279+
---
280+
281+
## System Property Reference Table
282+
283+
| Ident | Purpose | Value Type | Applied To |
284+
|-------|---------|------------|------------|
285+
| `:logseq.property/created-at` | Creation timestamp | number (ms) | Block/Page |
286+
| `:logseq.property/updated-at` | Update timestamp | number (ms) | Block/Page |
287+
| `:logseq.property/icon` | Icon definition | `{type, id}` object | Block/Page |
288+
| `:logseq.property/hide-empty-value` | Hide if empty | boolean | Property entity |
289+
| `:logseq.property/closed-value-mode` | Enum mode | boolean | Property entity |
290+
| `:logseq.property/closed-values` | Allowed values | array | Property entity |
291+
| `:logseq.property/schema` | Schema definition | object | Property entity |
292+
| `:logseq.property. class/extends` | Parent classes | array of IDs | Tag entity |
293+
| `:logseq.property.class/properties` | Class properties | array of IDs | Tag entity |
294+
295+
---
296+
297+
## Best Practices for Idents
298+
299+
### 1. Prefer High-Level APIs Over Direct Ident Manipulation
300+
Use specialized APIs instead of setting idents directly:
301+
302+
```typescript
303+
// ✅ Better: Use API
304+
await logseq.Editor.addTagExtends(childTag.uuid, parentTag.uuid)
305+
306+
// ❌ Avoid: Direct ident manipulation
307+
await logseq. Editor.upsertBlockProperty(
308+
childTag.uuid,
309+
': logseq.property. class/extends',
310+
[parentTag.id]
311+
)
312+
```
313+
314+
### 2. Only Use Idents for System Properties
315+
Custom properties should use regular names:
316+
317+
```typescript
318+
// ✅ Correct: System property with ident
319+
await logseq. Editor.upsertBlockProperty(
320+
page.uuid,
321+
': logseq.property/created-at',
322+
Date.now()
323+
)
324+
325+
// ✅ Correct: Custom property with name
326+
await logseq.Editor. upsertBlockProperty(
327+
page.uuid,
328+
'author',
329+
'John Doe'
330+
)
331+
332+
// ❌ Wrong: Don't create custom idents
333+
await logseq.Editor. upsertBlockProperty(
334+
page.uuid,
335+
':myplugin/custom-prop', // Not supported
336+
'value'
337+
)
338+
```
339+
340+
### 3. Query System Properties by Ident in Datascript
341+
When using advanced queries, idents provide stable references:
342+
343+
```typescript
344+
// Query all pages created in the last 7 days
345+
const recentPages = await logseq. DB.datascriptQuery(`
346+
[:find (pull ?p [*])
347+
:where
348+
[?p :block/type "page"]
349+
[?p : logseq.property/created-at ? created]
350+
[(> ?created ${Date.now() - 7 * 24 * 60 * 60 * 1000})]]
351+
`)
352+
```

0 commit comments

Comments
 (0)