ocean-brain 0.1.1
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.
Potentially problematic release.
This version of ocean-brain might be problematic. Click here for more details.
- package/dist/index.js +41 -0
- package/package.json +32 -0
- package/server/client/dist/assets/index-BBmw_0Bo.css +1 -0
- package/server/client/dist/assets/index-TKn2sngc.js +393 -0
- package/server/client/dist/assets/module-RjUF93sV.js +716 -0
- package/server/client/dist/assets/native-48B9X9Wg.js +1 -0
- package/server/client/dist/assets/note-core-DTIu0anW.js +178 -0
- package/server/client/dist/assets/note-vendor-DhbUD4OO.js +54 -0
- package/server/client/dist/fonts/Pretendard-Bold.woff +0 -0
- package/server/client/dist/fonts/Pretendard-Bold.woff2 +0 -0
- package/server/client/dist/fonts/Pretendard-Regular.woff +0 -0
- package/server/client/dist/fonts/Pretendard-Regular.woff2 +0 -0
- package/server/client/dist/icon.png +0 -0
- package/server/client/dist/index.html +19 -0
- package/server/dist/app.js +18 -0
- package/server/dist/app.js.map +1 -0
- package/server/dist/main.js +5 -0
- package/server/dist/main.js.map +1 -0
- package/server/dist/models.js +8 -0
- package/server/dist/models.js.map +1 -0
- package/server/dist/modules/auth.js +16 -0
- package/server/dist/modules/auth.js.map +1 -0
- package/server/dist/modules/graphql.js +7 -0
- package/server/dist/modules/graphql.js.map +1 -0
- package/server/dist/modules/logger.js +72 -0
- package/server/dist/modules/logger.js.map +1 -0
- package/server/dist/modules/use-async.js +13 -0
- package/server/dist/modules/use-async.js.map +1 -0
- package/server/dist/paths.js +14 -0
- package/server/dist/paths.js.map +1 -0
- package/server/dist/schema/cache/index.js +58 -0
- package/server/dist/schema/cache/index.js.map +1 -0
- package/server/dist/schema/image/index.js +88 -0
- package/server/dist/schema/image/index.js.map +1 -0
- package/server/dist/schema/index.js +30 -0
- package/server/dist/schema/index.js.map +1 -0
- package/server/dist/schema/note/index.js +400 -0
- package/server/dist/schema/note/index.js.map +1 -0
- package/server/dist/schema/placeholder/index.js +105 -0
- package/server/dist/schema/placeholder/index.js.map +1 -0
- package/server/dist/schema/reminder/index.js +161 -0
- package/server/dist/schema/reminder/index.js.map +1 -0
- package/server/dist/schema/tag/index.js +81 -0
- package/server/dist/schema/tag/index.js.map +1 -0
- package/server/dist/types/index.js +2 -0
- package/server/dist/types/index.js.map +1 -0
- package/server/dist/types/input.js +1 -0
- package/server/dist/types/input.js.map +1 -0
- package/server/dist/urls.js +8 -0
- package/server/dist/urls.js.map +1 -0
- package/server/dist/views/image.js +101 -0
- package/server/dist/views/image.js.map +1 -0
- package/server/dist/views/index.js +2 -0
- package/server/dist/views/index.js.map +1 -0
- package/server/prisma/migrations/20230521193126_0000/migration.sql +24 -0
- package/server/prisma/migrations/20240317022222_0001/migration.sql +8 -0
- package/server/prisma/migrations/20240317094153_0002/migration.sql +8 -0
- package/server/prisma/migrations/20240318110450_0003/migration.sql +21 -0
- package/server/prisma/migrations/20240414044922_0004/migration.sql +15 -0
- package/server/prisma/migrations/20241115130540_0005/migration.sql +25 -0
- package/server/prisma/migrations/20250416124833_0006/migration.sql +29 -0
- package/server/prisma/migrations/20250711131318_0007/migration.sql +12 -0
- package/server/prisma/migrations/20251024192500_0008/migration.sql +2 -0
- package/server/prisma/migrations/20251026050237_0009/migration.sql +18 -0
- package/server/prisma/migrations/migration_lock.toml +3 -0
- package/server/prisma/schema.prisma +78 -0
|
@@ -0,0 +1,400 @@
|
|
|
1
|
+
import models from "../../models.js";
|
|
2
|
+
import { gql } from "../../modules/graphql.js";
|
|
3
|
+
const noteType = gql`
|
|
4
|
+
input PaginationInput {
|
|
5
|
+
limit: Int!
|
|
6
|
+
offset: Int!
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
input SearchFilterInput {
|
|
10
|
+
query: String!
|
|
11
|
+
sortBy: String
|
|
12
|
+
sortOrder: String
|
|
13
|
+
pinnedFirst: Boolean
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
input DateRangeInput {
|
|
17
|
+
start: String!
|
|
18
|
+
end: String!
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
enum NoteLayout {
|
|
22
|
+
narrow
|
|
23
|
+
wide
|
|
24
|
+
full
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
input NoteInput {
|
|
28
|
+
title: String
|
|
29
|
+
content: String
|
|
30
|
+
layout: NoteLayout
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
input NoteOrderInput {
|
|
34
|
+
id: ID!
|
|
35
|
+
order: Int!
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
type Tag {
|
|
39
|
+
id: ID!
|
|
40
|
+
name: String!
|
|
41
|
+
createdAt: String!
|
|
42
|
+
updatedAt: String!
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
type Note {
|
|
46
|
+
id: ID!
|
|
47
|
+
title: String!
|
|
48
|
+
content: String!
|
|
49
|
+
createdAt: String!
|
|
50
|
+
updatedAt: String!
|
|
51
|
+
pinned: Boolean!
|
|
52
|
+
order: Int!
|
|
53
|
+
layout: NoteLayout!
|
|
54
|
+
tags: [Tag!]!
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
type Notes {
|
|
58
|
+
totalCount: Int!
|
|
59
|
+
notes: [Note!]!
|
|
60
|
+
}
|
|
61
|
+
`;
|
|
62
|
+
const noteQuery = gql`
|
|
63
|
+
type GraphNode {
|
|
64
|
+
id: ID!
|
|
65
|
+
title: String!
|
|
66
|
+
connections: Int!
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
type GraphLink {
|
|
70
|
+
source: ID!
|
|
71
|
+
target: ID!
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
type NoteGraph {
|
|
75
|
+
nodes: [GraphNode!]!
|
|
76
|
+
links: [GraphLink!]!
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
type Query {
|
|
80
|
+
allNotes(searchFilter: SearchFilterInput, pagination: PaginationInput): Notes!
|
|
81
|
+
tagNotes(searchFilter: SearchFilterInput, pagination: PaginationInput): Notes!
|
|
82
|
+
notesInDateRange(dateRange: DateRangeInput): [Note!]!
|
|
83
|
+
pinnedNotes: [Note!]!
|
|
84
|
+
imageNotes(src: String!): [Note!]!
|
|
85
|
+
backReferences(id: ID!): [Note]!
|
|
86
|
+
note(id: ID!): Note!
|
|
87
|
+
noteGraph: NoteGraph!
|
|
88
|
+
}
|
|
89
|
+
`;
|
|
90
|
+
const noteMutation = gql`
|
|
91
|
+
type Mutation {
|
|
92
|
+
createNote(note: NoteInput!): Note!
|
|
93
|
+
updateNote(id: ID!, note: NoteInput!): Note!
|
|
94
|
+
deleteNote(id: ID!): Boolean!
|
|
95
|
+
pinNote(id: ID!, pinned: Boolean!): Note!
|
|
96
|
+
reorderNotes(notes: [NoteOrderInput!]!): [Note!]!
|
|
97
|
+
}
|
|
98
|
+
`;
|
|
99
|
+
const noteTypeDefs = `
|
|
100
|
+
${noteType}
|
|
101
|
+
${noteQuery}
|
|
102
|
+
${noteMutation}
|
|
103
|
+
`;
|
|
104
|
+
const extractBlocksByType = (type, dataArray) => {
|
|
105
|
+
let result = [];
|
|
106
|
+
for (const data of dataArray) {
|
|
107
|
+
if (data.type === type) {
|
|
108
|
+
result.push(data);
|
|
109
|
+
}
|
|
110
|
+
if (data.children && data.children.length > 0) {
|
|
111
|
+
result = result.concat(extractBlocksByType(type, data.children));
|
|
112
|
+
}
|
|
113
|
+
if (data.content && data.content.length > 0) {
|
|
114
|
+
for (const contentItem of data.content) {
|
|
115
|
+
if (contentItem.type === type) {
|
|
116
|
+
result.push(contentItem);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
return result;
|
|
122
|
+
};
|
|
123
|
+
const noteResolvers = {
|
|
124
|
+
Query: {
|
|
125
|
+
allNotes: async (_, {
|
|
126
|
+
searchFilter,
|
|
127
|
+
pagination
|
|
128
|
+
}) => {
|
|
129
|
+
const queryItems = searchFilter.query.split(" ");
|
|
130
|
+
const included = queryItems.filter((item) => !item.startsWith("-")).map((word) => `%${word}%`);
|
|
131
|
+
const excluded = queryItems.filter((item) => item.startsWith("-")).map((item) => item.slice(1)).map((word) => `%${word}%`);
|
|
132
|
+
const where = {
|
|
133
|
+
AND: [
|
|
134
|
+
...included.map((keyword) => ({
|
|
135
|
+
OR: [
|
|
136
|
+
{ title: { contains: keyword } },
|
|
137
|
+
{ content: { contains: keyword } }
|
|
138
|
+
]
|
|
139
|
+
})),
|
|
140
|
+
...excluded.map((keyword) => ({
|
|
141
|
+
NOT: {
|
|
142
|
+
OR: [
|
|
143
|
+
{ title: { contains: keyword } },
|
|
144
|
+
{ content: { contains: keyword } }
|
|
145
|
+
]
|
|
146
|
+
}
|
|
147
|
+
}))
|
|
148
|
+
]
|
|
149
|
+
};
|
|
150
|
+
const sortBy = searchFilter.sortBy || "updatedAt";
|
|
151
|
+
const sortOrder = searchFilter.sortOrder || "desc";
|
|
152
|
+
const pinnedFirst = searchFilter.pinnedFirst || false;
|
|
153
|
+
const orderBy = [];
|
|
154
|
+
if (pinnedFirst) {
|
|
155
|
+
orderBy.push({ pinned: "desc" });
|
|
156
|
+
}
|
|
157
|
+
if (sortBy === "createdAt") {
|
|
158
|
+
orderBy.push({ createdAt: sortOrder });
|
|
159
|
+
} else {
|
|
160
|
+
orderBy.push({ updatedAt: sortOrder });
|
|
161
|
+
}
|
|
162
|
+
const $notes = models.note.findMany({
|
|
163
|
+
orderBy,
|
|
164
|
+
where,
|
|
165
|
+
take: Number(pagination.limit),
|
|
166
|
+
skip: Number(pagination.offset)
|
|
167
|
+
});
|
|
168
|
+
return {
|
|
169
|
+
totalCount: models.note.count({ where }),
|
|
170
|
+
notes: $notes
|
|
171
|
+
};
|
|
172
|
+
},
|
|
173
|
+
notesInDateRange: async (_, { dateRange }) => {
|
|
174
|
+
const where = {
|
|
175
|
+
OR: [
|
|
176
|
+
{
|
|
177
|
+
updatedAt: {
|
|
178
|
+
gte: new Date(dateRange.start),
|
|
179
|
+
lte: new Date(dateRange.end)
|
|
180
|
+
}
|
|
181
|
+
},
|
|
182
|
+
{
|
|
183
|
+
createdAt: {
|
|
184
|
+
gte: new Date(dateRange.start),
|
|
185
|
+
lte: new Date(dateRange.end)
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
]
|
|
189
|
+
};
|
|
190
|
+
const $notes = await models.note.findMany({
|
|
191
|
+
orderBy: { createdAt: "asc" },
|
|
192
|
+
where
|
|
193
|
+
});
|
|
194
|
+
return $notes;
|
|
195
|
+
},
|
|
196
|
+
tagNotes: async (_, {
|
|
197
|
+
searchFilter,
|
|
198
|
+
pagination
|
|
199
|
+
}) => {
|
|
200
|
+
const where = { tags: { some: { id: Number(searchFilter.query) } } };
|
|
201
|
+
const $notes = models.note.findMany({
|
|
202
|
+
orderBy: { updatedAt: "desc" },
|
|
203
|
+
where,
|
|
204
|
+
take: Number(pagination.limit),
|
|
205
|
+
skip: Number(pagination.offset)
|
|
206
|
+
});
|
|
207
|
+
return {
|
|
208
|
+
totalCount: models.note.count({ where }),
|
|
209
|
+
notes: $notes
|
|
210
|
+
};
|
|
211
|
+
},
|
|
212
|
+
pinnedNotes: async () => models.note.findMany({
|
|
213
|
+
orderBy: [
|
|
214
|
+
{ order: "asc" },
|
|
215
|
+
{ updatedAt: "desc" }
|
|
216
|
+
],
|
|
217
|
+
where: { pinned: true }
|
|
218
|
+
}),
|
|
219
|
+
imageNotes: async (_, { src }) => models.note.findMany({
|
|
220
|
+
orderBy: { updatedAt: "desc" },
|
|
221
|
+
where: { content: { contains: src } }
|
|
222
|
+
}),
|
|
223
|
+
backReferences: async (_, { id }) => {
|
|
224
|
+
return models.note.findMany({
|
|
225
|
+
orderBy: [
|
|
226
|
+
{ pinned: "desc" },
|
|
227
|
+
{ updatedAt: "desc" }
|
|
228
|
+
],
|
|
229
|
+
where: { content: { contains: `reference","props":{"id":"${id}"` } }
|
|
230
|
+
});
|
|
231
|
+
},
|
|
232
|
+
note: async (_, { id }) => {
|
|
233
|
+
const $note = await models.note.findUnique({ where: { id: Number(id) } });
|
|
234
|
+
if (!$note) {
|
|
235
|
+
throw "NOT FOUND";
|
|
236
|
+
}
|
|
237
|
+
if ($note.content) {
|
|
238
|
+
const blocks = extractBlocksByType("reference", JSON.parse($note.content));
|
|
239
|
+
if (blocks.length > 0) {
|
|
240
|
+
const referenceIds = blocks.map((block) => Number(block.props.id));
|
|
241
|
+
const $references = await models.note.findMany({ where: { id: { in: referenceIds } } });
|
|
242
|
+
const newContent = $references.reduce((acc, $reference) => {
|
|
243
|
+
const reference = blocks.find((block) => Number(block.props.id) === $reference.id);
|
|
244
|
+
if (reference && reference.props.title !== $reference.title) {
|
|
245
|
+
return acc.replace(
|
|
246
|
+
`reference","props":{"id":"${reference.props.id}","title":"${reference.props.title}"`,
|
|
247
|
+
`reference","props":{"id":"${$reference.id}","title":"${$reference.title}"`
|
|
248
|
+
);
|
|
249
|
+
}
|
|
250
|
+
return acc;
|
|
251
|
+
}, $note.content);
|
|
252
|
+
if (newContent !== $note.content) {
|
|
253
|
+
try {
|
|
254
|
+
JSON.parse(newContent);
|
|
255
|
+
return await models.note.update({
|
|
256
|
+
where: { id: $note.id },
|
|
257
|
+
data: { content: newContent }
|
|
258
|
+
});
|
|
259
|
+
} catch (e) {
|
|
260
|
+
console.error(e);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
return $note;
|
|
266
|
+
},
|
|
267
|
+
noteGraph: async () => {
|
|
268
|
+
const $notes = await models.note.findMany({
|
|
269
|
+
select: {
|
|
270
|
+
id: true,
|
|
271
|
+
title: true,
|
|
272
|
+
content: true
|
|
273
|
+
}
|
|
274
|
+
});
|
|
275
|
+
const nodes = [];
|
|
276
|
+
const links = [];
|
|
277
|
+
const connectionCount = {};
|
|
278
|
+
const linkSet = /* @__PURE__ */ new Set();
|
|
279
|
+
for (const $note of $notes) {
|
|
280
|
+
if ($note.content) {
|
|
281
|
+
try {
|
|
282
|
+
const blocks = extractBlocksByType("reference", JSON.parse($note.content));
|
|
283
|
+
for (const block of blocks) {
|
|
284
|
+
const targetId = block.props.id;
|
|
285
|
+
if (targetId && String($note.id) !== targetId) {
|
|
286
|
+
const linkKey = `${$note.id}-${targetId}`;
|
|
287
|
+
const reverseLinkKey = `${targetId}-${$note.id}`;
|
|
288
|
+
if (!linkSet.has(linkKey) && !linkSet.has(reverseLinkKey)) {
|
|
289
|
+
linkSet.add(linkKey);
|
|
290
|
+
links.push({
|
|
291
|
+
source: String($note.id),
|
|
292
|
+
target: targetId
|
|
293
|
+
});
|
|
294
|
+
connectionCount[String($note.id)] = (connectionCount[String($note.id)] || 0) + 1;
|
|
295
|
+
connectionCount[targetId] = (connectionCount[targetId] || 0) + 1;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
} catch {
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
for (const $note of $notes) {
|
|
304
|
+
nodes.push({
|
|
305
|
+
id: String($note.id),
|
|
306
|
+
title: $note.title || "Untitled",
|
|
307
|
+
connections: connectionCount[String($note.id)] || 0
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
return {
|
|
311
|
+
nodes,
|
|
312
|
+
links
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
},
|
|
316
|
+
Mutation: {
|
|
317
|
+
createNote: async (_, { note }) => {
|
|
318
|
+
const PLACEHOLDER_PREFIX = "{%";
|
|
319
|
+
const PLACEHOLDER_SUFFIX = "%}";
|
|
320
|
+
const replacePlaceholder = async (content) => {
|
|
321
|
+
const placeholders = content.matchAll(new RegExp(`${PLACEHOLDER_PREFIX}([^}]+)${PLACEHOLDER_SUFFIX}`, "g"));
|
|
322
|
+
const $placeholders = await models.placeholder.findMany({
|
|
323
|
+
select: {
|
|
324
|
+
template: true,
|
|
325
|
+
replacement: true
|
|
326
|
+
},
|
|
327
|
+
where: { template: { in: Array.from(new Set(Array.from(placeholders, (p) => p[1]))) } }
|
|
328
|
+
});
|
|
329
|
+
for (const $placeholder of $placeholders) {
|
|
330
|
+
content = content.replace(new RegExp(`${PLACEHOLDER_PREFIX}${$placeholder.template}${PLACEHOLDER_SUFFIX}`, "g"), $placeholder.replacement);
|
|
331
|
+
}
|
|
332
|
+
return content;
|
|
333
|
+
};
|
|
334
|
+
const replacedTitle = await replacePlaceholder(note.title);
|
|
335
|
+
const replacedContent = await replacePlaceholder(note.content);
|
|
336
|
+
const $note = await models.note.create({
|
|
337
|
+
data: {
|
|
338
|
+
title: replacedTitle,
|
|
339
|
+
content: replacedContent,
|
|
340
|
+
...note.layout && { layout: note.layout }
|
|
341
|
+
}
|
|
342
|
+
});
|
|
343
|
+
if (note.content) {
|
|
344
|
+
const blocks = extractBlocksByType(
|
|
345
|
+
"tag",
|
|
346
|
+
JSON.parse(note.content)
|
|
347
|
+
);
|
|
348
|
+
return await models.note.update({
|
|
349
|
+
where: { id: $note.id },
|
|
350
|
+
data: { tags: { set: blocks.map((block) => ({ id: Number(block.props.id) })) } }
|
|
351
|
+
});
|
|
352
|
+
}
|
|
353
|
+
return $note;
|
|
354
|
+
},
|
|
355
|
+
updateNote: async (_, { id, note }) => {
|
|
356
|
+
let blocks = [];
|
|
357
|
+
if (note.content) {
|
|
358
|
+
blocks = extractBlocksByType(
|
|
359
|
+
"tag",
|
|
360
|
+
JSON.parse(note.content)
|
|
361
|
+
);
|
|
362
|
+
}
|
|
363
|
+
const $note = await models.note.update({
|
|
364
|
+
where: { id: Number(id) },
|
|
365
|
+
data: {
|
|
366
|
+
...note,
|
|
367
|
+
...note.content ? { tags: { set: blocks.map((block) => ({ id: Number(block.props.id) })) } } : {}
|
|
368
|
+
}
|
|
369
|
+
});
|
|
370
|
+
return $note;
|
|
371
|
+
},
|
|
372
|
+
deleteNote: async (_, { id }) => {
|
|
373
|
+
await models.tag.deleteMany({ where: { notes: { none: {} } } });
|
|
374
|
+
await models.note.delete({ where: { id: Number(id) } });
|
|
375
|
+
return true;
|
|
376
|
+
},
|
|
377
|
+
pinNote: (_, { id, pinned }) => models.note.update({
|
|
378
|
+
where: { id: Number(id) },
|
|
379
|
+
data: { pinned: Boolean(pinned) }
|
|
380
|
+
}),
|
|
381
|
+
reorderNotes: async (_, { notes }) => {
|
|
382
|
+
const updatePromises = notes.map(
|
|
383
|
+
({ id, order }) => models.note.update({
|
|
384
|
+
where: { id: Number(id) },
|
|
385
|
+
data: { order }
|
|
386
|
+
})
|
|
387
|
+
);
|
|
388
|
+
return await Promise.all(updatePromises);
|
|
389
|
+
}
|
|
390
|
+
},
|
|
391
|
+
Note: { tags: async (note) => await models.tag.findMany({ where: { notes: { some: { id: note.id } } } }) }
|
|
392
|
+
};
|
|
393
|
+
export {
|
|
394
|
+
noteMutation,
|
|
395
|
+
noteQuery,
|
|
396
|
+
noteResolvers,
|
|
397
|
+
noteType,
|
|
398
|
+
noteTypeDefs
|
|
399
|
+
};
|
|
400
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/schema/note/index.ts"],"sourcesContent":["import type { IResolvers } from '@graphql-tools/utils';\n\nimport models from '~/models.js';\nimport { gql } from '~/modules/graphql.js';\n\nimport type { Note, Prisma } from '~/models.js';\nimport type { Pagination, SearchFilter, NoteInput } from '~/types/index.js';\n\nexport const noteType = gql`\n input PaginationInput {\n limit: Int!\n offset: Int!\n }\n\n input SearchFilterInput {\n query: String!\n sortBy: String\n sortOrder: String\n pinnedFirst: Boolean\n }\n\n input DateRangeInput {\n start: String!\n end: String!\n }\n\n enum NoteLayout {\n narrow\n wide\n full\n }\n\n input NoteInput {\n title: String\n content: String\n layout: NoteLayout\n }\n\n input NoteOrderInput {\n id: ID!\n order: Int!\n }\n\n type Tag {\n id: ID!\n name: String!\n createdAt: String!\n updatedAt: String!\n }\n\n type Note {\n id: ID!\n title: String!\n content: String!\n createdAt: String!\n updatedAt: String!\n pinned: Boolean!\n order: Int!\n layout: NoteLayout!\n tags: [Tag!]!\n }\n\n type Notes {\n totalCount: Int!\n notes: [Note!]!\n }\n`;\n\nexport const noteQuery = gql`\n type GraphNode {\n id: ID!\n title: String!\n connections: Int!\n }\n\n type GraphLink {\n source: ID!\n target: ID!\n }\n\n type NoteGraph {\n nodes: [GraphNode!]!\n links: [GraphLink!]!\n }\n\n type Query {\n allNotes(searchFilter: SearchFilterInput, pagination: PaginationInput): Notes!\n tagNotes(searchFilter: SearchFilterInput, pagination: PaginationInput): Notes!\n notesInDateRange(dateRange: DateRangeInput): [Note!]!\n pinnedNotes: [Note!]!\n imageNotes(src: String!): [Note!]!\n backReferences(id: ID!): [Note]!\n note(id: ID!): Note!\n noteGraph: NoteGraph!\n }\n`;\n\nexport const noteMutation = gql`\n type Mutation {\n createNote(note: NoteInput!): Note!\n updateNote(id: ID!, note: NoteInput!): Note!\n deleteNote(id: ID!): Boolean!\n pinNote(id: ID!, pinned: Boolean!): Note!\n reorderNotes(notes: [NoteOrderInput!]!): [Note!]!\n }\n`;\n\nexport const noteTypeDefs = `\n ${noteType}\n ${noteQuery}\n ${noteMutation}\n`;\n\ninterface BlockNote<T = unknown> {\n id: string;\n type: string;\n props: T;\n content?: BlockNote<T>[];\n children?: BlockNote<T>[];\n}\n\nconst extractBlocksByType = <T>(type: string, dataArray: BlockNote[]): BlockNote<T>[] => {\n let result: BlockNote[] = [];\n\n for (const data of dataArray) {\n if (data.type === type) {\n result.push(data);\n }\n\n if (data.children && data.children.length > 0) {\n result = result.concat(extractBlocksByType(type, data.children));\n }\n\n if (data.content && data.content.length > 0) {\n for (const contentItem of data.content) {\n if (contentItem.type === type) {\n result.push(contentItem);\n }\n }\n }\n }\n\n return result as unknown as BlockNote<T>[];\n};\n\nexport const noteResolvers: IResolvers = {\n Query: {\n allNotes: async (_, {\n searchFilter,\n pagination\n }: {\n searchFilter: SearchFilter;\n pagination: Pagination;\n }) => {\n const queryItems = searchFilter.query.split(' ');\n const included = queryItems\n .filter((item: string) => !item.startsWith('-'))\n .map((word: string) => `%${word}%`);\n const excluded = queryItems\n .filter((item: string) => item.startsWith('-'))\n .map((item: string) => item.slice(1))\n .map((word: string) => `%${word}%`);\n\n const where: Prisma.NoteWhereInput = {\n AND: [\n ...included.map((keyword: string) => ({\n OR: [\n { title: { contains: keyword } },\n { content: { contains: keyword } }\n ]\n })),\n ...excluded.map((keyword: string) => ({\n NOT: {\n OR: [\n { title: { contains: keyword } },\n { content: { contains: keyword } }\n ]\n }\n }))\n ]\n };\n\n const sortBy = searchFilter.sortBy || 'updatedAt';\n const sortOrder = searchFilter.sortOrder || 'desc';\n const pinnedFirst = searchFilter.pinnedFirst || false;\n\n const orderBy: Prisma.NoteOrderByWithRelationInput[] = [];\n\n if (pinnedFirst) {\n orderBy.push({ pinned: 'desc' });\n }\n\n if (sortBy === 'createdAt') {\n orderBy.push({ createdAt: sortOrder as 'asc' | 'desc' });\n } else {\n orderBy.push({ updatedAt: sortOrder as 'asc' | 'desc' });\n }\n\n const $notes = models.note.findMany({\n orderBy,\n where,\n take: Number(pagination.limit),\n skip: Number(pagination.offset)\n });\n return {\n totalCount: models.note.count({ where }),\n notes: $notes\n };\n },\n notesInDateRange: async (_, { dateRange }: {\n dateRange: {\n start: string;\n end: string;\n };\n }) => {\n const where: Prisma.NoteWhereInput = {\n OR: [\n {\n updatedAt: {\n gte: new Date(dateRange.start),\n lte: new Date(dateRange.end)\n }\n },\n {\n createdAt: {\n gte: new Date(dateRange.start),\n lte: new Date(dateRange.end)\n }\n }\n ]\n };\n\n const $notes = await models.note.findMany({\n orderBy: { createdAt: 'asc' },\n where\n });\n\n return $notes;\n },\n tagNotes: async (_, {\n searchFilter,\n pagination\n }: {\n searchFilter: SearchFilter;\n pagination: Pagination;\n }) => {\n const where: Prisma.NoteWhereInput = { tags: { some: { id: Number(searchFilter.query) } } };\n\n const $notes = models.note.findMany({\n orderBy: { updatedAt: 'desc' },\n where,\n take: Number(pagination.limit),\n skip: Number(pagination.offset)\n });\n return {\n totalCount: models.note.count({ where }),\n notes: $notes\n };\n },\n pinnedNotes: async () => models.note.findMany({\n orderBy: [\n { order: 'asc' },\n { updatedAt: 'desc' }\n ],\n where: { pinned: true }\n }),\n imageNotes: async (_, { src }) => models.note.findMany({\n orderBy: { updatedAt: 'desc' },\n where: { content: { contains: src } }\n }),\n backReferences: async (_, { id }: Note) => {\n return models.note.findMany({\n orderBy: [\n { pinned: 'desc' },\n { updatedAt: 'desc' }\n ],\n where: { content: { contains: `reference\",\"props\":{\"id\":\"${id}\"` } }\n });\n },\n note: async (_, { id }: Note) => {\n const $note = await models.note.findUnique({ where: { id: Number(id) } });\n if (!$note) {\n throw 'NOT FOUND';\n }\n if ($note.content) {\n const blocks = extractBlocksByType<{\n id: string;\n title: string;\n }>('reference', JSON.parse($note.content));\n if (blocks.length > 0) {\n const referenceIds = blocks.map(block => Number(block.props.id));\n const $references = await models.note.findMany({ where: { id: { in: referenceIds } } });\n const newContent = $references.reduce<string>((acc: string, $reference: Note) => {\n const reference = blocks.find(block => Number(block.props.id) === $reference.id);\n if (reference && reference.props.title !== $reference.title) {\n return acc.replace(\n `reference\",\"props\":{\"id\":\"${reference.props.id}\",\"title\":\"${reference.props.title}\"`,\n `reference\",\"props\":{\"id\":\"${$reference.id}\",\"title\":\"${$reference.title}\"`\n );\n }\n return acc;\n }, $note.content);\n if (newContent !== $note.content) {\n try {\n JSON.parse(newContent);\n return await models.note.update({\n where: { id: $note.id },\n data: { content: newContent }\n });\n } catch (e) {\n console.error(e);\n }\n }\n }\n }\n return $note;\n },\n noteGraph: async () => {\n const $notes = await models.note.findMany({\n select: {\n id: true,\n title: true,\n content: true\n }\n });\n\n const nodes: Array<{ id: string; title: string; connections: number }> = [];\n const links: Array<{ source: string; target: string }> = [];\n const connectionCount: Record<string, number> = {};\n const linkSet = new Set<string>();\n\n // Extract all references from each note\n for (const $note of $notes) {\n if ($note.content) {\n try {\n const blocks = extractBlocksByType<{ id: string }>('reference', JSON.parse($note.content));\n for (const block of blocks) {\n const targetId = block.props.id;\n // Avoid self-references and duplicate links\n if (targetId && String($note.id) !== targetId) {\n const linkKey = `${$note.id}-${targetId}`;\n const reverseLinkKey = `${targetId}-${$note.id}`;\n if (!linkSet.has(linkKey) && !linkSet.has(reverseLinkKey)) {\n linkSet.add(linkKey);\n links.push({\n source: String($note.id),\n target: targetId\n });\n // Count connections for both nodes\n connectionCount[String($note.id)] = (connectionCount[String($note.id)] || 0) + 1;\n connectionCount[targetId] = (connectionCount[targetId] || 0) + 1;\n }\n }\n }\n } catch {\n // Skip notes with invalid JSON content\n }\n }\n }\n\n // Build nodes array with connection counts\n for (const $note of $notes) {\n nodes.push({\n id: String($note.id),\n title: $note.title || 'Untitled',\n connections: connectionCount[String($note.id)] || 0\n });\n }\n\n return {\n nodes,\n links\n };\n }\n },\n Mutation: {\n createNote: async (_, { note }: { note: NoteInput }) => {\n const PLACEHOLDER_PREFIX = '{%';\n const PLACEHOLDER_SUFFIX = '%}';\n\n const replacePlaceholder = async (content: string) => {\n const placeholders = content.matchAll(new RegExp(`${PLACEHOLDER_PREFIX}([^}]+)${PLACEHOLDER_SUFFIX}`, 'g'));\n const $placeholders = await models.placeholder.findMany({\n select: {\n template: true,\n replacement: true\n },\n where: { template: { in: Array.from(new Set(Array.from(placeholders, p => p[1]))) } }\n });\n\n for (const $placeholder of $placeholders) {\n content = content.replace(new RegExp(`${PLACEHOLDER_PREFIX}${$placeholder.template}${PLACEHOLDER_SUFFIX}`, 'g'), $placeholder.replacement);\n }\n return content;\n };\n\n const replacedTitle = await replacePlaceholder(note.title);\n const replacedContent = await replacePlaceholder(note.content);\n\n const $note = await models.note.create({\n data: {\n title: replacedTitle,\n content: replacedContent,\n ...(note.layout && { layout: note.layout })\n }\n });\n if (note.content) {\n const blocks = extractBlocksByType<{ id: string }>(\n 'tag',\n JSON.parse(note.content)\n );\n\n return await models.note.update({\n where: { id: $note.id },\n data: { tags: { set: blocks.map(block => ({ id: Number(block.props.id) })) } }\n });\n }\n\n return $note;\n },\n updateNote: async (_, { id, note }: { id: number; note: NoteInput }) => {\n let blocks: BlockNote<{ id: string }>[] = [];\n\n if (note.content) {\n blocks = extractBlocksByType<{ id: string }>(\n 'tag',\n JSON.parse(note.content)\n );\n }\n\n const $note = await models.note.update({\n where: { id: Number(id) },\n data: {\n ...note,\n ...(note.content ? { tags: { set: blocks.map(block => ({ id: Number(block.props.id) })) } } : {})\n }\n });\n return $note;\n },\n deleteNote: async (_, { id }: Note) => {\n await models.tag.deleteMany({ where: { notes: { none: {} } } });\n await models.note.delete({ where: { id: Number(id) } });\n return true;\n },\n pinNote: (_, { id, pinned }: Note) => models.note.update({\n where: { id: Number(id) },\n data: { pinned: Boolean(pinned) }\n }),\n reorderNotes: async (_, { notes }: { notes: Array<{ id: string; order: number }> }) => {\n const updatePromises = notes.map(({ id, order }) =>\n models.note.update({\n where: { id: Number(id) },\n data: { order }\n })\n );\n return await Promise.all(updatePromises);\n }\n },\n Note: { tags: async (note: Note) => await models.tag.findMany({ where: { notes: { some: { id: note.id } } } }) }\n};\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import models from "../../models.js";
|
|
2
|
+
import { gql } from "../../modules/graphql.js";
|
|
3
|
+
const placeholderType = gql`
|
|
4
|
+
input PaginationInput {
|
|
5
|
+
limit: Int!
|
|
6
|
+
offset: Int!
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
input SearchFilterInput {
|
|
10
|
+
query: String!
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
type Placeholder {
|
|
14
|
+
id: ID!
|
|
15
|
+
name: String!
|
|
16
|
+
template: String!
|
|
17
|
+
replacement: String!
|
|
18
|
+
createdAt: String!
|
|
19
|
+
updatedAt: String!
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
type Placeholders {
|
|
23
|
+
totalCount: Int!
|
|
24
|
+
placeholders: [Placeholder!]!
|
|
25
|
+
}
|
|
26
|
+
`;
|
|
27
|
+
const placeholderQuery = gql`
|
|
28
|
+
type Query {
|
|
29
|
+
allPlaceholders(searchFilter: SearchFilterInput, pagination: PaginationInput): Placeholders!
|
|
30
|
+
placeholder(id: ID!): Placeholder
|
|
31
|
+
}
|
|
32
|
+
`;
|
|
33
|
+
const placeholderMutation = gql`
|
|
34
|
+
type Mutation {
|
|
35
|
+
createPlaceholder(name: String!, template: String!, replacement: String): Placeholder!
|
|
36
|
+
updatePlaceholder(id: ID!, name: String, template: String, replacement: String): Placeholder!
|
|
37
|
+
deletePlaceholder(id: ID!): Boolean!
|
|
38
|
+
}
|
|
39
|
+
`;
|
|
40
|
+
const placeholderTypeDefs = `
|
|
41
|
+
${placeholderType}
|
|
42
|
+
${placeholderQuery}
|
|
43
|
+
${placeholderMutation}
|
|
44
|
+
`;
|
|
45
|
+
const placeholderResolvers = {
|
|
46
|
+
Query: {
|
|
47
|
+
allPlaceholders: async (_, { searchFilter, pagination }) => {
|
|
48
|
+
const placeholders = await models.placeholder.findMany({
|
|
49
|
+
where: searchFilter?.query ? { name: { contains: searchFilter.query } } : void 0,
|
|
50
|
+
take: pagination?.limit,
|
|
51
|
+
skip: pagination?.offset
|
|
52
|
+
});
|
|
53
|
+
const totalCount = await models.placeholder.count();
|
|
54
|
+
return {
|
|
55
|
+
totalCount,
|
|
56
|
+
placeholders
|
|
57
|
+
};
|
|
58
|
+
},
|
|
59
|
+
placeholder: async (_, { id }) => {
|
|
60
|
+
return await models.placeholder.findFirst({ where: { id } });
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
Mutation: {
|
|
64
|
+
createPlaceholder: async (_, { name, template, replacement }) => {
|
|
65
|
+
return await models.placeholder.create({
|
|
66
|
+
data: {
|
|
67
|
+
name,
|
|
68
|
+
template,
|
|
69
|
+
replacement
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
},
|
|
73
|
+
updatePlaceholder: async (_, { id, name, template, replacement }) => {
|
|
74
|
+
const placeholder = await models.placeholder.findFirst({ where: { id } });
|
|
75
|
+
if (!placeholder) {
|
|
76
|
+
throw new Error("Placeholder not found");
|
|
77
|
+
}
|
|
78
|
+
await models.placeholder.update({
|
|
79
|
+
where: { id },
|
|
80
|
+
data: {
|
|
81
|
+
name,
|
|
82
|
+
template,
|
|
83
|
+
replacement
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
return placeholder;
|
|
87
|
+
},
|
|
88
|
+
deletePlaceholder: async (_, { id }) => {
|
|
89
|
+
const placeholder = await models.placeholder.findFirst({ where: { id: Number(id) } });
|
|
90
|
+
if (!placeholder) {
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
await models.placeholder.delete({ where: { id: Number(id) } });
|
|
94
|
+
return true;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
export {
|
|
99
|
+
placeholderMutation,
|
|
100
|
+
placeholderQuery,
|
|
101
|
+
placeholderResolvers,
|
|
102
|
+
placeholderType,
|
|
103
|
+
placeholderTypeDefs
|
|
104
|
+
};
|
|
105
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/schema/placeholder/index.ts"],"sourcesContent":["import type { IResolvers } from '@graphql-tools/utils';\n\nimport models, { type Placeholder } from '~/models.js';\nimport { gql } from '~/modules/graphql.js';\nimport type { Pagination, SearchFilter } from '~/types/index.js';\n\nexport const placeholderType = gql`\n input PaginationInput {\n limit: Int!\n offset: Int!\n }\n\n input SearchFilterInput {\n query: String!\n }\n\n type Placeholder {\n id: ID!\n name: String!\n template: String!\n replacement: String!\n createdAt: String!\n updatedAt: String!\n }\n\n type Placeholders {\n totalCount: Int!\n placeholders: [Placeholder!]!\n }\n`;\n\nexport const placeholderQuery = gql`\n type Query {\n allPlaceholders(searchFilter: SearchFilterInput, pagination: PaginationInput): Placeholders!\n placeholder(id: ID!): Placeholder\n }\n`;\n\nexport const placeholderMutation = gql`\n type Mutation {\n createPlaceholder(name: String!, template: String!, replacement: String): Placeholder!\n updatePlaceholder(id: ID!, name: String, template: String, replacement: String): Placeholder!\n deletePlaceholder(id: ID!): Boolean!\n }\n`;\n\nexport const placeholderTypeDefs = `\n ${placeholderType}\n ${placeholderQuery}\n ${placeholderMutation}\n`;\n\nexport const placeholderResolvers: IResolvers = {\n Query: {\n allPlaceholders: async (_, { searchFilter, pagination }: { searchFilter?: SearchFilter; pagination?: Pagination }) => {\n const placeholders = await models.placeholder.findMany({\n where: searchFilter?.query ? { name: { contains: searchFilter.query } } : undefined,\n take: pagination?.limit,\n skip: pagination?.offset\n });\n\n const totalCount = await models.placeholder.count();\n\n return {\n totalCount,\n placeholders\n };\n },\n placeholder: async (_, { id }: { id: number }) => {\n return await models.placeholder.findFirst({ where: { id } });\n }\n },\n Mutation: {\n createPlaceholder: async (_, { name, template, replacement }: Placeholder) => {\n return await models.placeholder.create({\n data: {\n name,\n template,\n replacement\n }\n });\n },\n updatePlaceholder: async (_, { id, name, template, replacement }: Placeholder) => {\n const placeholder = await models.placeholder.findFirst({ where: { id } });\n if (!placeholder) {\n throw new Error('Placeholder not found');\n }\n\n await models.placeholder.update({\n where: { id },\n data: {\n name,\n template,\n replacement\n }\n });\n\n return placeholder;\n },\n deletePlaceholder: async (_, { id }: { id: number }) => {\n const placeholder = await models.placeholder.findFirst({ where: { id: Number(id) } });\n if (!placeholder) {\n return false;\n }\n\n await models.placeholder.delete({ where: { id: Number(id) } });\n return true;\n }\n }\n};\n"],"mappings":"AAEA,OAAO,YAAkC;AACzC,SAAS,WAAW;AAGb,MAAM,kBAAkB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAyBxB,MAAM,mBAAmB;AAAA;AAAA;AAAA;AAAA;AAAA;AAOzB,MAAM,sBAAsB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQ5B,MAAM,sBAAsB;AAAA,MAC7B,eAAe;AAAA,MACf,gBAAgB;AAAA,MAChB,mBAAmB;AAAA;AAGlB,MAAM,uBAAmC;AAAA,EAC5C,OAAO;AAAA,IACH,iBAAiB,OAAO,GAAG,EAAE,cAAc,WAAW,MAAgE;AAClH,YAAM,eAAe,MAAM,OAAO,YAAY,SAAS;AAAA,QACnD,OAAO,cAAc,QAAQ,EAAE,MAAM,EAAE,UAAU,aAAa,MAAM,EAAE,IAAI;AAAA,QAC1E,MAAM,YAAY;AAAA,QAClB,MAAM,YAAY;AAAA,MACtB,CAAC;AAED,YAAM,aAAa,MAAM,OAAO,YAAY,MAAM;AAElD,aAAO;AAAA,QACH;AAAA,QACA;AAAA,MACJ;AAAA,IACJ;AAAA,IACA,aAAa,OAAO,GAAG,EAAE,GAAG,MAAsB;AAC9C,aAAO,MAAM,OAAO,YAAY,UAAU,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC;AAAA,IAC/D;AAAA,EACJ;AAAA,EACA,UAAU;AAAA,IACN,mBAAmB,OAAO,GAAG,EAAE,MAAM,UAAU,YAAY,MAAmB;AAC1E,aAAO,MAAM,OAAO,YAAY,OAAO;AAAA,QACnC,MAAM;AAAA,UACF;AAAA,UACA;AAAA,UACA;AAAA,QACJ;AAAA,MACJ,CAAC;AAAA,IACL;AAAA,IACA,mBAAmB,OAAO,GAAG,EAAE,IAAI,MAAM,UAAU,YAAY,MAAmB;AAC9E,YAAM,cAAc,MAAM,OAAO,YAAY,UAAU,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC;AACxE,UAAI,CAAC,aAAa;AACd,cAAM,IAAI,MAAM,uBAAuB;AAAA,MAC3C;AAEA,YAAM,OAAO,YAAY,OAAO;AAAA,QAC5B,OAAO,EAAE,GAAG;AAAA,QACZ,MAAM;AAAA,UACF;AAAA,UACA;AAAA,UACA;AAAA,QACJ;AAAA,MACJ,CAAC;AAED,aAAO;AAAA,IACX;AAAA,IACA,mBAAmB,OAAO,GAAG,EAAE,GAAG,MAAsB;AACpD,YAAM,cAAc,MAAM,OAAO,YAAY,UAAU,EAAE,OAAO,EAAE,IAAI,OAAO,EAAE,EAAE,EAAE,CAAC;AACpF,UAAI,CAAC,aAAa;AACd,eAAO;AAAA,MACX;AAEA,YAAM,OAAO,YAAY,OAAO,EAAE,OAAO,EAAE,IAAI,OAAO,EAAE,EAAE,EAAE,CAAC;AAC7D,aAAO;AAAA,IACX;AAAA,EACJ;AACJ;","names":[]}
|