Files
OSIT-AE-App-Svelte/src/lib/ae_journals/ae_journals__journal_entry.ts
Scott Idem 4a39ca1468 refactor(sort): introduce build_tmp_sort utility; apply to event_presentation and journals
Creates src/lib/ae_core/core__idb_sort.ts with build_tmp_sort() — a shared
helper for computing tmp_sort_1/2/3 fields stored in Dexie. Fixes two bugs
present in all generic _process_generic_props implementations:
  - priority encoded as 0/1 ASC (true sorted last); now inverted: true→'0'
  - sort stored as unpadded string ("10" < "2"); now 8-char zero-padded

Applied to:
  - ae_events__event_presentation: replaces inline specific_processor code
  - ae_journals__journal + ae_journals__journal_entry: replaces manual formulas;
    journal liveQueries (.reverse().sortBy()) updated to plain .sortBy() since
    the inverted encoding handles direction without needing Dexie's .reverse()

Other modules (sessions, presenters, locations, posts, core) left unchanged
until their sort behavior is reviewed separately.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-28 20:38:25 -04:00

1073 lines
34 KiB
TypeScript

import { marked } from 'marked';
import type { key_val } from '$lib/stores/ae_stores';
import { api } from '$lib/api/api';
import { db_save_ae_obj_li__ae_obj } from '$lib/ae_core/core__idb_dexie';
import { build_tmp_sort } from '$lib/ae_core/core__idb_sort';
import { db_journals } from '$lib/ae_journals/db_journals';
import type { ae_JournalEntry } from '$lib/types/ae_types';
const ae_promises: key_val = {};
// Updated 2026-01-05
export async function load_ae_obj_id__journal_entry({
api_cfg,
journal_entry_id,
try_cache = true,
log_lvl = 0
}: {
api_cfg: any;
journal_entry_id: string;
try_cache?: boolean;
log_lvl?: number;
}): Promise<ae_JournalEntry | null> {
if (log_lvl) {
console.log(
`*** load_ae_obj_id__journal_entry() *** journal_entry_id=${journal_entry_id}`
);
}
ae_promises.load__journal_entry_obj = await api
.get_ae_obj({
api_cfg: api_cfg,
obj_type: 'journal_entry',
obj_id: journal_entry_id,
log_lvl: log_lvl
})
.then(async function (journal_entry_obj_get_result) {
if (journal_entry_obj_get_result) {
if (try_cache) {
// Process the results first
const processed_obj_li =
await process_ae_obj__journal_entry_props({
obj_li: [journal_entry_obj_get_result],
log_lvl: log_lvl
});
if (log_lvl) {
console.log('Processed object list:', processed_obj_li);
}
// Save the updated results list to the database.
// IDB write is optional caching — quota failures must not discard the API result.
try {
await db_save_ae_obj_li__ae_obj({
db_instance: db_journals,
table_name: 'journal_entry',
obj_li: processed_obj_li,
properties_to_save: properties_to_save,
log_lvl: log_lvl
});
} catch (save_error) {
console.warn('IDB cache write failed for journal_entry (quota?):', save_error);
}
}
return journal_entry_obj_get_result;
} else {
console.log('No results returned.');
return null;
}
})
.catch(function (error: any) {
console.log('No results returned or failed.', error);
});
return ae_promises.load__journal_entry_obj;
}
// Updated 2026-01-02
export async function load_ae_obj_li__journal_entry({
api_cfg,
for_obj_type = 'journal',
for_obj_id,
enabled = 'enabled',
hidden = 'not_hidden',
limit = 99,
offset = 0,
order_by_li = {
priority: 'DESC',
sort: 'DESC',
name: 'ASC',
updated_on: 'DESC',
created_on: 'DESC'
},
params = {},
try_cache = true,
log_lvl = 0
}: {
api_cfg: any;
for_obj_type: string;
for_obj_id: string;
enabled?: 'enabled' | 'all' | 'not_enabled' | undefined;
hidden?: 'hidden' | 'all' | 'not_hidden' | undefined;
limit?: number;
offset?: number;
order_by_li?: key_val;
params?: key_val;
try_cache?: boolean;
log_lvl?: number;
}): Promise<ae_JournalEntry[]> {
if (log_lvl) {
console.log(
`*** load_ae_obj_li__journal_entry() *** for_obj_type=${for_obj_type} for_obj_id=${for_obj_id}`
);
}
let promise;
if (for_obj_type === 'journal' && for_obj_id) {
promise = api.get_nested_obj_li({
api_cfg,
parent_type: 'journal',
parent_id: for_obj_id,
child_type: 'journal_entry',
limit,
offset,
enabled,
hidden,
order_by_li,
log_lvl
});
} else {
promise = api.get_ae_obj_li({
api_cfg,
obj_type: 'journal_entry',
for_obj_type,
for_obj_id,
enabled,
hidden,
limit,
offset,
order_by_li,
log_lvl
});
}
ae_promises.load__journal_entry_obj_li = await promise
.then(async function (journal_entry_obj_li_get_result) {
if (journal_entry_obj_li_get_result) {
if (try_cache) {
// Process the results first
const processed_obj_li =
await process_ae_obj__journal_entry_props({
obj_li: journal_entry_obj_li_get_result,
journal_id:
for_obj_type === 'journal'
? for_obj_id
: undefined,
log_lvl: log_lvl
});
if (log_lvl) {
console.log('Processed object list:', processed_obj_li);
}
// Save the updated results list to the database.
// IDB write is optional caching — quota failures must not discard the API result.
if (log_lvl) {
console.log('Saving to DB...');
}
try {
await db_save_ae_obj_li__ae_obj({
db_instance: db_journals,
table_name: 'journal_entry',
obj_li: processed_obj_li,
properties_to_save: properties_to_save,
log_lvl: log_lvl
});
if (log_lvl) {
console.log('DB save completed.');
}
} catch (save_error) {
console.warn('IDB cache write failed for journal_entry (quota?):', save_error);
}
}
return journal_entry_obj_li_get_result;
} else {
return [];
}
})
.catch(function (error: any) {
console.log('No results returned or failed.', error);
});
if (log_lvl) {
console.log(
'ae_promises.load__journal_entry_obj_li:',
ae_promises.load__journal_entry_obj_li
);
}
return ae_promises.load__journal_entry_obj_li;
}
// Updated 2026-01-05
export async function create_ae_obj__journal_entry({
api_cfg,
journal_id,
data_kv,
params = {},
try_cache = true,
log_lvl = 0
}: {
api_cfg: any;
journal_id: string;
data_kv: key_val;
params?: key_val;
try_cache?: boolean;
log_lvl?: number;
}): Promise<ae_JournalEntry | null> {
if (log_lvl) {
console.log(
`*** create_ae_obj__journal_entry() *** journal_id=${journal_id}`
);
}
if (!journal_id) {
console.log(`ERROR: Journals - Entry - journal_id required to create`);
return null;
}
ae_promises.create__journal_entry = await api
.create_nested_obj({
api_cfg: api_cfg,
parent_type: 'journal',
parent_id: journal_id,
child_type: 'journal_entry',
fields: data_kv,
params: params,
log_lvl: log_lvl
})
.then(async function (journal_entry_obj_create_result) {
if (journal_entry_obj_create_result) {
if (try_cache) {
// Process the results first
const processed_obj_li =
await process_ae_obj__journal_entry_props({
obj_li: [journal_entry_obj_create_result],
journal_id,
log_lvl: log_lvl
});
if (log_lvl) {
console.log('Processed object list:', processed_obj_li);
}
// IDB write is optional caching — quota failures must not discard the API result.
try {
await db_save_ae_obj_li__ae_obj({
db_instance: db_journals,
table_name: 'journal_entry',
obj_li: processed_obj_li,
properties_to_save: properties_to_save,
log_lvl: log_lvl
});
} catch (save_error) {
console.warn('IDB cache write failed for journal_entry (quota?):', save_error);
}
}
return journal_entry_obj_create_result;
} else {
return null;
}
})
.catch(function (error: any) {
console.log('No results returned or failed.', error);
});
return ae_promises.create__journal_entry;
}
// Updated 2026-01-05
export async function delete_ae_obj_id__journal_entry({
api_cfg,
journal_entry_id,
method = 'delete', // 'delete', 'disable', 'hide'
params = {},
try_cache = true,
log_lvl = 0
}: {
api_cfg: any;
journal_entry_id: string;
method?: 'delete' | 'soft_delete' | 'disable' | 'hide';
params?: key_val;
try_cache?: boolean;
log_lvl?: number;
}) {
if (log_lvl) {
console.log(
`*** delete_ae_obj_id__journal_entry() *** journal_entry_id=${journal_entry_id}`
);
}
ae_promises.delete__journal_entry_obj = await api
.delete_ae_obj({
api_cfg: api_cfg,
obj_type: 'journal_entry',
obj_id: journal_entry_id,
method: method,
params: params,
log_lvl: log_lvl
})
.catch(function (error: any) {
console.log('No results returned or failed.', error);
})
.finally(function () {
if (try_cache) {
if (log_lvl) {
console.log(
`Attempting to remove IDB entry for journal_entry_id=${journal_entry_id}`
);
}
db_journals.journal_entry.delete(journal_entry_id); // Delete from the DB no matter what.
}
});
return ae_promises.delete__journal_entry_obj;
}
// This new function is using CRUD V3 Search.
// Updated 2026-01-27
export async function qry__journal_entry({
api_cfg,
journal_id,
person_id = null,
qry_str = null, // Example: 'name:contains:"test"'
qry_category_code = null,
qry_created_on = null, // Example greater than: '2024-10-24'
qry_alert = null,
qry_priority = null,
enabled = 'enabled',
hidden = 'not_hidden',
limit = 50,
offset = 0,
order_by_li = {
group: 'DESC',
priority: 'DESC',
sort: 'DESC',
alert: 'DESC',
name: 'ASC',
updated_on: 'DESC',
created_on: 'DESC'
},
params = {},
try_cache = true,
log_lvl = 0
}: {
api_cfg: any;
journal_id: any;
person_id?: string | null;
qry_str?: null | string;
qry_category_code?: null | string;
qry_created_on?: null | string;
qry_alert?: null | string;
qry_priority?: null | number;
enabled?: 'enabled' | 'all' | 'not_enabled' | undefined;
hidden?: 'hidden' | 'all' | 'not_hidden' | undefined;
limit?: number;
offset?: number;
order_by_li?: key_val;
params?: any;
try_cache?: boolean;
log_lvl?: number;
}) {
if (log_lvl) {
console.log(
`*** qry__journal_entry() *** journal_id=${journal_id} person_id=${person_id}`
);
}
const search_query: any = { and: [] };
if (qry_str) {
// Using 'like' with wildcards to ensure compatibility
search_query.and.push({
field: 'default_qry_str',
op: 'like',
value: `%${qry_str.trim()}%`
});
params['lk_qry'] = { default_qry_str: qry_str.trim() };
}
if (qry_category_code) {
search_query.and.push({
field: 'category_code',
op: 'eq',
value: qry_category_code
});
}
if (qry_created_on) {
search_query.and.push({
field: 'created_on',
op: 'gt',
value: qry_created_on
});
}
if (qry_priority) {
search_query.and.push({
field: 'priority',
op: 'eq',
value: qry_priority
});
}
// Context scoping: Prefer journal_id if provided, otherwise fallback to person_id (global search)
if (journal_id) {
search_query.and.push({
field: 'journal_id',
op: 'eq',
value: journal_id
});
} else if (person_id) {
search_query.and.push({
field: 'person_id',
op: 'eq',
value: person_id
});
} else {
console.warn(
'qry__journal_entry: No journal_id or person_id provided. Search might be too broad.'
);
}
// Add enabled/hidden filters
if (enabled === 'enabled') {
search_query.and.push({ field: 'enable', op: 'eq', value: true });
} else if (enabled === 'not_enabled') {
search_query.and.push({ field: 'enable', op: 'eq', value: false });
}
if (hidden === 'hidden') {
search_query.and.push({ field: 'hide', op: 'eq', value: true });
} else if (hidden === 'not_hidden') {
search_query.and.push({ field: 'hide', op: 'eq', value: false });
}
ae_promises.load__journal_entry_obj_li = await api
.search_ae_obj({
api_cfg: api_cfg,
obj_type: 'journal_entry',
search_query,
order_by_li,
limit,
offset,
params,
log_lvl
})
.then(async function (journal_entry_obj_li_get_result) {
// Handle V3 API envelope { data: [], meta: ... } or direct array
let valid_result_li: ae_JournalEntry[] = [];
if (Array.isArray(journal_entry_obj_li_get_result)) {
valid_result_li = journal_entry_obj_li_get_result;
} else if (
journal_entry_obj_li_get_result &&
typeof journal_entry_obj_li_get_result === 'object' &&
Array.isArray((journal_entry_obj_li_get_result as any).data)
) {
valid_result_li = (journal_entry_obj_li_get_result as any).data;
}
if (valid_result_li && valid_result_li.length > 0) {
if (try_cache) {
const processed_obj_li =
await process_ae_obj__journal_entry_props({
obj_li: valid_result_li,
journal_id,
log_lvl
});
// IDB write is optional caching — quota failures must not discard the API result.
try {
await db_save_ae_obj_li__ae_obj({
db_instance: db_journals,
table_name: 'journal_entry',
obj_li: processed_obj_li,
properties_to_save,
log_lvl
});
} catch (save_error) {
console.warn('IDB cache write failed for journal_entry (quota?):', save_error);
}
}
return valid_result_li;
} else {
return [];
}
});
if (log_lvl) {
console.log(
'ae_promises.load__journal_entry_obj_li:',
ae_promises.load__journal_entry_obj_li
);
}
return ae_promises.load__journal_entry_obj_li;
}
// Updated 2025-03-15
// export async function update_ae_obj__journal_entry(
// {
// api_cfg,
// journal_entry_id,
// data_kv,
// params = {},
// try_cache = true,
// log_lvl = 0
// }: {
// api_cfg: any,
// journal_entry_id: string,
// data_kv: key_val,
// params?: key_val,
// try_cache?: boolean,
// log_lvl?: number
// }
// ) {
// if (log_lvl) {
// console.log(`*** update_ae_obj__journal_entry() *** journal_entry_id=${journal_entry_id}`, data_kv);
// }
// ae_promises.update__journal_entry_obj = api.update_ae_obj_id_crud({
// api_cfg: api_cfg,
// obj_type: 'journal_entry',
// obj_id: journal_entry_id,
// fields: data_kv,
// key: api_cfg.api_crud_super_key,
// params: params,
// return_obj: true,
// log_lvl: log_lvl
// })
// .then(async function (journal_entry_obj_update_result) {
// // if (journal_entry_obj_update_result) {
// if (try_cache) {
// db_save_ae_obj_li__journal_entry({
// obj_type: 'journal_entry',
// obj_li: [journal_entry_obj_update_result],
// log_lvl: log_lvl
// })
// .then(function (result) {
// return result;
// })
// .finally(function () {
// return journal_entry_obj_update_result;
// });
// } else {
// return journal_entry_obj_update_result;
// }
// // } else {
// // return null;
// // }
// })
// .catch(function (error: any) {
// console.log('No results returned or failed.', error);
// })
// .finally(function () {
// });
// if (log_lvl) {
// console.log('ae_promises.update__journal_entry_obj:', ae_promises.update__journal_entry_obj);
// }
// return await ae_promises.update__journal_entry_obj;
// }
// Updated 2026-01-05
export async function update_ae_obj__journal_entry({
api_cfg,
journal_entry_id,
data_kv,
params = {},
try_cache = true,
log_lvl = 0
}: {
api_cfg: any;
journal_entry_id: string;
data_kv: key_val;
params?: key_val;
try_cache?: boolean;
log_lvl?: number;
}): Promise<ae_JournalEntry | null> {
if (log_lvl) {
console.log(
`*** update_ae_obj__journal_entry() *** journal_entry_id=${journal_entry_id}`,
data_kv
);
}
// Perform the API update
const result = await api.update_ae_obj({
api_cfg: api_cfg,
obj_type: 'journal_entry',
obj_id: journal_entry_id,
fields: data_kv,
params: params,
log_lvl: log_lvl
});
// Handle the result
if (result) {
if (try_cache) {
// Process the results first
const processed_obj_li = await process_ae_obj__journal_entry_props({
obj_li: [result],
log_lvl: log_lvl
});
if (log_lvl) {
console.log('Processed object list:', processed_obj_li);
}
// IDB write is optional caching — quota failures must not discard the API result.
try {
await db_save_ae_obj_li__ae_obj({
db_instance: db_journals,
table_name: 'journal_entry',
obj_li: processed_obj_li,
properties_to_save: properties_to_save,
log_lvl: log_lvl
});
} catch (save_error) {
console.warn('IDB cache write failed for journal_entry (quota?):', save_error);
}
}
return result;
} else {
console.error('Failed to update journal entry.');
return null;
}
}
// // This function will loop through the journal_entry_obj_li and save each one to the DB.
// // Updated 2025-05-09
// export async function db_save_ae_obj_li__journal_entry({
// obj_type,
// obj_li,
// log_lvl = 0
// }: {
// obj_type: string;
// obj_li: any;
// log_lvl?: number;
// }) {
// // log_lvl = 1;
// if (log_lvl) {
// console.log(`*** db_save_ae_obj_li__journal_entry() *** obj_type=${obj_type}`, obj_li);
// }
// if (obj_li && obj_li.length) {
// // let obj_li_id = obj_li.map((obj: any) => obj.journal_entry_id);
// const obj_li_id: string[] = [];
// for (const obj of obj_li) {
// // obj_li.forEach(async function (obj: any) {
// if (log_lvl) {
// console.log(`Processing ae_obj ${obj_type}:`, obj);
// }
// let content = obj.content ?? '';
// // remove the most common zerowidth characters from the start of the file
// let content_cleaned: null | string = null;
// let content_md_html: null | string = null; // await marked.parse(content_cleaned ?? '') ?? null;
// // let content_md_html_alt: null|string = await marked.parse(content_cleaned ?? '', { gfm: false }) ?? null;
// if (obj.content_encrypted) {
// // In theory "content" should be null if "content_encrypted" has a value.
// content = null; // obj.content_encrypted;
// content_cleaned = null;
// content_md_html = null;
// } else {
// content_cleaned = content.replace(/^[\u200B\u200C\u200D\u200E\u200F\uFEFF]/, '');
// content_md_html = (await marked.parse(content_cleaned ?? '')) ?? null;
// }
// let history = obj.history ?? '';
// let history_cleaned: null | string = null;
// let history_md_html: null | string = null; // await marked.parse(history_cleaned ?? '') ?? null;
// if (obj.history_encrypted) {
// // In theory "history" should be null if "history_encrypted" has a value.
// history = null; // obj.history_encrypted;
// history_cleaned = null;
// history_md_html = null;
// } else {
// history_cleaned = history.replace(/^[\u200B\u200C\u200D\u200E\u200F\uFEFF]/, '');
// history_md_html = (await marked.parse(history_cleaned ?? '')) ?? null;
// }
// const obj_record = {
// id: obj.journal_entry_id,
// journal_entry_id: obj.journal_entry_id,
// journal_id: obj.journal_id,
// code: obj.code,
// for_type: obj.for_type,
// for_id: obj.for_id,
// journal_entry_type: obj.journal_entry_type,
// person_id: obj.person_id,
// template: obj.template ?? null, // Allow for a template to be used, otherwise null
// activity_code: obj.activity_code,
// category_code: obj.category_code,
// type_code: obj.type_code,
// topic_code: obj.topic_code,
// tags: obj.tags,
// public: obj.public,
// private: obj.private,
// personal: obj.personal,
// professional: obj.professional,
// name: obj.name,
// short_name: obj.short_name ?? null,
// summary: obj.summary,
// outline: obj.outline,
// // description: obj.description,
// content: obj.content,
// content_md_html: content_md_html ?? undefined,
// // content_md_html_alt: content_md_html_alt,
// content_html: obj.content_html,
// content_json: obj.content_json,
// content_encrypted: obj.content_encrypted,
// history: obj.history,
// history_md_html: history_md_html ?? undefined,
// history_encrypted: obj.history_encrypted,
// passcode_hash: obj.passcode_hash,
// // url: obj.url,
// // url_text: obj.url_text,
// // hosted_file_id: obj.hosted_file_id,
// // file_path: obj.file_path,
// // filename: obj.filename,
// // file_extension: obj.file_extension,
// // start_datetime: obj.start_datetime,
// // end_datetime: obj.end_datetime,
// // timezone: obj.timezone,
// // original_datetime: obj.original_datetime,
// // original_timezone: obj.original_timezone,
// // original_location: obj.original_location,
// // original_url: obj.original_url,
// // original_url_text: obj.original_url_text,
// // enable_for_public: obj.enable_for_public,
// alert: obj.alert,
// alert_msg: obj.alert_msg,
// // cfg_json: obj.cfg_json ?? {},
// data_json: obj.data_json ?? {},
// // This only allows for basic access to the data.
// // passcode_read: obj.passcode_read, // For LLM (AI) generated summary...???
// // passcode_read_expire: obj.passcode_read_expire,
// // passcode_write: obj.passcode_write,
// // passcode_write_expire: obj.passcode_write_expire,
// enable: obj.enable,
// hide: obj.hide,
// archive: obj.archive,
// archive_on: obj.archive_on,
// priority: obj.priority,
// sort: obj.sort,
// group: obj.group,
// notes: obj.notes,
// created_on: obj.created_on,
// updated_on: obj.updated_on,
// // Generated fields for sorting locally only
// tmp_sort_1: `${obj.group}_${obj.priority}_${obj.sort}_${obj.updated_on}_${obj.created_on}`,
// tmp_sort_2: `${obj.group}_${obj.priority}_${obj.sort}_${obj.updated_on ?? obj.created_on}`,
// // tmp_sort_1: `${obj.original_datetime}_${obj.group}_${obj.priority}_${obj.sort}`,
// // tmp_sort_2: `${obj.group}_${obj.original_datetime}_${obj.priority}_${obj.sort}`,
// // Generated fields for sorting locally only
// // tmp_sort_1: `${obj.original_datetime}_${obj.group}_${obj.priority}_${obj.sort}`,
// // tmp_sort_2: `${obj.group}_${obj.original_datetime}_${obj.priority}_${obj.sort}`,
// // From SQL view
// journal_code: obj.journal_code,
// journal_name: obj.journal_name
// // A key value list of the others
// // journal_other_kv: obj.journal_other_kv,
// // journal_other_li: obj.journal_other_li,
// };
// let id_random = null;
// try {
// id_random = await db_journals.journal_entry.update(obj_record.id, obj_record);
// } catch (error) {
// console.log(`Error: Failed to update ${obj_record.id}: ${error}`);
// }
// if (!id_random) {
// if (log_lvl) {
// console.log(`Failed to update record with ID: ${obj_record.id}. Trying put...`);
// }
// try {
// id_random = await db_journals.journal_entry.put(obj_record);
// } catch (error) {
// console.log(`Error: Failed to put ${obj.journal_entry_id}: ${error}`);
// }
// } else {
// if (log_lvl) {
// console.log(`Updated record with ID: ${obj_record.id}`);
// }
// obj_li_id.push(obj_record.id);
// }
// if (!id_random) {
// console.log(`Failed to save record with ID: ${obj_record.id}`);
// } else {
// if (log_lvl) {
// console.log(`Saved record with ID: ${obj_record.id}`);
// }
// }
// // });
// }
// return obj_li_id;
// } else {
// if (log_lvl) {
// console.log('No objects to save.');
// }
// return [];
// }
// }
// Updated 2025-05-09
const properties_to_save = [
'id',
'journal_entry_id',
'journal_id',
'code',
'for_type',
'for_id',
'journal_entry_type',
'person_id',
'template', // Allow for a template to be used, otherwise null
'activity_code',
'category_code',
'type_code',
'topic_code',
'tags',
'public',
'private',
'personal',
'professional',
'name',
'short_name',
'summary',
'outline',
// 'description',
'content',
// content_md_html is computed from content on every load — not stored to save IDB quota
'content_html',
'content_json',
'content_encrypted',
'history',
// history_md_html is computed from history on every load — not stored to save IDB quota
'history_encrypted',
'passcode_hash',
'alert',
'alert_msg',
// 'cfg_json',
'data_json',
'enable',
'hide',
'archive',
'archive_on',
'priority',
'sort',
'group',
'notes',
'created_on',
'updated_on',
// Generated fields for sorting locally only
'tmp_sort_1',
'tmp_sort_2',
'tmp_sort_3',
// 'tmp_sort_a',
// 'tmp_sort_b',
// From SQL view
'journal_code',
'journal_name'
// A key value list of the others
// 'journal_other_kv',
// 'journal_other_li',
];
/**
* NON-EXPORTED LOCAL HELPER
* Processes a list of Aether objects by applying common and specific transformations.
*/
async function _process_generic_props<T extends Record<string, any>>({
obj_li,
obj_type,
log_lvl = 0,
specific_processor
}: {
obj_li: T[];
obj_type: string;
log_lvl?: number;
specific_processor?: (obj: T) => Promise<T> | T;
}): Promise<T[]> {
if (log_lvl > 0) {
console.log(
`*** _process_generic_props: Processing ${obj_li.length} objects of type "${obj_type}" ***`
);
}
if (!obj_li || obj_li.length === 0) {
if (log_lvl > 0) console.log('No objects to process.');
return [];
}
const processed_obj_li: T[] = [];
for (const original_obj of obj_li) {
let processed_obj = { ...original_obj };
// --- Common Transformations ---
// 1. Standardize ID and other '_random' fields
for (const key in processed_obj) {
if (key.endsWith('_random')) {
const newKey = key.slice(0, -7); // Remove '_random' suffix
(processed_obj as any)[newKey] = processed_obj[key];
}
}
// Ensure 'id' is set from '[obj_type]_id_random'
const randomIdKey = `${obj_type}_id`;
if (processed_obj[randomIdKey]) {
(processed_obj as any).id = processed_obj[randomIdKey];
}
// 2. Create common computed properties for client-side sorting.
const group = processed_obj.group ?? '0';
const priority = processed_obj.priority ? 1 : 0;
const sort = processed_obj.sort ?? '0';
const updated =
processed_obj.updated_on ??
processed_obj.created_on ??
new Date(0).toISOString();
const name = processed_obj.name ?? '';
(processed_obj as any).tmp_sort_1 =
`${group}_${priority}_${sort}_${updated}`;
(processed_obj as any).tmp_sort_2 =
`${group}_${priority}_${sort}_${name}_${updated}`;
// --- Specific Transformations ---
if (specific_processor) {
processed_obj = await Promise.resolve(
specific_processor(processed_obj)
);
}
processed_obj_li.push(processed_obj as T);
}
return processed_obj_li;
}
// Updated 2025-05-09
export async function process_ae_obj__journal_entry_props({
obj_li,
journal_id,
log_lvl = 0
}: {
obj_li: any[];
journal_id?: string;
log_lvl?: number;
}) {
return _process_generic_props({
obj_li,
obj_type: 'journal_entry',
log_lvl,
specific_processor: async (obj) => {
// Inject journal_id if provided and missing
if (journal_id) {
if (!obj.journal_id) obj.journal_id = journal_id;
// if (!obj.journal_id_random) obj.journal_id_random = journal_id;
}
// Content processing
let content = obj.content ?? '';
let content_cleaned: null | string = null;
let content_md_html: null | string = null;
if (obj.content_encrypted) {
content = null;
content_cleaned = null;
content_md_html = null;
} else {
content_cleaned = content.replace(
/^[\u200B\u200C\u200D\u200E\u200F\uFEFF]/,
''
);
content_md_html =
(await marked.parse(content_cleaned ?? '')) ?? null;
}
obj.content = content;
obj.content_md_html = content_md_html;
// History processing
let history = obj.history ?? '';
let history_cleaned: null | string = null;
let history_md_html: null | string = null;
if (obj.history_encrypted) {
history = null;
history_cleaned = null;
history_md_html = null;
} else {
history_cleaned = history.replace(
/^[\u200B\u200C\u200D\u200E\u200F\uFEFF]/,
''
);
history_md_html =
(await marked.parse(history_cleaned ?? '')) ?? null;
}
obj.history = history;
obj.history_md_html = history_md_html;
// Journal entry-specific computed sort fields via build_tmp_sort.
// Order: priority DESC → sort ASC → name ASC → updated ASC (all ascending, no .reverse())
const updated =
obj.updated_on ?? obj.created_on ?? new Date(0).toISOString();
const { tmp_sort_1, tmp_sort_2, tmp_sort_3 } = build_tmp_sort({
prefix: [obj.group ?? ''],
priority: obj.priority,
sort: obj.sort,
fields_2: [obj.name],
fields_3: [updated]
});
obj.tmp_sort_1 = tmp_sort_1;
obj.tmp_sort_2 = tmp_sort_2;
obj.tmp_sort_3 = tmp_sort_3;
return obj;
}
});
}