@undefineds.co/drizzle-solid 0.2.7 → 0.2.9
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/CHANGELOG-DRAFT.md +444 -0
- package/dist/core/ast-to-sparql.d.ts +1 -6
- package/dist/core/ast-to-sparql.d.ts.map +1 -1
- package/dist/core/ast-to-sparql.js +3 -22
- package/dist/core/ast-to-sparql.js.map +1 -1
- package/dist/core/execution/ldp-executor.d.ts +8 -7
- package/dist/core/execution/ldp-executor.d.ts.map +1 -1
- package/dist/core/execution/ldp-executor.js +106 -126
- package/dist/core/execution/ldp-executor.js.map +1 -1
- package/dist/core/execution/pod-executor.d.ts.map +1 -1
- package/dist/core/execution/pod-executor.js +9 -0
- package/dist/core/execution/pod-executor.js.map +1 -1
- package/dist/core/execution/sparql-strategy.d.ts +7 -26
- package/dist/core/execution/sparql-strategy.d.ts.map +1 -1
- package/dist/core/execution/sparql-strategy.js +40 -96
- package/dist/core/execution/sparql-strategy.js.map +1 -1
- package/dist/core/execution/types.d.ts +8 -8
- package/dist/core/execution/types.d.ts.map +1 -1
- package/dist/core/pod-database.d.ts +0 -4
- package/dist/core/pod-database.d.ts.map +1 -1
- package/dist/core/pod-database.js +8 -32
- package/dist/core/pod-database.js.map +1 -1
- package/dist/core/pod-dialect.d.ts +10 -24
- package/dist/core/pod-dialect.d.ts.map +1 -1
- package/dist/core/pod-dialect.js +19 -182
- package/dist/core/pod-dialect.js.map +1 -1
- package/dist/core/pod-session.d.ts +6 -2
- package/dist/core/pod-session.d.ts.map +1 -1
- package/dist/core/pod-session.js +8 -2
- package/dist/core/pod-session.js.map +1 -1
- package/dist/core/query-builders/select-query-builder.d.ts.map +1 -1
- package/dist/core/query-builders/select-query-builder.js +0 -13
- package/dist/core/query-builders/select-query-builder.js.map +1 -1
- package/dist/core/query-conditions.d.ts.map +1 -1
- package/dist/core/query-conditions.js.map +1 -1
- package/dist/core/resource-resolver/base-resolver.d.ts.map +1 -1
- package/dist/core/resource-resolver/base-resolver.js +9 -1
- package/dist/core/resource-resolver/base-resolver.js.map +1 -1
- package/dist/core/resource-resolver/document-resolver.d.ts.map +1 -1
- package/dist/core/resource-resolver/document-resolver.js +51 -8
- package/dist/core/resource-resolver/document-resolver.js.map +1 -1
- package/dist/core/runtime/pod-runtime.d.ts +25 -0
- package/dist/core/runtime/pod-runtime.d.ts.map +1 -1
- package/dist/core/runtime/pod-runtime.js +67 -0
- package/dist/core/runtime/pod-runtime.js.map +1 -1
- package/dist/core/sparql/builder/select-builder.d.ts.map +1 -1
- package/dist/core/sparql/builder/select-builder.js +8 -1
- package/dist/core/sparql/builder/select-builder.js.map +1 -1
- package/dist/core/subject/index.js +1 -1
- package/dist/core/subject/index.js.map +1 -1
- package/dist/core/subject/resolver.js +2 -2
- package/dist/core/subject/types.d.ts +8 -1
- package/dist/core/subject/types.d.ts.map +1 -1
- package/dist/core/triple/builder.d.ts.map +1 -1
- package/dist/core/triple/builder.js +2 -3
- package/dist/core/triple/builder.js.map +1 -1
- package/dist/core/typeindex-manager.d.ts +6 -0
- package/dist/core/typeindex-manager.d.ts.map +1 -1
- package/dist/core/typeindex-manager.js +21 -0
- package/dist/core/typeindex-manager.js.map +1 -1
- package/dist/core/uri/resolver.d.ts.map +1 -1
- package/dist/core/uri/resolver.js +1 -7
- package/dist/core/uri/resolver.js.map +1 -1
- package/dist/core/uri/types.d.ts +0 -3
- package/dist/core/uri/types.d.ts.map +1 -1
- package/dist/driver.d.ts +5 -0
- package/dist/driver.d.ts.map +1 -1
- package/dist/driver.js +1 -0
- package/dist/driver.js.map +1 -1
- package/dist/esm/core/ast-to-sparql.d.ts +1 -6
- package/dist/esm/core/ast-to-sparql.d.ts.map +1 -1
- package/dist/esm/core/ast-to-sparql.js +3 -22
- package/dist/esm/core/ast-to-sparql.js.map +1 -1
- package/dist/esm/core/execution/ldp-executor.d.ts +8 -7
- package/dist/esm/core/execution/ldp-executor.d.ts.map +1 -1
- package/dist/esm/core/execution/ldp-executor.js +106 -126
- package/dist/esm/core/execution/ldp-executor.js.map +1 -1
- package/dist/esm/core/execution/pod-executor.d.ts.map +1 -1
- package/dist/esm/core/execution/pod-executor.js +9 -0
- package/dist/esm/core/execution/pod-executor.js.map +1 -1
- package/dist/esm/core/execution/sparql-strategy.d.ts +7 -26
- package/dist/esm/core/execution/sparql-strategy.d.ts.map +1 -1
- package/dist/esm/core/execution/sparql-strategy.js +40 -96
- package/dist/esm/core/execution/sparql-strategy.js.map +1 -1
- package/dist/esm/core/execution/types.d.ts +8 -8
- package/dist/esm/core/execution/types.d.ts.map +1 -1
- package/dist/esm/core/pod-database.d.ts +0 -4
- package/dist/esm/core/pod-database.d.ts.map +1 -1
- package/dist/esm/core/pod-database.js +8 -32
- package/dist/esm/core/pod-database.js.map +1 -1
- package/dist/esm/core/pod-dialect.d.ts +10 -24
- package/dist/esm/core/pod-dialect.d.ts.map +1 -1
- package/dist/esm/core/pod-dialect.js +19 -182
- package/dist/esm/core/pod-dialect.js.map +1 -1
- package/dist/esm/core/pod-session.d.ts +6 -2
- package/dist/esm/core/pod-session.d.ts.map +1 -1
- package/dist/esm/core/pod-session.js +8 -2
- package/dist/esm/core/pod-session.js.map +1 -1
- package/dist/esm/core/query-builders/select-query-builder.d.ts.map +1 -1
- package/dist/esm/core/query-builders/select-query-builder.js +0 -13
- package/dist/esm/core/query-builders/select-query-builder.js.map +1 -1
- package/dist/esm/core/query-conditions.d.ts.map +1 -1
- package/dist/esm/core/query-conditions.js.map +1 -1
- package/dist/esm/core/resource-resolver/base-resolver.d.ts.map +1 -1
- package/dist/esm/core/resource-resolver/base-resolver.js +9 -1
- package/dist/esm/core/resource-resolver/base-resolver.js.map +1 -1
- package/dist/esm/core/resource-resolver/document-resolver.d.ts.map +1 -1
- package/dist/esm/core/resource-resolver/document-resolver.js +51 -8
- package/dist/esm/core/resource-resolver/document-resolver.js.map +1 -1
- package/dist/esm/core/runtime/pod-runtime.d.ts +25 -0
- package/dist/esm/core/runtime/pod-runtime.d.ts.map +1 -1
- package/dist/esm/core/runtime/pod-runtime.js +67 -0
- package/dist/esm/core/runtime/pod-runtime.js.map +1 -1
- package/dist/esm/core/sparql/builder/select-builder.d.ts.map +1 -1
- package/dist/esm/core/sparql/builder/select-builder.js +8 -1
- package/dist/esm/core/sparql/builder/select-builder.js.map +1 -1
- package/dist/esm/core/subject/index.js +1 -1
- package/dist/esm/core/subject/index.js.map +1 -1
- package/dist/esm/core/subject/resolver.js +2 -2
- package/dist/esm/core/subject/types.d.ts +8 -1
- package/dist/esm/core/subject/types.d.ts.map +1 -1
- package/dist/esm/core/triple/builder.d.ts.map +1 -1
- package/dist/esm/core/triple/builder.js +2 -3
- package/dist/esm/core/triple/builder.js.map +1 -1
- package/dist/esm/core/typeindex-manager.d.ts +6 -0
- package/dist/esm/core/typeindex-manager.d.ts.map +1 -1
- package/dist/esm/core/typeindex-manager.js +21 -0
- package/dist/esm/core/typeindex-manager.js.map +1 -1
- package/dist/esm/core/uri/resolver.d.ts.map +1 -1
- package/dist/esm/core/uri/resolver.js +1 -7
- package/dist/esm/core/uri/resolver.js.map +1 -1
- package/dist/esm/core/uri/types.d.ts +0 -3
- package/dist/esm/core/uri/types.d.ts.map +1 -1
- package/dist/esm/driver.d.ts +5 -0
- package/dist/esm/driver.d.ts.map +1 -1
- package/dist/esm/driver.js +1 -0
- package/dist/esm/driver.js.map +1 -1
- package/dist/esm/index.d.ts +1 -0
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/utils/webid-resolver.d.ts +24 -0
- package/dist/esm/utils/webid-resolver.d.ts.map +1 -0
- package/dist/esm/utils/webid-resolver.js +69 -0
- package/dist/esm/utils/webid-resolver.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/utils/webid-resolver.d.ts +24 -0
- package/dist/utils/webid-resolver.d.ts.map +1 -0
- package/dist/utils/webid-resolver.js +73 -0
- package/dist/utils/webid-resolver.js.map +1 -0
- package/package.json +1 -1
- package/dist/core/pod-table.d.ts +0 -710
- package/dist/core/pod-table.d.ts.map +0 -1
- package/dist/core/pod-table.js +0 -1300
- package/dist/core/pod-table.js.map +0 -1
- package/dist/core/publish-manager.d.ts +0 -90
- package/dist/core/publish-manager.d.ts.map +0 -1
- package/dist/core/publish-manager.js +0 -147
- package/dist/core/publish-manager.js.map +0 -1
- package/dist/esm/core/pod-table.d.ts +0 -710
- package/dist/esm/core/pod-table.d.ts.map +0 -1
- package/dist/esm/core/pod-table.js +0 -1249
- package/dist/esm/core/pod-table.js.map +0 -1
- package/dist/esm/core/publish-manager.d.ts +0 -90
- package/dist/esm/core/publish-manager.d.ts.map +0 -1
- package/dist/esm/core/publish-manager.js +0 -143
- package/dist/esm/core/publish-manager.js.map +0 -1
package/dist/core/pod-table.js
DELETED
|
@@ -1,1300 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var _a, _b;
|
|
3
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
-
exports.RDF_CLASSES = exports.RDF_PREDICATES = exports.PodTable = exports.SolidSchema = exports.PodArrayColumn = exports.PodUriColumn = exports.PodObjectColumn = exports.PodJsonColumn = exports.PodDateTimeColumn = exports.PodBooleanColumn = exports.PodIntegerColumn = exports.PodStringColumn = exports.PodColumnBase = exports.ColumnBuilder = void 0;
|
|
5
|
-
exports.solidSchema = solidSchema;
|
|
6
|
-
exports.isSolidSchema = isSolidSchema;
|
|
7
|
-
exports.boolean = boolean;
|
|
8
|
-
exports.timestamp = timestamp;
|
|
9
|
-
exports.json = json;
|
|
10
|
-
exports.object = object;
|
|
11
|
-
exports.uri = uri;
|
|
12
|
-
exports.iri = iri;
|
|
13
|
-
exports.podString = podString;
|
|
14
|
-
exports.podInteger = podInteger;
|
|
15
|
-
exports.podBoolean = podBoolean;
|
|
16
|
-
exports.podDateTime = podDateTime;
|
|
17
|
-
exports.podJson = podJson;
|
|
18
|
-
exports.podObject = podObject;
|
|
19
|
-
exports.id = id;
|
|
20
|
-
exports.string = string;
|
|
21
|
-
exports.int = int;
|
|
22
|
-
exports.integer = integer;
|
|
23
|
-
exports.date = date;
|
|
24
|
-
exports.datetime = datetime;
|
|
25
|
-
exports.text = text;
|
|
26
|
-
exports.varchar = varchar;
|
|
27
|
-
exports.char = char;
|
|
28
|
-
exports.bigint = bigint;
|
|
29
|
-
exports.smallint = smallint;
|
|
30
|
-
exports.tinyint = tinyint;
|
|
31
|
-
exports.mediumint = mediumint;
|
|
32
|
-
exports.serial = serial;
|
|
33
|
-
exports.real = real;
|
|
34
|
-
exports.decimal = decimal;
|
|
35
|
-
exports.numeric = numeric;
|
|
36
|
-
exports.float = float;
|
|
37
|
-
exports.double = double;
|
|
38
|
-
exports.jsonb = jsonb;
|
|
39
|
-
exports.podTable = podTable;
|
|
40
|
-
exports.relations = relations;
|
|
41
|
-
const drizzle_orm_1 = require("drizzle-orm");
|
|
42
|
-
// NanoID-like ID Generator (URL-friendly, cryptographically strong)
|
|
43
|
-
const urlAlphabet = 'useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict';
|
|
44
|
-
const generateNanoId = (size = 21) => {
|
|
45
|
-
let id = '';
|
|
46
|
-
// Use crypto for randomness (browser & modern Node)
|
|
47
|
-
let bytes;
|
|
48
|
-
if (typeof globalThis.crypto !== 'undefined' && typeof globalThis.crypto.getRandomValues === 'function') {
|
|
49
|
-
bytes = globalThis.crypto.getRandomValues(new Uint8Array(size));
|
|
50
|
-
}
|
|
51
|
-
else {
|
|
52
|
-
// Fallback for older Node.js or environments without Web Crypto API (less secure)
|
|
53
|
-
// For Node.js, require('crypto') might be an option but we avoid dynamic require for bundling.
|
|
54
|
-
// This fallback is less secure but prevents crashes.
|
|
55
|
-
console.warn("Using Math.random fallback for NanoID generation. Consider polyfilling crypto or upgrading Node.js for production.");
|
|
56
|
-
bytes = new Uint8Array(size);
|
|
57
|
-
for (let i = 0; i < size; i++) {
|
|
58
|
-
bytes[i] = Math.floor(Math.random() * 256); // Fill with pseudo-random bytes
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
for (let i = 0; i < size; i++) {
|
|
62
|
-
id += urlAlphabet[bytes[i] % urlAlphabet.length];
|
|
63
|
-
}
|
|
64
|
-
return id;
|
|
65
|
-
};
|
|
66
|
-
const hasStringValue = (input) => typeof input === 'object' && input !== null && typeof input.value === 'string';
|
|
67
|
-
const hasTermValue = (input) => typeof input === 'object' && input !== null &&
|
|
68
|
-
typeof input.term === 'object' &&
|
|
69
|
-
input.term !== null &&
|
|
70
|
-
typeof input.term?.value === 'string';
|
|
71
|
-
const resolveTermIri = (input) => {
|
|
72
|
-
if (typeof input === 'string') {
|
|
73
|
-
return input;
|
|
74
|
-
}
|
|
75
|
-
if (hasStringValue(input)) {
|
|
76
|
-
return input.value;
|
|
77
|
-
}
|
|
78
|
-
if (hasTermValue(input)) {
|
|
79
|
-
return input.term.value;
|
|
80
|
-
}
|
|
81
|
-
throw new Error('Term must be a string or VocabTerm with a string value');
|
|
82
|
-
};
|
|
83
|
-
class ColumnBuilder {
|
|
84
|
-
constructor(name, dataType, options = {}, predicate, elementType) {
|
|
85
|
-
this.name = name;
|
|
86
|
-
this.dataType = dataType;
|
|
87
|
-
this.options = { ...options }; // 复制options避免引用问题
|
|
88
|
-
this._predicateUri = predicate;
|
|
89
|
-
this.elementType = elementType ?? null;
|
|
90
|
-
}
|
|
91
|
-
// 统一的值格式化方法 - Column 层负责类型转换
|
|
92
|
-
formatValue(value) {
|
|
93
|
-
if (value === null || value === undefined) {
|
|
94
|
-
throw new Error('Cannot format null or undefined value');
|
|
95
|
-
}
|
|
96
|
-
// 处理数组类型 - 使用多重属性
|
|
97
|
-
if (this.options.isArray) {
|
|
98
|
-
if (!Array.isArray(value)) {
|
|
99
|
-
throw new Error('Array column requires array value');
|
|
100
|
-
}
|
|
101
|
-
// 返回字符串数组,每个元素会作为单独的三元组
|
|
102
|
-
return value.map(item => this.formatSingleValue(item));
|
|
103
|
-
}
|
|
104
|
-
return this.formatSingleValue(value);
|
|
105
|
-
}
|
|
106
|
-
// 格式化单个值
|
|
107
|
-
formatSingleValue(value) {
|
|
108
|
-
const effectiveType = this.options.isArray && this.elementType ? this.elementType : this.dataType;
|
|
109
|
-
// 处理引用类型
|
|
110
|
-
if (this.options.referenceTarget && typeof value === 'string') {
|
|
111
|
-
return `<${value}>`;
|
|
112
|
-
}
|
|
113
|
-
// 根据数据类型格式化
|
|
114
|
-
switch (effectiveType) {
|
|
115
|
-
case 'string':
|
|
116
|
-
return `"${String(value).replace(/"/g, '\\"')}"`;
|
|
117
|
-
case 'integer':
|
|
118
|
-
return String(Number(value));
|
|
119
|
-
case 'boolean':
|
|
120
|
-
return `"${value}"^^<http://www.w3.org/2001/XMLSchema#boolean>`;
|
|
121
|
-
case 'datetime': {
|
|
122
|
-
const date = value instanceof Date ? value : new Date(value);
|
|
123
|
-
return `"${date.toISOString()}"^^<http://www.w3.org/2001/XMLSchema#dateTime>`;
|
|
124
|
-
}
|
|
125
|
-
case 'json':
|
|
126
|
-
case 'object': {
|
|
127
|
-
const jsonString = JSON.stringify(value);
|
|
128
|
-
return `"${jsonString.replace(/"/g, '\\"')}"^^<http://www.w3.org/2001/XMLSchema#json>`;
|
|
129
|
-
}
|
|
130
|
-
case 'uri':
|
|
131
|
-
// URI 类型直接作为 NamedNode,不需要引号
|
|
132
|
-
if (typeof value !== 'string' || (!value.startsWith('http://') && !value.startsWith('https://'))) {
|
|
133
|
-
throw new Error(`URI column requires valid HTTP(S) URL, got: ${value}`);
|
|
134
|
-
}
|
|
135
|
-
return `<${value}>`;
|
|
136
|
-
default:
|
|
137
|
-
return `"${String(value).replace(/"/g, '\\"')}"`;
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
// 统一的值解析方法 - Column 层负责类型解析
|
|
141
|
-
parseValue(rdfValue, datatypeIri) {
|
|
142
|
-
// 处理数组类型在 SPARQL 执行层会返回多个值的数组
|
|
143
|
-
if (this.options.isArray) {
|
|
144
|
-
// 这个方法主要用于解析单个 RDF 值,数组会在查询层处理
|
|
145
|
-
return this.parseSingleValue(rdfValue, datatypeIri);
|
|
146
|
-
}
|
|
147
|
-
return this.parseSingleValue(rdfValue, datatypeIri);
|
|
148
|
-
}
|
|
149
|
-
// 解析单个值
|
|
150
|
-
parseSingleValue(rdfValue, datatypeIri) {
|
|
151
|
-
if (!datatypeIri) {
|
|
152
|
-
return rdfValue;
|
|
153
|
-
}
|
|
154
|
-
// 根据数据类型和 RDF 类型解析
|
|
155
|
-
if (datatypeIri.includes('#integer') || datatypeIri.includes('#int')) {
|
|
156
|
-
return parseInt(rdfValue, 10);
|
|
157
|
-
}
|
|
158
|
-
else if (datatypeIri.includes('#decimal') || datatypeIri.includes('#double')) {
|
|
159
|
-
return parseFloat(rdfValue);
|
|
160
|
-
}
|
|
161
|
-
else if (datatypeIri.includes('#boolean')) {
|
|
162
|
-
return rdfValue === 'true';
|
|
163
|
-
}
|
|
164
|
-
else if (datatypeIri.includes('#dateTime')) {
|
|
165
|
-
return new Date(rdfValue);
|
|
166
|
-
}
|
|
167
|
-
else if (datatypeIri.includes('#json')) {
|
|
168
|
-
try {
|
|
169
|
-
return JSON.parse(rdfValue);
|
|
170
|
-
}
|
|
171
|
-
catch (error) {
|
|
172
|
-
console.warn('Failed to parse JSON value:', rdfValue);
|
|
173
|
-
return rdfValue;
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
// URI 类型检测 - 如果看起来像 URI 就直接返回
|
|
177
|
-
if (rdfValue.startsWith('http://') || rdfValue.startsWith('https://')) {
|
|
178
|
-
return rdfValue;
|
|
179
|
-
}
|
|
180
|
-
return rdfValue;
|
|
181
|
-
}
|
|
182
|
-
primaryKey() {
|
|
183
|
-
const predicate = this.name === 'id'
|
|
184
|
-
? '@id'
|
|
185
|
-
: this.options.predicate;
|
|
186
|
-
this.options = {
|
|
187
|
-
...this.options,
|
|
188
|
-
primaryKey: true,
|
|
189
|
-
required: true,
|
|
190
|
-
predicate
|
|
191
|
-
};
|
|
192
|
-
if (predicate) {
|
|
193
|
-
this._predicateUri = predicate;
|
|
194
|
-
}
|
|
195
|
-
return this;
|
|
196
|
-
}
|
|
197
|
-
notNull() {
|
|
198
|
-
this.options = { ...this.options, required: true, notNull: true };
|
|
199
|
-
return this;
|
|
200
|
-
}
|
|
201
|
-
predicate(uri) {
|
|
202
|
-
const resolved = resolveTermIri(uri);
|
|
203
|
-
this._predicateUri = resolved;
|
|
204
|
-
this.options = { ...this.options, predicate: resolved };
|
|
205
|
-
return this;
|
|
206
|
-
}
|
|
207
|
-
default(value) {
|
|
208
|
-
this.options = { ...this.options, defaultValue: value };
|
|
209
|
-
return this;
|
|
210
|
-
}
|
|
211
|
-
defaultNow() {
|
|
212
|
-
this.options = { ...this.options, defaultValue: () => new Date() };
|
|
213
|
-
return this;
|
|
214
|
-
}
|
|
215
|
-
inverse(value = true) {
|
|
216
|
-
this.options = { ...this.options, inverse: value };
|
|
217
|
-
return this;
|
|
218
|
-
}
|
|
219
|
-
/**
|
|
220
|
-
* 设置引用目标
|
|
221
|
-
*
|
|
222
|
-
* 支持三种输入格式:
|
|
223
|
-
* 1. class URI 字符串 (https://...) - 从 tableRegistry 按 class 查找
|
|
224
|
-
* 2. 表名字符串 (非 URL 格式) - 从 tableNameRegistry 按表名查找
|
|
225
|
-
* 3. PodTable 对象 - 直接使用,优先级最高
|
|
226
|
-
*
|
|
227
|
-
* @example
|
|
228
|
-
* // 使用 class URI(自动推导表)
|
|
229
|
-
* author: uri('author').reference('https://schema.org/Person')
|
|
230
|
-
*
|
|
231
|
-
* // 使用表名(解决同 class 多表歧义)
|
|
232
|
-
* author: uri('author').reference('users_public')
|
|
233
|
-
*
|
|
234
|
-
* // 使用表对象(类型安全,但注意循环依赖)
|
|
235
|
-
* author: uri('author').reference(usersTable)
|
|
236
|
-
*/
|
|
237
|
-
reference(target) {
|
|
238
|
-
if (typeof target === 'string') {
|
|
239
|
-
// 字符串:根据格式判断是 class URI 还是表名
|
|
240
|
-
if (target.startsWith('http://') || target.startsWith('https://')) {
|
|
241
|
-
// class URI
|
|
242
|
-
this.options = { ...this.options, referenceTarget: target };
|
|
243
|
-
}
|
|
244
|
-
else {
|
|
245
|
-
// 表名
|
|
246
|
-
this.options = { ...this.options, referenceTableName: target };
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
else {
|
|
250
|
-
// PodTable 对象
|
|
251
|
-
this.options = { ...this.options, referenceTable: target };
|
|
252
|
-
}
|
|
253
|
-
return this;
|
|
254
|
-
}
|
|
255
|
-
// Array support - similar to Drizzle ORM PostgreSQL
|
|
256
|
-
array() {
|
|
257
|
-
const arrayBuilder = new ColumnBuilder(this.name, 'array', {
|
|
258
|
-
...this.options,
|
|
259
|
-
baseType: this.dataType,
|
|
260
|
-
isArray: true
|
|
261
|
-
}, this._predicateUri, this.dataType);
|
|
262
|
-
return arrayBuilder;
|
|
263
|
-
}
|
|
264
|
-
// method to get predicate URI
|
|
265
|
-
getPredicateUri() {
|
|
266
|
-
return this._predicateUri;
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
exports.ColumnBuilder = ColumnBuilder;
|
|
270
|
-
// 列类型基类
|
|
271
|
-
class PodColumnBase {
|
|
272
|
-
constructor(name, dataType, options = {}, tableName) {
|
|
273
|
-
this.name = name;
|
|
274
|
-
this.dataType = dataType;
|
|
275
|
-
this.options = options;
|
|
276
|
-
this.tableName = tableName;
|
|
277
|
-
}
|
|
278
|
-
// 获取 RDF 谓词
|
|
279
|
-
getPredicate(tableNamespace) {
|
|
280
|
-
if (this.options.predicate) {
|
|
281
|
-
return this.options.predicate;
|
|
282
|
-
}
|
|
283
|
-
if (tableNamespace) {
|
|
284
|
-
return `${tableNamespace.uri}${this.name}`;
|
|
285
|
-
}
|
|
286
|
-
throw new Error(`Missing predicate for column "${this.name}"; please set namespace or predicate explicitly.`);
|
|
287
|
-
}
|
|
288
|
-
// 检查是否是引用类型
|
|
289
|
-
isReference() {
|
|
290
|
-
return !!(this.options.referenceTarget || this.options.referenceTableName || this.options.referenceTable);
|
|
291
|
-
}
|
|
292
|
-
// 获取引用目标 class URI
|
|
293
|
-
getReferenceTarget() {
|
|
294
|
-
return this.options.referenceTarget;
|
|
295
|
-
}
|
|
296
|
-
// 获取引用的目标表名
|
|
297
|
-
getReferenceTableName() {
|
|
298
|
-
return this.options.referenceTableName;
|
|
299
|
-
}
|
|
300
|
-
// 获取引用的目标表对象
|
|
301
|
-
getReferenceTable() {
|
|
302
|
-
return this.options.referenceTable;
|
|
303
|
-
}
|
|
304
|
-
// 链式方法 - 简化版本,直接返回 this
|
|
305
|
-
primaryKey() {
|
|
306
|
-
this.options.primaryKey = true;
|
|
307
|
-
this.options.required = true; // 主键自动为 required
|
|
308
|
-
if (!this.options.predicate && this.name === 'id') {
|
|
309
|
-
this.options.predicate = '@id';
|
|
310
|
-
}
|
|
311
|
-
return this;
|
|
312
|
-
}
|
|
313
|
-
notNull() {
|
|
314
|
-
this.options.required = true;
|
|
315
|
-
return this;
|
|
316
|
-
}
|
|
317
|
-
default(value) {
|
|
318
|
-
this.options.defaultValue = value;
|
|
319
|
-
return this;
|
|
320
|
-
}
|
|
321
|
-
predicate(uri) {
|
|
322
|
-
this.options.predicate = resolveTermIri(uri);
|
|
323
|
-
return this;
|
|
324
|
-
}
|
|
325
|
-
/**
|
|
326
|
-
* 设置引用目标
|
|
327
|
-
*
|
|
328
|
-
* 支持三种输入格式:
|
|
329
|
-
* 1. class URI 字符串 (https://...) - 从 tableRegistry 按 class 查找
|
|
330
|
-
* 2. 表名字符串 (非 URL 格式) - 从 tableNameRegistry 按表名查找
|
|
331
|
-
* 3. PodTable 对象 - 直接使用,优先级最高
|
|
332
|
-
*/
|
|
333
|
-
reference(target) {
|
|
334
|
-
if (typeof target === 'string') {
|
|
335
|
-
if (target.startsWith('http://') || target.startsWith('https://')) {
|
|
336
|
-
this.options.referenceTarget = target;
|
|
337
|
-
}
|
|
338
|
-
else {
|
|
339
|
-
this.options.referenceTableName = target;
|
|
340
|
-
}
|
|
341
|
-
}
|
|
342
|
-
else {
|
|
343
|
-
this.options.referenceTable = target;
|
|
344
|
-
}
|
|
345
|
-
return this;
|
|
346
|
-
}
|
|
347
|
-
inverse(value = true) {
|
|
348
|
-
this.options.inverse = value;
|
|
349
|
-
return this;
|
|
350
|
-
}
|
|
351
|
-
isInverse() {
|
|
352
|
-
return this.options.inverse === true;
|
|
353
|
-
}
|
|
354
|
-
// 统一的值格式化方法 - Column 层负责类型转换
|
|
355
|
-
formatValue(value) {
|
|
356
|
-
if (value === null || value === undefined) {
|
|
357
|
-
throw new Error('Cannot format null or undefined value');
|
|
358
|
-
}
|
|
359
|
-
// 处理数组类型 - 使用多重属性
|
|
360
|
-
if (this.options.isArray) {
|
|
361
|
-
if (!Array.isArray(value)) {
|
|
362
|
-
throw new Error('Array column requires array value');
|
|
363
|
-
}
|
|
364
|
-
// 返回字符串数组,每个元素会作为单独的三元组
|
|
365
|
-
return value.map(item => this.formatSingleValue(item));
|
|
366
|
-
}
|
|
367
|
-
return this.formatSingleValue(value);
|
|
368
|
-
}
|
|
369
|
-
// 格式化单个值
|
|
370
|
-
formatSingleValue(value) {
|
|
371
|
-
// 处理引用类型
|
|
372
|
-
if (this.options.referenceTarget && typeof value === 'string') {
|
|
373
|
-
return `<${value}>`;
|
|
374
|
-
}
|
|
375
|
-
// 根据数据类型格式化
|
|
376
|
-
switch (this.dataType) {
|
|
377
|
-
case 'string':
|
|
378
|
-
return `"${String(value).replace(/"/g, '\\"')}"`;
|
|
379
|
-
case 'integer':
|
|
380
|
-
return `"${Number(value)}"^^<http://www.w3.org/2001/XMLSchema#integer>`;
|
|
381
|
-
case 'boolean':
|
|
382
|
-
return `"${value}"^^<http://www.w3.org/2001/XMLSchema#boolean>`;
|
|
383
|
-
case 'datetime': {
|
|
384
|
-
const date = value instanceof Date ? value : new Date(value);
|
|
385
|
-
return `"${date.toISOString()}"^^<http://www.w3.org/2001/XMLSchema#dateTime>`;
|
|
386
|
-
}
|
|
387
|
-
case 'json':
|
|
388
|
-
case 'object': {
|
|
389
|
-
const jsonString = JSON.stringify(value);
|
|
390
|
-
return `"${jsonString.replace(/"/g, '\\"')}"^^<http://www.w3.org/2001/XMLSchema#json>`;
|
|
391
|
-
}
|
|
392
|
-
case 'uri':
|
|
393
|
-
// URI 类型直接作为 NamedNode,不需要引号
|
|
394
|
-
// 简单的 URI 校验:必须包含 scheme (即包含冒号)
|
|
395
|
-
// 这可以排除像 "xpod_123" 这样的普通字符串,同时支持 http, https, urn, mailto 等
|
|
396
|
-
if (typeof value !== 'string' || !value.includes(':')) {
|
|
397
|
-
throw new Error(`URI column requires valid IRI (must contain scheme), got: ${value}`);
|
|
398
|
-
}
|
|
399
|
-
return `<${value}>`;
|
|
400
|
-
default:
|
|
401
|
-
return `"${String(value).replace(/"/g, '\\"')}"`;
|
|
402
|
-
}
|
|
403
|
-
}
|
|
404
|
-
}
|
|
405
|
-
exports.PodColumnBase = PodColumnBase;
|
|
406
|
-
_a = drizzle_orm_1.entityKind;
|
|
407
|
-
PodColumnBase[_a] = 'PodColumn';
|
|
408
|
-
// 具体的列类型
|
|
409
|
-
class PodStringColumn extends PodColumnBase {
|
|
410
|
-
constructor(name, options = {}) {
|
|
411
|
-
super(name, 'string', options);
|
|
412
|
-
}
|
|
413
|
-
}
|
|
414
|
-
exports.PodStringColumn = PodStringColumn;
|
|
415
|
-
class PodIntegerColumn extends PodColumnBase {
|
|
416
|
-
constructor(name, options = {}) {
|
|
417
|
-
super(name, 'integer', options);
|
|
418
|
-
}
|
|
419
|
-
}
|
|
420
|
-
exports.PodIntegerColumn = PodIntegerColumn;
|
|
421
|
-
class PodBooleanColumn extends PodColumnBase {
|
|
422
|
-
constructor(name, options = {}) {
|
|
423
|
-
super(name, 'boolean', options);
|
|
424
|
-
}
|
|
425
|
-
}
|
|
426
|
-
exports.PodBooleanColumn = PodBooleanColumn;
|
|
427
|
-
class PodDateTimeColumn extends PodColumnBase {
|
|
428
|
-
constructor(name, options = {}) {
|
|
429
|
-
super(name, 'datetime', options);
|
|
430
|
-
}
|
|
431
|
-
}
|
|
432
|
-
exports.PodDateTimeColumn = PodDateTimeColumn;
|
|
433
|
-
class PodJsonColumn extends PodColumnBase {
|
|
434
|
-
constructor(name, options = {}) {
|
|
435
|
-
super(name, 'json', options);
|
|
436
|
-
}
|
|
437
|
-
}
|
|
438
|
-
exports.PodJsonColumn = PodJsonColumn;
|
|
439
|
-
class PodObjectColumn extends PodColumnBase {
|
|
440
|
-
constructor(name, options = {}) {
|
|
441
|
-
super(name, 'object', options);
|
|
442
|
-
}
|
|
443
|
-
}
|
|
444
|
-
exports.PodObjectColumn = PodObjectColumn;
|
|
445
|
-
class PodUriColumn extends PodColumnBase {
|
|
446
|
-
constructor(name, options = {}) {
|
|
447
|
-
super(name, 'uri', options);
|
|
448
|
-
}
|
|
449
|
-
}
|
|
450
|
-
exports.PodUriColumn = PodUriColumn;
|
|
451
|
-
class PodArrayColumn extends PodColumnBase {
|
|
452
|
-
constructor(name, elementType, options = {}) {
|
|
453
|
-
super(name, 'array', options);
|
|
454
|
-
this.elementType = elementType;
|
|
455
|
-
}
|
|
456
|
-
}
|
|
457
|
-
exports.PodArrayColumn = PodArrayColumn;
|
|
458
|
-
// ============ Schema 继承工具函数 ============
|
|
459
|
-
/**
|
|
460
|
-
* 验证子类列不能修改父类的 predicate
|
|
461
|
-
* @internal
|
|
462
|
-
*/
|
|
463
|
-
function validateColumnOverride(childColumn, parentColumn, columnName, childSchemaName, parentSchemaName) {
|
|
464
|
-
const childPredicate = childColumn.getPredicateUri?.() ?? childColumn.options?.predicate;
|
|
465
|
-
const parentPredicate = parentColumn.options?.predicate;
|
|
466
|
-
if (childPredicate && parentPredicate && childPredicate !== parentPredicate) {
|
|
467
|
-
throw new Error(`Schema 继承错误: 不能修改 "${columnName}" 列的 predicate。` +
|
|
468
|
-
`父 schema "${parentSchemaName}" 定义为 "${parentPredicate}",` +
|
|
469
|
-
`子 schema "${childSchemaName}" 尝试改为 "${childPredicate}"。` +
|
|
470
|
-
`子类只能添加约束(notNull, default),不能更改 predicate。`);
|
|
471
|
-
}
|
|
472
|
-
}
|
|
473
|
-
/**
|
|
474
|
-
* 合并父子 schema 的列定义
|
|
475
|
-
* @internal
|
|
476
|
-
*/
|
|
477
|
-
function mergeSchemaColumns(parentSchema, childColumns, childSchemaName) {
|
|
478
|
-
const mergedColumns = {};
|
|
479
|
-
// 先复制父类所有列
|
|
480
|
-
for (const [name, col] of Object.entries(parentSchema.columns)) {
|
|
481
|
-
mergedColumns[name] = col;
|
|
482
|
-
}
|
|
483
|
-
// 处理子类列
|
|
484
|
-
for (const [name, childCol] of Object.entries(childColumns)) {
|
|
485
|
-
const parentCol = parentSchema.columns[name];
|
|
486
|
-
if (parentCol) {
|
|
487
|
-
// 覆盖父类列 - 验证 predicate 不变
|
|
488
|
-
if (!(childCol instanceof PodColumnBase)) {
|
|
489
|
-
validateColumnOverride(childCol, parentCol, name, childSchemaName, parentSchema.name);
|
|
490
|
-
// 继承父类的 predicate(如果子类没有指定)
|
|
491
|
-
const builder = childCol;
|
|
492
|
-
if (!builder.getPredicateUri?.() && !builder.options?.predicate) {
|
|
493
|
-
builder.options = { ...builder.options, predicate: parentCol.options?.predicate };
|
|
494
|
-
}
|
|
495
|
-
}
|
|
496
|
-
}
|
|
497
|
-
mergedColumns[name] = childCol;
|
|
498
|
-
}
|
|
499
|
-
return mergedColumns;
|
|
500
|
-
}
|
|
501
|
-
/**
|
|
502
|
-
* SolidSchema - 独立的 schema 定义类
|
|
503
|
-
*
|
|
504
|
-
* 只包含表的结构信息(列、类型、谓词映射),不包含 base。
|
|
505
|
-
* 可以通过 .at(base) 方法绑定到具体位置,生成 PodTable。
|
|
506
|
-
*
|
|
507
|
-
* @example
|
|
508
|
-
* // 定义 schema(不绑定位置)
|
|
509
|
-
* const profileSchema = solidSchema('profile', {
|
|
510
|
-
* name: string('name').predicate(FOAF.name),
|
|
511
|
-
* avatar: uri('avatar').predicate(FOAF.img),
|
|
512
|
-
* }, {
|
|
513
|
-
* type: FOAF.Person,
|
|
514
|
-
* });
|
|
515
|
-
*
|
|
516
|
-
* // 绑定到具体位置
|
|
517
|
-
* const myProfile = profileSchema.at('/profile/card.ttl');
|
|
518
|
-
* const aliceProfile = profileSchema.at('https://alice.pod/profile/card.ttl');
|
|
519
|
-
*/
|
|
520
|
-
class SolidSchema {
|
|
521
|
-
constructor(name, columns, options) {
|
|
522
|
-
this.name = name;
|
|
523
|
-
this.columns = columns;
|
|
524
|
-
this.options = options;
|
|
525
|
-
this.$kind = 'SolidSchema';
|
|
526
|
-
this.namespace = options.namespace;
|
|
527
|
-
this.subjectTemplate = options.subjectTemplate;
|
|
528
|
-
this.subClassOf = options.subClassOf
|
|
529
|
-
? (Array.isArray(options.subClassOf)
|
|
530
|
-
? options.subClassOf.map(resolveTermIri)
|
|
531
|
-
: [resolveTermIri(options.subClassOf)])
|
|
532
|
-
: undefined;
|
|
533
|
-
}
|
|
534
|
-
/**
|
|
535
|
-
* 绑定到具体位置,生成 PodTable
|
|
536
|
-
*
|
|
537
|
-
* @param base 资源路径(相对路径或绝对 IRI)
|
|
538
|
-
* @example
|
|
539
|
-
* const myProfile = profileSchema.at('/profile/card.ttl');
|
|
540
|
-
* const aliceProfile = profileSchema.at('https://alice.pod/profile/card.ttl');
|
|
541
|
-
*/
|
|
542
|
-
at(base) {
|
|
543
|
-
return new PodTable(this.name, this.columns, {
|
|
544
|
-
...this.options,
|
|
545
|
-
base,
|
|
546
|
-
});
|
|
547
|
-
}
|
|
548
|
-
/**
|
|
549
|
-
* 创建继承当前 schema 的子 schema
|
|
550
|
-
*
|
|
551
|
-
* 子类会继承父类的所有列,并可以:
|
|
552
|
-
* - 添加新的属性
|
|
553
|
-
* - 给继承的属性添加约束(如 notNull、default)
|
|
554
|
-
* - 但不能修改继承属性的 predicate
|
|
555
|
-
*
|
|
556
|
-
* @param name - 子 schema 名称
|
|
557
|
-
* @param columns - 子类新增或覆盖的列
|
|
558
|
-
* @param options - 子 schema 选项(必须提供 type)
|
|
559
|
-
* @returns 包含所有继承列和新列的子 schema
|
|
560
|
-
*
|
|
561
|
-
* @example
|
|
562
|
-
* const secretSchema = solidSchema('secret', {
|
|
563
|
-
* id: id(),
|
|
564
|
-
* name: string('name').predicate(VOCAB.name),
|
|
565
|
-
* createdAt: datetime('createdAt').predicate(VOCAB.createdAt),
|
|
566
|
-
* }, {
|
|
567
|
-
* type: 'https://vocab.example/Secret',
|
|
568
|
-
* });
|
|
569
|
-
*
|
|
570
|
-
* // 创建子 schema
|
|
571
|
-
* const apiKeySchema = secretSchema.extend('apiKey', {
|
|
572
|
-
* // 新增属性
|
|
573
|
-
* apiKey: string('apiKey').notNull().predicate(VOCAB.apiKey),
|
|
574
|
-
* // 增强父类属性(添加约束,但不能改 predicate)
|
|
575
|
-
* name: string('name').notNull(),
|
|
576
|
-
* }, {
|
|
577
|
-
* type: 'https://vocab.example/APIKey',
|
|
578
|
-
* });
|
|
579
|
-
*
|
|
580
|
-
* // apiKeySchema 包含: id, name(notNull), createdAt, apiKey
|
|
581
|
-
* // apiKeySchema.subClassOf 自动包含 'https://vocab.example/Secret'
|
|
582
|
-
*/
|
|
583
|
-
extend(name, columns, options) {
|
|
584
|
-
// 合并列
|
|
585
|
-
const mergedColumnDefs = mergeSchemaColumns(this, columns, name);
|
|
586
|
-
// 处理 subClassOf - 自动包含父类 type
|
|
587
|
-
const subClassOf = [this.type];
|
|
588
|
-
if (this.subClassOf) {
|
|
589
|
-
subClassOf.push(...this.subClassOf);
|
|
590
|
-
}
|
|
591
|
-
// 创建子 schema(使用 solidSchema 函数处理列转换)
|
|
592
|
-
return solidSchema(name, mergedColumnDefs, {
|
|
593
|
-
...options,
|
|
594
|
-
subClassOf,
|
|
595
|
-
});
|
|
596
|
-
}
|
|
597
|
-
/**
|
|
598
|
-
* 获取 RDF 类型
|
|
599
|
-
*/
|
|
600
|
-
get type() {
|
|
601
|
-
return resolveTermIri(this.options.type);
|
|
602
|
-
}
|
|
603
|
-
}
|
|
604
|
-
exports.SolidSchema = SolidSchema;
|
|
605
|
-
/**
|
|
606
|
-
* 创建 SolidSchema(不绑定位置的 schema 定义)
|
|
607
|
-
*
|
|
608
|
-
* @example
|
|
609
|
-
* const profileSchema = solidSchema('profile', {
|
|
610
|
-
* name: string('name').predicate(FOAF.name),
|
|
611
|
-
* }, {
|
|
612
|
-
* type: FOAF.Person,
|
|
613
|
-
* });
|
|
614
|
-
*
|
|
615
|
-
* // 使用时绑定位置
|
|
616
|
-
* const myProfile = profileSchema.at('/profile/card.ttl');
|
|
617
|
-
*/
|
|
618
|
-
function solidSchema(name, columns, options) {
|
|
619
|
-
// 复用 podTable 的列处理逻辑
|
|
620
|
-
const processedColumns = {};
|
|
621
|
-
for (const [key, value] of Object.entries(columns)) {
|
|
622
|
-
if (value instanceof PodColumnBase) {
|
|
623
|
-
processedColumns[key] = value;
|
|
624
|
-
continue;
|
|
625
|
-
}
|
|
626
|
-
let column;
|
|
627
|
-
switch (value.dataType) {
|
|
628
|
-
case 'integer':
|
|
629
|
-
column = new PodIntegerColumn(value.name, value.options);
|
|
630
|
-
break;
|
|
631
|
-
case 'datetime':
|
|
632
|
-
column = new PodDateTimeColumn(value.name, value.options);
|
|
633
|
-
break;
|
|
634
|
-
case 'boolean':
|
|
635
|
-
column = new PodBooleanColumn(value.name, value.options);
|
|
636
|
-
break;
|
|
637
|
-
case 'json':
|
|
638
|
-
column = new PodJsonColumn(value.name, value.options);
|
|
639
|
-
break;
|
|
640
|
-
case 'object':
|
|
641
|
-
column = new PodObjectColumn(value.name, value.options);
|
|
642
|
-
break;
|
|
643
|
-
case 'array': {
|
|
644
|
-
const elementType = (value.elementType ?? value.options.baseType ?? 'string');
|
|
645
|
-
column = new PodArrayColumn(value.name, elementType, value.options);
|
|
646
|
-
break;
|
|
647
|
-
}
|
|
648
|
-
case 'uri':
|
|
649
|
-
column = new PodUriColumn(value.name, value.options);
|
|
650
|
-
break;
|
|
651
|
-
case 'string':
|
|
652
|
-
default:
|
|
653
|
-
column = new PodStringColumn(value.name, value.options);
|
|
654
|
-
break;
|
|
655
|
-
}
|
|
656
|
-
const predicateUri = value.getPredicateUri();
|
|
657
|
-
if (predicateUri) {
|
|
658
|
-
column.predicate(predicateUri);
|
|
659
|
-
}
|
|
660
|
-
processedColumns[key] = column;
|
|
661
|
-
}
|
|
662
|
-
return new SolidSchema(name, processedColumns, options);
|
|
663
|
-
}
|
|
664
|
-
/**
|
|
665
|
-
* 检查目标是否为 SolidSchema
|
|
666
|
-
*/
|
|
667
|
-
function isSolidSchema(target) {
|
|
668
|
-
return target instanceof SolidSchema || target?.$kind === 'SolidSchema';
|
|
669
|
-
}
|
|
670
|
-
// 表定义类 - 支持泛型以进行类型推断
|
|
671
|
-
class PodTable {
|
|
672
|
-
constructor(name, columns, options) {
|
|
673
|
-
this.initialized = false;
|
|
674
|
-
const typeInput = options.type;
|
|
675
|
-
if (!typeInput) {
|
|
676
|
-
throw new Error('podTable requires a type (RDF class) via options.type');
|
|
677
|
-
}
|
|
678
|
-
const typeIndexOption = options.typeIndex;
|
|
679
|
-
const validTypeIndex = typeIndexOption === 'private' || typeIndexOption === 'public';
|
|
680
|
-
if (typeIndexOption && !validTypeIndex) {
|
|
681
|
-
console.warn(`Invalid typeIndex value "${typeIndexOption}", disabling TypeIndex registration.`);
|
|
682
|
-
}
|
|
683
|
-
const baseConfig = this.resolveBase(options.base, name);
|
|
684
|
-
this.resourcePath = baseConfig.resourcePath;
|
|
685
|
-
this.containerPath = baseConfig.containerPath;
|
|
686
|
-
const subjectTemplateInfo = this.resolveSubjectTemplate(options.subjectTemplate, baseConfig.resourcePath, baseConfig.containerPath, name);
|
|
687
|
-
this.subjectTemplate = subjectTemplateInfo.template;
|
|
688
|
-
this.hasCustomSubjectTemplate = subjectTemplateInfo.isCustom;
|
|
689
|
-
this.resourceMode = options.resourceMode ?? (options.sparqlEndpoint ? 'sparql' : undefined);
|
|
690
|
-
this.sparqlEndpoint = options.sparqlEndpoint;
|
|
691
|
-
// TypeIndex 注册默认取决于是否提供 typeIndex,且 autoRegister 未显式禁用
|
|
692
|
-
this.registerTypeIndexEnabled = validTypeIndex && options.autoRegister !== false;
|
|
693
|
-
this.config = {
|
|
694
|
-
name,
|
|
695
|
-
base: baseConfig.resourcePath,
|
|
696
|
-
type: resolveTermIri(typeInput),
|
|
697
|
-
namespace: options.namespace,
|
|
698
|
-
typeIndex: validTypeIndex ? typeIndexOption : undefined,
|
|
699
|
-
saiRegistryPath: options.saiRegistryPath,
|
|
700
|
-
subjectTemplate: this.subjectTemplate,
|
|
701
|
-
autoRegister: options.autoRegister,
|
|
702
|
-
containerPath: baseConfig.containerPath,
|
|
703
|
-
hooks: options.hooks,
|
|
704
|
-
};
|
|
705
|
-
this.parentClasses = this.normalizeParents(options.subClassOf ?? []);
|
|
706
|
-
if (this.parentClasses.length > 0) {
|
|
707
|
-
this.config.subClassOf = [...this.parentClasses];
|
|
708
|
-
}
|
|
709
|
-
this.columns = columns;
|
|
710
|
-
// 将列直接添加到表对象上,以便直接访问
|
|
711
|
-
Object.assign(this, columns);
|
|
712
|
-
// 记录列所属的表,便于 JOIN/分组等语义解析,并检查主键数量
|
|
713
|
-
let primaryKeyCount = 0;
|
|
714
|
-
for (const column of Object.values(columns)) {
|
|
715
|
-
if (column.options.primaryKey) {
|
|
716
|
-
primaryKeyCount++;
|
|
717
|
-
}
|
|
718
|
-
column.table = this;
|
|
719
|
-
column.tableName = name;
|
|
720
|
-
// 检查所有列是否都有有效的 predicate 或表级 namespace
|
|
721
|
-
if (!column.options.predicate && // 没有明确的 predicate
|
|
722
|
-
!(column._virtualId) && // 不是虚拟 ID 列 (@id)
|
|
723
|
-
!options.namespace // 表没有定义 namespace
|
|
724
|
-
) {
|
|
725
|
-
throw new Error(`Column "${column.name}" in table "${name}" is missing a predicate. Please set a 'predicate' option for the column or a 'namespace' for the table.`);
|
|
726
|
-
}
|
|
727
|
-
}
|
|
728
|
-
if (primaryKeyCount !== 1) {
|
|
729
|
-
throw new Error(`PodTable "${name}" must have exactly one primary key column. Found ${primaryKeyCount}.`);
|
|
730
|
-
}
|
|
731
|
-
// 初始化 drizzle-zod 兼容的属性
|
|
732
|
-
this.$inferSelect = {};
|
|
733
|
-
this.$inferInsert = {};
|
|
734
|
-
this.$inferUpdate = {};
|
|
735
|
-
// 初始化 _ 属性
|
|
736
|
-
this._ = {
|
|
737
|
-
brand: 'Table',
|
|
738
|
-
config: this.config,
|
|
739
|
-
name,
|
|
740
|
-
schema: undefined,
|
|
741
|
-
columns,
|
|
742
|
-
inferSelect: {},
|
|
743
|
-
inferInsert: {},
|
|
744
|
-
inferUpdate: {}
|
|
745
|
-
};
|
|
746
|
-
this.mapping = this.buildTableMapping();
|
|
747
|
-
}
|
|
748
|
-
// 获取容器路径
|
|
749
|
-
getContainerPath() {
|
|
750
|
-
return this.containerPath;
|
|
751
|
-
}
|
|
752
|
-
// 获取 RDF 类
|
|
753
|
-
getType() {
|
|
754
|
-
return this.config.type;
|
|
755
|
-
}
|
|
756
|
-
/**
|
|
757
|
-
* @deprecated 使用 getType()
|
|
758
|
-
*/
|
|
759
|
-
getRdfClass() {
|
|
760
|
-
return this.getType();
|
|
761
|
-
}
|
|
762
|
-
// 获取命名空间
|
|
763
|
-
getNamespace() {
|
|
764
|
-
return this.config.namespace;
|
|
765
|
-
}
|
|
766
|
-
getSubjectTemplate() {
|
|
767
|
-
return this.subjectTemplate;
|
|
768
|
-
}
|
|
769
|
-
/**
|
|
770
|
-
* 检查是否有用户提供的 subjectTemplate
|
|
771
|
-
*/
|
|
772
|
-
hasCustomTemplate() {
|
|
773
|
-
return this.hasCustomSubjectTemplate;
|
|
774
|
-
}
|
|
775
|
-
getSubClassOf() {
|
|
776
|
-
return [...this.parentClasses];
|
|
777
|
-
}
|
|
778
|
-
getMapping() {
|
|
779
|
-
return this.mapping;
|
|
780
|
-
}
|
|
781
|
-
/**
|
|
782
|
-
* 获取表的 schema 定义(用于联邦查询)
|
|
783
|
-
*
|
|
784
|
-
* 返回只包含结构信息的 SolidSchema,不包含 base
|
|
785
|
-
* 用于 relations() 中的联邦查询,数据位置通过 discover 动态发现
|
|
786
|
-
*
|
|
787
|
-
* @example
|
|
788
|
-
* const friendsRelations = relations(friends, ({ many }) => ({
|
|
789
|
-
* posts: many(posts.$schema, {
|
|
790
|
-
* discover: (friend) => friend.webId,
|
|
791
|
-
* }),
|
|
792
|
-
* }));
|
|
793
|
-
*/
|
|
794
|
-
get $schema() {
|
|
795
|
-
return new SolidSchema(this.config.name, this.columns, {
|
|
796
|
-
type: this.config.type,
|
|
797
|
-
namespace: this.config.namespace,
|
|
798
|
-
subjectTemplate: this.subjectTemplate,
|
|
799
|
-
subClassOf: this.parentClasses.length > 0 ? [...this.parentClasses] : undefined,
|
|
800
|
-
});
|
|
801
|
-
}
|
|
802
|
-
/**
|
|
803
|
-
* Generate a relative URI for a record by ID
|
|
804
|
-
*
|
|
805
|
-
* This returns a Pod-relative URI that drizzle-solid will automatically
|
|
806
|
-
* resolve to an absolute URI using the Pod URL at runtime.
|
|
807
|
-
*
|
|
808
|
-
* @param id - The record ID (typically a nanoid or user-defined identifier)
|
|
809
|
-
* @returns Relative URI like '/.data/agents/xK9mN2.ttl' or '/.data/tags.ttl#abc123'
|
|
810
|
-
*
|
|
811
|
-
* @example
|
|
812
|
-
* // Generate URI for a record by its ID
|
|
813
|
-
* const agentUri = agentTable.resolveUri('xK9mN2pL');
|
|
814
|
-
* // => '/.data/agents/xK9mN2pL.ttl'
|
|
815
|
-
*
|
|
816
|
-
* // Prefer using @id from query results when available
|
|
817
|
-
* const msg = { maker: existingAgent['@id'], content: 'Hello!' }
|
|
818
|
-
*/
|
|
819
|
-
resolveUri(id) {
|
|
820
|
-
// Apply subjectTemplate
|
|
821
|
-
const template = this.subjectTemplate;
|
|
822
|
-
const resolved = template.replace(/\{id\}/g, id);
|
|
823
|
-
// Build relative URI based on mode
|
|
824
|
-
if (resolved.startsWith('#')) {
|
|
825
|
-
// Fragment mode: /.data/tags.ttl#id
|
|
826
|
-
const resourcePath = this.resourcePath;
|
|
827
|
-
return `${resourcePath}${resolved}`;
|
|
828
|
-
}
|
|
829
|
-
// Document mode: /.data/agents/openrouter.ttl
|
|
830
|
-
const normalizedContainer = this.containerPath.endsWith('/')
|
|
831
|
-
? this.containerPath
|
|
832
|
-
: `${this.containerPath}/`;
|
|
833
|
-
return `${normalizedContainer}${resolved}`;
|
|
834
|
-
}
|
|
835
|
-
resolveBase(base, tableName) {
|
|
836
|
-
if (!base || base.trim().length === 0) {
|
|
837
|
-
throw new Error(`podTable '${tableName}' requires a 'base' option.\n` +
|
|
838
|
-
`Examples:\n` +
|
|
839
|
-
` base: '/data/${tableName}.ttl' // relative path for your Pod\n` +
|
|
840
|
-
` base: '/data/${tableName}/' // container path\n` +
|
|
841
|
-
` base: 'https://other.pod/data/${tableName}.ttl' // absolute IRI for other Pods`);
|
|
842
|
-
}
|
|
843
|
-
const normalizedInput = this.normalizeBaseInput(base);
|
|
844
|
-
const normalizedPath = this.normalizeResourcePath(normalizedInput);
|
|
845
|
-
if (normalizedPath.endsWith('/')) {
|
|
846
|
-
// Container/directory path - for Document mode
|
|
847
|
-
const containerPath = this.ensureTrailingSlash(normalizedPath);
|
|
848
|
-
return {
|
|
849
|
-
resourcePath: containerPath,
|
|
850
|
-
containerPath
|
|
851
|
-
};
|
|
852
|
-
}
|
|
853
|
-
// File path - for Fragment mode
|
|
854
|
-
const containerPath = this.ensureTrailingSlash(this.deriveContainerPath(normalizedPath));
|
|
855
|
-
return {
|
|
856
|
-
resourcePath: normalizedPath,
|
|
857
|
-
containerPath,
|
|
858
|
-
};
|
|
859
|
-
}
|
|
860
|
-
normalizeBaseInput(rawBase) {
|
|
861
|
-
const trimmed = rawBase.trim();
|
|
862
|
-
if (trimmed.length === 0) {
|
|
863
|
-
throw new Error('podTable requires a non-empty base');
|
|
864
|
-
}
|
|
865
|
-
const schemeMatch = trimmed.match(/^([a-zA-Z][\w+.-]*):\/\/(.*)$/);
|
|
866
|
-
if (schemeMatch) {
|
|
867
|
-
const [, scheme, remainder] = schemeMatch;
|
|
868
|
-
const normalizedScheme = scheme.toLowerCase();
|
|
869
|
-
const remainderTrimmed = remainder.trim();
|
|
870
|
-
if (normalizedScheme === 'http' || normalizedScheme === 'https') {
|
|
871
|
-
const rest = remainderTrimmed.length === 0 ? '' : remainderTrimmed;
|
|
872
|
-
return `${normalizedScheme}://${rest}`;
|
|
873
|
-
}
|
|
874
|
-
const normalizedRemainder = remainderTrimmed.length === 0 ? '/' : remainderTrimmed;
|
|
875
|
-
return normalizedRemainder.startsWith('/') ? normalizedRemainder : `/${normalizedRemainder}`;
|
|
876
|
-
}
|
|
877
|
-
return trimmed;
|
|
878
|
-
}
|
|
879
|
-
normalizeResourcePath(resourcePath) {
|
|
880
|
-
if (typeof resourcePath !== 'string' || resourcePath.trim().length === 0) {
|
|
881
|
-
throw new Error('podTable requires a non-empty base');
|
|
882
|
-
}
|
|
883
|
-
if (/^[a-zA-Z][\w+.-]*:\/\//.test(resourcePath)) {
|
|
884
|
-
return resourcePath;
|
|
885
|
-
}
|
|
886
|
-
const trimmed = resourcePath.trim().replace(/^(\.\/)+/, '');
|
|
887
|
-
const normalized = trimmed.replace(/\/+/g, '/');
|
|
888
|
-
if (normalized.startsWith('/')) {
|
|
889
|
-
return normalized;
|
|
890
|
-
}
|
|
891
|
-
return `/${normalized}`;
|
|
892
|
-
}
|
|
893
|
-
deriveContainerPath(resourcePath) {
|
|
894
|
-
const withoutTrailingSlash = resourcePath.endsWith('/')
|
|
895
|
-
? resourcePath.slice(0, -1)
|
|
896
|
-
: resourcePath;
|
|
897
|
-
const lastSlash = withoutTrailingSlash.lastIndexOf('/');
|
|
898
|
-
if (lastSlash === -1) {
|
|
899
|
-
return '/';
|
|
900
|
-
}
|
|
901
|
-
return withoutTrailingSlash.slice(0, lastSlash + 1);
|
|
902
|
-
}
|
|
903
|
-
ensureTrailingSlash(path) {
|
|
904
|
-
return path.endsWith('/') ? path : `${path}/`;
|
|
905
|
-
}
|
|
906
|
-
getResourcePath() {
|
|
907
|
-
return this.resourcePath;
|
|
908
|
-
}
|
|
909
|
-
getResourceMode() {
|
|
910
|
-
return this.resourceMode;
|
|
911
|
-
}
|
|
912
|
-
getSparqlEndpoint() {
|
|
913
|
-
return this.sparqlEndpoint;
|
|
914
|
-
}
|
|
915
|
-
shouldRegisterTypeIndex() {
|
|
916
|
-
return this.registerTypeIndexEnabled;
|
|
917
|
-
}
|
|
918
|
-
async init(initializer) {
|
|
919
|
-
await initializer.registerTable(this);
|
|
920
|
-
}
|
|
921
|
-
isInitialized() {
|
|
922
|
-
return this.initialized;
|
|
923
|
-
}
|
|
924
|
-
markInitialized(initialized = true) {
|
|
925
|
-
this.initialized = initialized;
|
|
926
|
-
}
|
|
927
|
-
/**
|
|
928
|
-
* 动态更新 base(TypeIndex 自动发现等场景)
|
|
929
|
-
*/
|
|
930
|
-
setBase(base) {
|
|
931
|
-
const resolved = this.resolveBase(base, this.config.name);
|
|
932
|
-
this.resourcePath = resolved.resourcePath;
|
|
933
|
-
this.containerPath = resolved.containerPath;
|
|
934
|
-
this.config.base = resolved.resourcePath;
|
|
935
|
-
this.config.containerPath = resolved.containerPath; // Sync config.containerPath
|
|
936
|
-
if (this._?.config) {
|
|
937
|
-
this._.config.base = this.config.base;
|
|
938
|
-
this._.config.containerPath = this.config.containerPath;
|
|
939
|
-
}
|
|
940
|
-
if (!this.hasCustomSubjectTemplate) {
|
|
941
|
-
this.subjectTemplate = this.buildDefaultSubjectTemplate(this.config.base, this.config.containerPath, this.config.name);
|
|
942
|
-
this.config.subjectTemplate = this.subjectTemplate;
|
|
943
|
-
if (this._?.config) {
|
|
944
|
-
this._.config.subjectTemplate = this.subjectTemplate;
|
|
945
|
-
}
|
|
946
|
-
}
|
|
947
|
-
this.mapping = this.buildTableMapping();
|
|
948
|
-
}
|
|
949
|
-
/**
|
|
950
|
-
* 动态更新 subjectTemplate(SAI DataRegistration 自动发现等场景)
|
|
951
|
-
*/
|
|
952
|
-
setSubjectTemplate(template) {
|
|
953
|
-
this.subjectTemplate = template;
|
|
954
|
-
this.hasCustomSubjectTemplate = true;
|
|
955
|
-
this.config.subjectTemplate = template;
|
|
956
|
-
if (this._?.config) {
|
|
957
|
-
this._.config.subjectTemplate = template;
|
|
958
|
-
}
|
|
959
|
-
this.mapping = this.buildTableMapping();
|
|
960
|
-
}
|
|
961
|
-
/**
|
|
962
|
-
* 动态设置 SPARQL endpoint(自动发现等场景)
|
|
963
|
-
*/
|
|
964
|
-
setSparqlEndpoint(endpoint) {
|
|
965
|
-
this.sparqlEndpoint = endpoint;
|
|
966
|
-
if (!this.resourceMode) {
|
|
967
|
-
this.resourceMode = 'sparql';
|
|
968
|
-
}
|
|
969
|
-
}
|
|
970
|
-
// 获取所有列
|
|
971
|
-
getColumns() {
|
|
972
|
-
return this.columns;
|
|
973
|
-
}
|
|
974
|
-
getColumn(name) {
|
|
975
|
-
return this.columns[name];
|
|
976
|
-
}
|
|
977
|
-
// 检查列是否存在
|
|
978
|
-
hasColumn(name) {
|
|
979
|
-
return name in this.columns;
|
|
980
|
-
}
|
|
981
|
-
resolveSubjectTemplate(template, resourcePath, containerPath, tableName) {
|
|
982
|
-
if (template && template.trim().length > 0) {
|
|
983
|
-
return { template: template.trim(), isCustom: true };
|
|
984
|
-
}
|
|
985
|
-
return {
|
|
986
|
-
template: this.buildDefaultSubjectTemplate(resourcePath, containerPath, tableName),
|
|
987
|
-
isCustom: false
|
|
988
|
-
};
|
|
989
|
-
}
|
|
990
|
-
buildDefaultSubjectTemplate(resourcePath, containerPath, tableName = 'resource') {
|
|
991
|
-
const normalizedContainer = this.ensureTrailingSlash(containerPath || '');
|
|
992
|
-
// If the table base is a container (document mode), containerPath should end with `${tableName}/`.
|
|
993
|
-
// Otherwise, assume fragment mode.
|
|
994
|
-
const isDocumentMode = normalizedContainer.endsWith(`${tableName}/`);
|
|
995
|
-
if (isDocumentMode) {
|
|
996
|
-
return '{id}.ttl';
|
|
997
|
-
}
|
|
998
|
-
// Fragment mode: all rows in one resource, distinguished by fragment.
|
|
999
|
-
// resourcePath is expected to be the concrete document path (e.g. `/data/tags.ttl`).
|
|
1000
|
-
if (resourcePath && resourcePath.includes('{')) {
|
|
1001
|
-
return resourcePath;
|
|
1002
|
-
}
|
|
1003
|
-
return '#{id}';
|
|
1004
|
-
}
|
|
1005
|
-
buildTableMapping() {
|
|
1006
|
-
const mappedColumns = {};
|
|
1007
|
-
for (const column of Object.values(this.columns)) {
|
|
1008
|
-
mappedColumns[column.name] = this.buildColumnMapping(column);
|
|
1009
|
-
}
|
|
1010
|
-
return {
|
|
1011
|
-
name: this.config.name,
|
|
1012
|
-
type: this.config.type,
|
|
1013
|
-
subjectTemplate: this.subjectTemplate,
|
|
1014
|
-
namespace: this.config.namespace,
|
|
1015
|
-
subClassOf: this.parentClasses.length > 0 ? [...this.parentClasses] : undefined,
|
|
1016
|
-
columns: mappedColumns,
|
|
1017
|
-
relations: this.relations
|
|
1018
|
-
};
|
|
1019
|
-
}
|
|
1020
|
-
buildColumnMapping(column) {
|
|
1021
|
-
const predicate = column._virtualId
|
|
1022
|
-
? '@id'
|
|
1023
|
-
: column.getPredicate(this.config.namespace);
|
|
1024
|
-
return {
|
|
1025
|
-
column: column.name,
|
|
1026
|
-
predicate,
|
|
1027
|
-
kind: column.isReference() ? 'object' : 'datatype',
|
|
1028
|
-
datatype: this.inferColumnDatatype(column),
|
|
1029
|
-
referenceTarget: column.getReferenceTarget(),
|
|
1030
|
-
isArray: column.options.isArray ?? false,
|
|
1031
|
-
inverse: column.isInverse()
|
|
1032
|
-
};
|
|
1033
|
-
}
|
|
1034
|
-
inferColumnDatatype(column) {
|
|
1035
|
-
switch (column.dataType) {
|
|
1036
|
-
case 'string':
|
|
1037
|
-
return 'http://www.w3.org/2001/XMLSchema#string';
|
|
1038
|
-
case 'integer':
|
|
1039
|
-
return 'http://www.w3.org/2001/XMLSchema#integer';
|
|
1040
|
-
case 'boolean':
|
|
1041
|
-
return 'http://www.w3.org/2001/XMLSchema#boolean';
|
|
1042
|
-
case 'datetime':
|
|
1043
|
-
return 'http://www.w3.org/2001/XMLSchema#dateTime';
|
|
1044
|
-
case 'json':
|
|
1045
|
-
case 'object':
|
|
1046
|
-
return 'http://www.w3.org/2001/XMLSchema#json';
|
|
1047
|
-
case 'uri':
|
|
1048
|
-
return undefined;
|
|
1049
|
-
default:
|
|
1050
|
-
return undefined;
|
|
1051
|
-
}
|
|
1052
|
-
}
|
|
1053
|
-
normalizeParents(value) {
|
|
1054
|
-
if (!value) {
|
|
1055
|
-
return [];
|
|
1056
|
-
}
|
|
1057
|
-
const entries = Array.isArray(value) ? value : [value];
|
|
1058
|
-
const normalized = entries
|
|
1059
|
-
.map((entry) => resolveTermIri(entry))
|
|
1060
|
-
.filter((entry) => entry && entry.length > 0);
|
|
1061
|
-
return Array.from(new Set(normalized));
|
|
1062
|
-
}
|
|
1063
|
-
}
|
|
1064
|
-
exports.PodTable = PodTable;
|
|
1065
|
-
_b = drizzle_orm_1.entityKind;
|
|
1066
|
-
PodTable[_b] = 'PodTable';
|
|
1067
|
-
function boolean(name, options = {}) {
|
|
1068
|
-
return new ColumnBuilder(name, 'boolean', options);
|
|
1069
|
-
}
|
|
1070
|
-
function timestamp(name, options = {}) {
|
|
1071
|
-
return new ColumnBuilder(name, 'datetime', options);
|
|
1072
|
-
}
|
|
1073
|
-
function json(name, options = {}) {
|
|
1074
|
-
return new ColumnBuilder(name, 'json', options);
|
|
1075
|
-
}
|
|
1076
|
-
function object(name, options = {}) {
|
|
1077
|
-
return new ColumnBuilder(name, 'object', options);
|
|
1078
|
-
}
|
|
1079
|
-
function uri(name, options = {}) {
|
|
1080
|
-
return new ColumnBuilder(name, 'uri', options);
|
|
1081
|
-
}
|
|
1082
|
-
// IRI 别名,方便习惯使用 IRI 术语的场景
|
|
1083
|
-
function iri(name, options = {}) {
|
|
1084
|
-
return uri(name, options);
|
|
1085
|
-
}
|
|
1086
|
-
// Pod 专用的列定义函数(保留向后兼容)
|
|
1087
|
-
function podString(name, options = {}) {
|
|
1088
|
-
return new PodStringColumn(name, options);
|
|
1089
|
-
}
|
|
1090
|
-
function podInteger(name, options = {}) {
|
|
1091
|
-
return new PodIntegerColumn(name, options);
|
|
1092
|
-
}
|
|
1093
|
-
function podBoolean(name, options = {}) {
|
|
1094
|
-
return new PodBooleanColumn(name, options);
|
|
1095
|
-
}
|
|
1096
|
-
function podDateTime(name, options = {}) {
|
|
1097
|
-
return new PodDateTimeColumn(name, options);
|
|
1098
|
-
}
|
|
1099
|
-
function podJson(name, options = {}) {
|
|
1100
|
-
return new PodJsonColumn(name, options);
|
|
1101
|
-
}
|
|
1102
|
-
function podObject(name, options = {}) {
|
|
1103
|
-
return new PodObjectColumn(name, options);
|
|
1104
|
-
}
|
|
1105
|
-
// 专用 ID 列,自动 predicate 为 @id,便于构造 subject IRI
|
|
1106
|
-
// 特殊 ID 列:不单独存储谓词,只用于生成/解析 subject/@id(最多一个)
|
|
1107
|
-
function id(name = 'id', options = {}) {
|
|
1108
|
-
const col = new PodStringColumn(name, {
|
|
1109
|
-
...options,
|
|
1110
|
-
predicate: '@id',
|
|
1111
|
-
primaryKey: true,
|
|
1112
|
-
required: true,
|
|
1113
|
-
defaultValue: options.defaultValue ?? generateNanoId // Default to NanoID generation
|
|
1114
|
-
});
|
|
1115
|
-
// 标记为"虚拟 ID 列",生成/解析 subject 时使用,但不额外输出三元组
|
|
1116
|
-
col._virtualId = true;
|
|
1117
|
-
return col;
|
|
1118
|
-
}
|
|
1119
|
-
// 创建类型安全的builder函数
|
|
1120
|
-
function string(name, options = {}) {
|
|
1121
|
-
return new ColumnBuilder(name, 'string', options);
|
|
1122
|
-
}
|
|
1123
|
-
function int(name, options = {}) {
|
|
1124
|
-
return new ColumnBuilder(name, 'integer', options);
|
|
1125
|
-
}
|
|
1126
|
-
function integer(name, options = {}) {
|
|
1127
|
-
return new ColumnBuilder(name, 'integer', options);
|
|
1128
|
-
}
|
|
1129
|
-
function date(name, options = {}) {
|
|
1130
|
-
return new ColumnBuilder(name, 'datetime', options);
|
|
1131
|
-
}
|
|
1132
|
-
// 时间相关列类型别名
|
|
1133
|
-
function datetime(name, options = {}) {
|
|
1134
|
-
return new ColumnBuilder(name, 'datetime', options);
|
|
1135
|
-
}
|
|
1136
|
-
// 文本相关列类型别名
|
|
1137
|
-
function text(name, options = {}) {
|
|
1138
|
-
return new ColumnBuilder(name, 'string', options);
|
|
1139
|
-
}
|
|
1140
|
-
function varchar(name, options = {}) {
|
|
1141
|
-
return new ColumnBuilder(name, 'string', options);
|
|
1142
|
-
}
|
|
1143
|
-
function char(name, options = {}) {
|
|
1144
|
-
return new ColumnBuilder(name, 'string', options);
|
|
1145
|
-
}
|
|
1146
|
-
// 数字相关列类型别名
|
|
1147
|
-
function bigint(name, options = {}) {
|
|
1148
|
-
return new ColumnBuilder(name, 'integer', options);
|
|
1149
|
-
}
|
|
1150
|
-
function smallint(name, options = {}) {
|
|
1151
|
-
return new ColumnBuilder(name, 'integer', options);
|
|
1152
|
-
}
|
|
1153
|
-
function tinyint(name, options = {}) {
|
|
1154
|
-
return new ColumnBuilder(name, 'integer', options);
|
|
1155
|
-
}
|
|
1156
|
-
function mediumint(name, options = {}) {
|
|
1157
|
-
return new ColumnBuilder(name, 'integer', options);
|
|
1158
|
-
}
|
|
1159
|
-
function serial(name, options = {}) {
|
|
1160
|
-
return new ColumnBuilder(name, 'integer', options);
|
|
1161
|
-
}
|
|
1162
|
-
// 浮点数相关列类型别名
|
|
1163
|
-
function real(name, options = {}) {
|
|
1164
|
-
return new ColumnBuilder(name, 'integer', options);
|
|
1165
|
-
}
|
|
1166
|
-
function decimal(name, options = {}) {
|
|
1167
|
-
return new ColumnBuilder(name, 'integer', options);
|
|
1168
|
-
}
|
|
1169
|
-
function numeric(name, options = {}) {
|
|
1170
|
-
return new ColumnBuilder(name, 'integer', options);
|
|
1171
|
-
}
|
|
1172
|
-
function float(name, options = {}) {
|
|
1173
|
-
return new ColumnBuilder(name, 'integer', options);
|
|
1174
|
-
}
|
|
1175
|
-
function double(name, options = {}) {
|
|
1176
|
-
return new ColumnBuilder(name, 'integer', options);
|
|
1177
|
-
}
|
|
1178
|
-
// JSON相关别名
|
|
1179
|
-
function jsonb(name, options = {}) {
|
|
1180
|
-
return new ColumnBuilder(name, 'json', options);
|
|
1181
|
-
}
|
|
1182
|
-
function podTable(name, columns, options) {
|
|
1183
|
-
const processedColumns = {};
|
|
1184
|
-
for (const [key, value] of Object.entries(columns)) {
|
|
1185
|
-
if (value instanceof PodColumnBase) {
|
|
1186
|
-
processedColumns[key] = value;
|
|
1187
|
-
continue;
|
|
1188
|
-
}
|
|
1189
|
-
let column;
|
|
1190
|
-
switch (value.dataType) {
|
|
1191
|
-
case 'integer':
|
|
1192
|
-
column = new PodIntegerColumn(value.name, value.options);
|
|
1193
|
-
break;
|
|
1194
|
-
case 'datetime':
|
|
1195
|
-
column = new PodDateTimeColumn(value.name, value.options);
|
|
1196
|
-
break;
|
|
1197
|
-
case 'boolean':
|
|
1198
|
-
column = new PodBooleanColumn(value.name, value.options);
|
|
1199
|
-
break;
|
|
1200
|
-
case 'json':
|
|
1201
|
-
column = new PodJsonColumn(value.name, value.options);
|
|
1202
|
-
break;
|
|
1203
|
-
case 'object':
|
|
1204
|
-
column = new PodObjectColumn(value.name, value.options);
|
|
1205
|
-
break;
|
|
1206
|
-
case 'array': {
|
|
1207
|
-
const elementType = (value.elementType ?? value.options.baseType ?? 'string');
|
|
1208
|
-
column = new PodArrayColumn(value.name, elementType, value.options);
|
|
1209
|
-
break;
|
|
1210
|
-
}
|
|
1211
|
-
case 'uri':
|
|
1212
|
-
column = new PodUriColumn(value.name, value.options);
|
|
1213
|
-
break;
|
|
1214
|
-
case 'string':
|
|
1215
|
-
default:
|
|
1216
|
-
column = new PodStringColumn(value.name, value.options);
|
|
1217
|
-
break;
|
|
1218
|
-
}
|
|
1219
|
-
const predicateUri = value.getPredicateUri();
|
|
1220
|
-
if (predicateUri) {
|
|
1221
|
-
column.predicate(predicateUri);
|
|
1222
|
-
}
|
|
1223
|
-
processedColumns[key] = column;
|
|
1224
|
-
}
|
|
1225
|
-
return new PodTable(name, processedColumns, options);
|
|
1226
|
-
}
|
|
1227
|
-
function relations(table, builder) {
|
|
1228
|
-
const helpers = {
|
|
1229
|
-
one: (target, options = {}) => {
|
|
1230
|
-
const isFederated = isSolidSchema(target);
|
|
1231
|
-
return {
|
|
1232
|
-
type: 'one',
|
|
1233
|
-
table: target,
|
|
1234
|
-
fields: options.fields,
|
|
1235
|
-
references: options.references,
|
|
1236
|
-
relationName: options.relationName,
|
|
1237
|
-
discover: options.discover,
|
|
1238
|
-
isFederated,
|
|
1239
|
-
};
|
|
1240
|
-
},
|
|
1241
|
-
many: (target, options = {}) => {
|
|
1242
|
-
const isFederated = isSolidSchema(target);
|
|
1243
|
-
return {
|
|
1244
|
-
type: 'many',
|
|
1245
|
-
table: target,
|
|
1246
|
-
fields: options.fields,
|
|
1247
|
-
references: options.references,
|
|
1248
|
-
relationName: options.relationName,
|
|
1249
|
-
discover: options.discover,
|
|
1250
|
-
isFederated,
|
|
1251
|
-
};
|
|
1252
|
-
}
|
|
1253
|
-
};
|
|
1254
|
-
const defs = builder(helpers);
|
|
1255
|
-
table.relations = defs;
|
|
1256
|
-
return defs;
|
|
1257
|
-
}
|
|
1258
|
-
// 常用的 RDF 谓词常量
|
|
1259
|
-
exports.RDF_PREDICATES = {
|
|
1260
|
-
// Schema.org 常用谓词
|
|
1261
|
-
SCHEMA_NAME: 'https://schema.org/name',
|
|
1262
|
-
SCHEMA_EMAIL: 'https://schema.org/email',
|
|
1263
|
-
SCHEMA_IDENTIFIER: 'https://schema.org/identifier',
|
|
1264
|
-
SCHEMA_DATE_CREATED: 'https://schema.org/dateCreated',
|
|
1265
|
-
SCHEMA_DATE_MODIFIED: 'https://schema.org/dateModified',
|
|
1266
|
-
SCHEMA_DESCRIPTION: 'https://schema.org/description',
|
|
1267
|
-
SCHEMA_URL: 'https://schema.org/url',
|
|
1268
|
-
SCHEMA_TITLE: 'https://schema.org/title',
|
|
1269
|
-
SCHEMA_TEXT: 'https://schema.org/text',
|
|
1270
|
-
SCHEMA_AUTHOR: 'https://schema.org/author',
|
|
1271
|
-
SCHEMA_DATE_PUBLISHED: 'https://schema.org/datePublished',
|
|
1272
|
-
// FOAF 常用谓词
|
|
1273
|
-
FOAF_NAME: 'http://xmlns.com/foaf/0.1/name',
|
|
1274
|
-
FOAF_MBOX: 'http://xmlns.com/foaf/0.1/mbox',
|
|
1275
|
-
FOAF_HOMEPAGE: 'http://xmlns.com/foaf/0.1/homepage',
|
|
1276
|
-
// Dublin Core 常用谓词
|
|
1277
|
-
DC_TITLE: 'http://purl.org/dc/terms/title',
|
|
1278
|
-
DC_DESCRIPTION: 'http://purl.org/dc/terms/description',
|
|
1279
|
-
DC_CREATED: 'http://purl.org/dc/terms/created',
|
|
1280
|
-
DC_MODIFIED: 'http://purl.org/dc/terms/modified',
|
|
1281
|
-
};
|
|
1282
|
-
// 常用的 RDF 类型常量
|
|
1283
|
-
exports.RDF_CLASSES = {
|
|
1284
|
-
// Schema.org 常用类型
|
|
1285
|
-
SCHEMA_PERSON: 'https://schema.org/Person',
|
|
1286
|
-
SCHEMA_BLOG_POSTING: 'https://schema.org/BlogPosting',
|
|
1287
|
-
SCHEMA_ARTICLE: 'https://schema.org/Article',
|
|
1288
|
-
SCHEMA_ORGANIZATION: 'https://schema.org/Organization',
|
|
1289
|
-
SCHEMA_EVENT: 'https://schema.org/Event',
|
|
1290
|
-
SCHEMA_PLACE: 'https://schema.org/Place',
|
|
1291
|
-
// FOAF 常用类型
|
|
1292
|
-
FOAF_PERSON: 'http://xmlns.com/foaf/0.1/Person',
|
|
1293
|
-
FOAF_ORGANIZATION: 'http://xmlns.com/foaf/0.1/Organization',
|
|
1294
|
-
// 自定义应用类型示例
|
|
1295
|
-
APP_USER: 'https://myapp.com/vocab#User',
|
|
1296
|
-
APP_POST: 'https://myapp.com/vocab#Post',
|
|
1297
|
-
APP_COMMENT: 'https://myapp.com/vocab#Comment',
|
|
1298
|
-
APP_TAG: 'https://myapp.com/vocab#Tag',
|
|
1299
|
-
};
|
|
1300
|
-
//# sourceMappingURL=pod-table.js.map
|