@framers/sql-storage-adapter 0.7.3 → 0.7.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/README.md +45 -13
  2. package/dist/cjs/core/contracts/features.js +4 -2
  3. package/dist/cjs/core/contracts/fts.d.ts +20 -8
  4. package/dist/cjs/core/portable.d.ts +2 -0
  5. package/dist/cjs/core/portable.js +5 -0
  6. package/dist/cjs/features/auth/authJsAdapter.d.ts +110 -0
  7. package/dist/cjs/features/auth/authJsAdapter.js +251 -0
  8. package/dist/cjs/fts/PostgresFts.d.ts +14 -13
  9. package/dist/cjs/fts/PostgresFts.js +61 -33
  10. package/dist/cjs/fts/SqliteFts4.d.ts +28 -0
  11. package/dist/cjs/fts/SqliteFts4.js +67 -0
  12. package/dist/cjs/fts/SqliteFts5.d.ts +1 -0
  13. package/dist/cjs/fts/SqliteFts5.js +3 -0
  14. package/dist/cjs/index.d.ts +2 -0
  15. package/dist/cjs/index.js +5 -0
  16. package/dist/core/contracts/features.d.ts.map +1 -1
  17. package/dist/core/contracts/features.js +6 -2
  18. package/dist/core/contracts/features.js.map +1 -1
  19. package/dist/core/contracts/fts.d.ts +20 -8
  20. package/dist/core/contracts/fts.d.ts.map +1 -1
  21. package/dist/core/portable.d.ts +2 -0
  22. package/dist/core/portable.d.ts.map +1 -1
  23. package/dist/core/portable.js +2 -0
  24. package/dist/core/portable.js.map +1 -1
  25. package/dist/features/auth/authJsAdapter.d.ts +110 -0
  26. package/dist/features/auth/authJsAdapter.d.ts.map +1 -0
  27. package/dist/features/auth/authJsAdapter.js +248 -0
  28. package/dist/features/auth/authJsAdapter.js.map +1 -0
  29. package/dist/fts/PostgresFts.d.ts +14 -13
  30. package/dist/fts/PostgresFts.d.ts.map +1 -1
  31. package/dist/fts/PostgresFts.js +83 -39
  32. package/dist/fts/PostgresFts.js.map +1 -1
  33. package/dist/fts/SqliteFts4.d.ts +28 -0
  34. package/dist/fts/SqliteFts4.d.ts.map +1 -0
  35. package/dist/fts/SqliteFts4.js +56 -0
  36. package/dist/fts/SqliteFts4.js.map +1 -0
  37. package/dist/fts/SqliteFts5.d.ts +1 -0
  38. package/dist/fts/SqliteFts5.d.ts.map +1 -1
  39. package/dist/fts/SqliteFts5.js +3 -0
  40. package/dist/fts/SqliteFts5.js.map +1 -1
  41. package/dist/index.d.ts +2 -0
  42. package/dist/index.d.ts.map +1 -1
  43. package/dist/index.js +2 -0
  44. package/dist/index.js.map +1 -1
  45. package/package.json +11 -1
@@ -0,0 +1,248 @@
1
+ import { createStorageFeatures } from '../../core/contracts/features.js';
2
+ const PREFIX = /^[A-Za-z_][A-Za-z0-9_]*$/;
3
+ const tablesFor = (options) => {
4
+ const prefix = options.tablePrefix ?? 'auth_';
5
+ if (!PREFIX.test(prefix)) {
6
+ throw new Error(`tablePrefix must be letters, digits and underscores, starting with a letter or an underscore; got ${JSON.stringify(prefix)}.`);
7
+ }
8
+ return {
9
+ users: `${prefix}users`,
10
+ accounts: `${prefix}accounts`,
11
+ sessions: `${prefix}sessions`,
12
+ verificationTokens: `${prefix}verification_tokens`,
13
+ };
14
+ };
15
+ /**
16
+ * The statements that create the adapter's tables and indexes on `db`'s
17
+ * engine, each `IF NOT EXISTS`, for a migration file or for
18
+ * ensureAuthJsTables.
19
+ */
20
+ export function authJsTablesSql(db, options = {}) {
21
+ const t = tablesFor(options);
22
+ const d = createStorageFeatures(db).dialect;
23
+ const timestamp = d.columnType('timestamp');
24
+ return [
25
+ `CREATE TABLE IF NOT EXISTS ${t.users} (id TEXT PRIMARY KEY, name TEXT, email TEXT UNIQUE, email_verified ${timestamp}, image TEXT)`,
26
+ `CREATE TABLE IF NOT EXISTS ${t.accounts} (
27
+ id TEXT PRIMARY KEY,
28
+ user_id TEXT NOT NULL REFERENCES ${t.users} (id) ON DELETE CASCADE,
29
+ type TEXT NOT NULL,
30
+ provider TEXT NOT NULL,
31
+ provider_account_id TEXT NOT NULL,
32
+ refresh_token TEXT,
33
+ access_token TEXT,
34
+ expires_at ${d.columnType('bigint')},
35
+ token_type TEXT,
36
+ scope TEXT,
37
+ id_token TEXT,
38
+ session_state TEXT,
39
+ UNIQUE (provider, provider_account_id)
40
+ )`,
41
+ `CREATE TABLE IF NOT EXISTS ${t.sessions} (session_token TEXT PRIMARY KEY, user_id TEXT NOT NULL REFERENCES ${t.users} (id) ON DELETE CASCADE, expires ${timestamp} NOT NULL)`,
42
+ `CREATE TABLE IF NOT EXISTS ${t.verificationTokens} (identifier TEXT NOT NULL, token TEXT NOT NULL, expires ${timestamp} NOT NULL, PRIMARY KEY (identifier, token))`,
43
+ `CREATE INDEX IF NOT EXISTS ${t.accounts}_user_id ON ${t.accounts} (user_id)`,
44
+ `CREATE INDEX IF NOT EXISTS ${t.sessions}_user_id ON ${t.sessions} (user_id)`,
45
+ ];
46
+ }
47
+ /** Creates the adapter's tables and indexes on `db` when they are missing. */
48
+ export async function ensureAuthJsTables(db, options = {}) {
49
+ for (const statement of authJsTablesSql(db, options)) {
50
+ await db.exec(statement);
51
+ }
52
+ }
53
+ /** A stored time as a Date: PostgreSQL returns one, SQLite ISO 8601 text. */
54
+ const toDate = (value) => value == null ? null : value instanceof Date ? value : new Date(String(value));
55
+ const toUser = (row) => ({
56
+ id: String(row.id),
57
+ name: row.name ?? null,
58
+ email: row.email,
59
+ emailVerified: toDate(row.email_verified),
60
+ image: row.image ?? null,
61
+ });
62
+ const toAccount = (row) => {
63
+ const account = {
64
+ userId: String(row.user_id),
65
+ type: row.type,
66
+ provider: row.provider,
67
+ providerAccountId: row.provider_account_id,
68
+ };
69
+ for (const field of ['refresh_token', 'access_token', 'token_type', 'scope', 'id_token', 'session_state']) {
70
+ if (row[field] != null)
71
+ account[field] = String(row[field]);
72
+ }
73
+ // PostgreSQL returns a BIGINT as text.
74
+ if (row.expires_at != null)
75
+ account.expires_at = Number(row.expires_at);
76
+ return account;
77
+ };
78
+ const toSession = (row) => ({
79
+ sessionToken: row.session_token,
80
+ userId: String(row.user_id),
81
+ expires: toDate(row.expires),
82
+ });
83
+ const toVerificationToken = (row) => ({
84
+ identifier: row.identifier,
85
+ token: row.token,
86
+ expires: toDate(row.expires),
87
+ });
88
+ const defaultId = () => {
89
+ const random = globalThis.crypto?.randomUUID;
90
+ if (!random)
91
+ throw new Error('crypto.randomUUID() is not available; pass generateId.');
92
+ return random.call(globalThis.crypto);
93
+ };
94
+ /**
95
+ * An Auth.js database adapter that keeps users, accounts, sessions and
96
+ * verification tokens in `db`, on PostgreSQL or SQLite. Create the tables
97
+ * first with ensureAuthJsTables (or authJsTablesSql in a migration).
98
+ *
99
+ * @example
100
+ * ```typescript
101
+ * import NextAuth from 'next-auth';
102
+ * import { createDatabase } from '@framers/sql-storage-adapter';
103
+ * import { createAuthJsAdapter, ensureAuthJsTables } from '@framers/sql-storage-adapter/authjs';
104
+ *
105
+ * const db = await createDatabase({ url: process.env.DATABASE_URL, strict: true });
106
+ * await ensureAuthJsTables(db);
107
+ * export const { handlers, auth } = NextAuth({ adapter: createAuthJsAdapter(db), providers: [] });
108
+ * ```
109
+ */
110
+ export function createAuthJsAdapter(db, options = {}) {
111
+ const t = tablesFor(options);
112
+ const generateId = options.generateId ?? defaultId;
113
+ const getUser = async (id) => {
114
+ const row = await db.get(`SELECT * FROM ${t.users} WHERE id = ?`, [id]);
115
+ return row ? toUser(row) : null;
116
+ };
117
+ const getSession = async (sessionToken) => {
118
+ const row = await db.get(`SELECT * FROM ${t.sessions} WHERE session_token = ?`, [sessionToken]);
119
+ return row ? toSession(row) : null;
120
+ };
121
+ return {
122
+ async createUser(user) {
123
+ const id = user.id ?? generateId();
124
+ await db.run(`INSERT INTO ${t.users} (id, name, email, email_verified, image) VALUES (?, ?, ?, ?, ?)`, [
125
+ id,
126
+ user.name ?? null,
127
+ user.email,
128
+ user.emailVerified ?? null,
129
+ user.image ?? null,
130
+ ]);
131
+ return (await getUser(id));
132
+ },
133
+ getUser,
134
+ async getUserByEmail(email) {
135
+ const row = await db.get(`SELECT * FROM ${t.users} WHERE email = ?`, [email]);
136
+ return row ? toUser(row) : null;
137
+ },
138
+ async getUserByAccount({ provider, providerAccountId }) {
139
+ const row = await db.get(`SELECT u.* FROM ${t.users} u JOIN ${t.accounts} a ON a.user_id = u.id WHERE a.provider = ? AND a.provider_account_id = ?`, [provider, providerAccountId]);
140
+ return row ? toUser(row) : null;
141
+ },
142
+ async updateUser(user) {
143
+ const fields = [];
144
+ if ('name' in user)
145
+ fields.push(['name', user.name ?? null]);
146
+ if ('email' in user)
147
+ fields.push(['email', user.email]);
148
+ if ('emailVerified' in user)
149
+ fields.push(['email_verified', user.emailVerified ?? null]);
150
+ if ('image' in user)
151
+ fields.push(['image', user.image ?? null]);
152
+ if (fields.length) {
153
+ await db.run(`UPDATE ${t.users} SET ${fields.map(([column]) => `${column} = ?`).join(', ')} WHERE id = ?`, [
154
+ ...fields.map(([, value]) => value),
155
+ user.id,
156
+ ]);
157
+ }
158
+ const updated = await getUser(user.id);
159
+ if (!updated)
160
+ throw new Error(`No user with id ${JSON.stringify(user.id)} to update.`);
161
+ return updated;
162
+ },
163
+ async deleteUser(userId) {
164
+ // Explicit deletes: sql.js and IndexedDB leave foreign keys off, so ON DELETE CASCADE would not run there.
165
+ return db.transaction(async (trx) => {
166
+ const row = await trx.get(`SELECT * FROM ${t.users} WHERE id = ?`, [userId]);
167
+ await trx.run(`DELETE FROM ${t.sessions} WHERE user_id = ?`, [userId]);
168
+ await trx.run(`DELETE FROM ${t.accounts} WHERE user_id = ?`, [userId]);
169
+ await trx.run(`DELETE FROM ${t.users} WHERE id = ?`, [userId]);
170
+ return row ? toUser(row) : null;
171
+ });
172
+ },
173
+ async linkAccount(account) {
174
+ await db.run(`INSERT INTO ${t.accounts} (id, user_id, type, provider, provider_account_id, refresh_token, access_token, expires_at, token_type, scope, id_token, session_state)
175
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, [
176
+ generateId(),
177
+ account.userId,
178
+ account.type,
179
+ account.provider,
180
+ account.providerAccountId,
181
+ account.refresh_token ?? null,
182
+ account.access_token ?? null,
183
+ account.expires_at ?? null,
184
+ account.token_type ?? null,
185
+ account.scope ?? null,
186
+ account.id_token ?? null,
187
+ account.session_state ?? null,
188
+ ]);
189
+ return account;
190
+ },
191
+ async unlinkAccount({ provider, providerAccountId }) {
192
+ await db.run(`DELETE FROM ${t.accounts} WHERE provider = ? AND provider_account_id = ?`, [provider, providerAccountId]);
193
+ },
194
+ async getAccount(providerAccountId, provider) {
195
+ const row = await db.get(`SELECT * FROM ${t.accounts} WHERE provider = ? AND provider_account_id = ?`, [
196
+ provider,
197
+ providerAccountId,
198
+ ]);
199
+ return row ? toAccount(row) : null;
200
+ },
201
+ async createSession(session) {
202
+ await db.run(`INSERT INTO ${t.sessions} (session_token, user_id, expires) VALUES (?, ?, ?)`, [
203
+ session.sessionToken,
204
+ session.userId,
205
+ session.expires,
206
+ ]);
207
+ return { sessionToken: session.sessionToken, userId: session.userId, expires: session.expires };
208
+ },
209
+ async getSessionAndUser(sessionToken) {
210
+ const session = await getSession(sessionToken);
211
+ if (!session)
212
+ return null;
213
+ const user = await getUser(session.userId);
214
+ return user ? { session, user } : null;
215
+ },
216
+ async updateSession(session) {
217
+ const fields = [];
218
+ if (session.expires !== undefined)
219
+ fields.push(['expires', session.expires]);
220
+ if (session.userId !== undefined)
221
+ fields.push(['user_id', session.userId]);
222
+ if (fields.length) {
223
+ await db.run(`UPDATE ${t.sessions} SET ${fields.map(([column]) => `${column} = ?`).join(', ')} WHERE session_token = ?`, [
224
+ ...fields.map(([, value]) => value),
225
+ session.sessionToken,
226
+ ]);
227
+ }
228
+ return getSession(session.sessionToken);
229
+ },
230
+ async deleteSession(sessionToken) {
231
+ await db.run(`DELETE FROM ${t.sessions} WHERE session_token = ?`, [sessionToken]);
232
+ },
233
+ async createVerificationToken(token) {
234
+ await db.run(`INSERT INTO ${t.verificationTokens} (identifier, token, expires) VALUES (?, ?, ?)`, [
235
+ token.identifier,
236
+ token.token,
237
+ token.expires,
238
+ ]);
239
+ return { identifier: token.identifier, token: token.token, expires: token.expires };
240
+ },
241
+ async useVerificationToken({ identifier, token }) {
242
+ // One statement: a token is used once, however many requests race for it.
243
+ const row = await db.get(`DELETE FROM ${t.verificationTokens} WHERE identifier = ? AND token = ? RETURNING identifier, token, expires`, [identifier, token]);
244
+ return row ? toVerificationToken(row) : null;
245
+ },
246
+ };
247
+ }
248
+ //# sourceMappingURL=authJsAdapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"authJsAdapter.js","sourceRoot":"","sources":["../../../src/features/auth/authJsAdapter.ts"],"names":[],"mappings":"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"}
@@ -1,29 +1,30 @@
1
1
  import type { IFullTextSearch } from '../core/contracts/fts.js';
2
+ type Weight = 'A' | 'B' | 'C' | 'D';
2
3
  /**
3
4
  * Postgres full-text search using tsvector columns and GIN indexes.
4
5
  *
5
- * Unlike FTS5 (separate virtual table), Postgres stores the tsvector
6
- * as a column `_tsv` on the content table itself. The `createIndex()`
7
- * call adds the column, creates the GIN index, and backfills existing rows.
6
+ * Unlike FTS5 (separate virtual table), Postgres stores the tsvector as a
7
+ * column `_tsv` on the content table itself. The `createIndex()` call adds the
8
+ * column, creates the GIN index, and backfills existing rows. Queries go
9
+ * through `websearch_to_tsquery`, which reads raw user text without syntax
10
+ * errors: words are ANDed, and `or`, `-word` and quoted phrases work as in a
11
+ * web search box.
8
12
  */
9
13
  export declare class PostgresFts implements IFullTextSearch {
10
- /** The content table is stored during createIndex for use by other methods. */
11
- private _contentTable;
12
- private _columns;
13
- private _lang;
14
14
  createIndex(config: {
15
15
  table: string;
16
16
  columns: string[];
17
17
  contentTable?: string;
18
18
  tokenizer?: string;
19
+ weights?: Record<string, Weight>;
19
20
  }): string;
20
- matchClause(_indexName: string, queryPlaceholder: string): string;
21
- rankExpression(_indexName: string, queryPlaceholder?: string): string;
22
- rebuildCommand(_indexName: string): string;
23
- syncInsert(_indexName: string, _rowIdExpr: string, columns: string[]): string;
21
+ matchClause(indexName: string, queryPlaceholder: string): string;
22
+ rankExpression(indexName: string, queryPlaceholder?: string): string;
23
+ relevanceOrder(indexName: string, queryPlaceholder?: string): string;
24
+ rebuildCommand(indexName: string): string;
25
+ syncInsert(indexName: string, _rowIdExpr: string, columns: string[]): string;
24
26
  sanitizeQuery(input: string): string;
25
27
  joinClause(contentTable: string, contentAlias: string, _ftsAlias: string, _indexName: string): string;
26
- /** Map FTS5-style tokenizer strings to Postgres text search configurations. */
27
- private _tokenizerToLang;
28
28
  }
29
+ export {};
29
30
  //# sourceMappingURL=PostgresFts.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"PostgresFts.d.ts","sourceRoot":"","sources":["../../src/fts/PostgresFts.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAEhE;;;;;;GAMG;AACH,qBAAa,WAAY,YAAW,eAAe;IACjD,+EAA+E;IAC/E,OAAO,CAAC,aAAa,CAAM;IAC3B,OAAO,CAAC,QAAQ,CAAgB;IAChC,OAAO,CAAC,KAAK,CAAa;IAE1B,WAAW,CAAC,MAAM,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,EAAE,CAAC;QAAC,YAAY,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,MAAM;IAe5G,WAAW,CAAC,UAAU,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,GAAG,MAAM;IAIjE,cAAc,CAAC,UAAU,EAAE,MAAM,EAAE,gBAAgB,CAAC,EAAE,MAAM,GAAG,MAAM;IAKrE,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM;IAM1C,UAAU,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,MAAM;IAQ7E,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM;IAIpC,UAAU,CAAC,YAAY,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM;IAIrG,+EAA+E;IAC/E,OAAO,CAAC,gBAAgB;CAKzB"}
1
+ {"version":3,"file":"PostgresFts.d.ts","sourceRoot":"","sources":["../../src/fts/PostgresFts.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAEhE,KAAK,MAAM,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC;AAoBpC;;;;;;;;;GASG;AACH,qBAAa,WAAY,YAAW,eAAe;IACjD,WAAW,CAAC,MAAM,EAAE;QAClB,KAAK,EAAE,MAAM,CAAC;QACd,OAAO,EAAE,MAAM,EAAE,CAAC;QAClB,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;KAClC,GAAG,MAAM;IAgBV,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,GAAG,MAAM;IAIhE,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,gBAAgB,CAAC,EAAE,MAAM,GAAG,MAAM;IAKpE,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,gBAAgB,CAAC,EAAE,MAAM,GAAG,MAAM;IAIpE,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM;IAKzC,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,MAAM;IAM5E,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM;IASpC,UAAU,CAAC,YAAY,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM;CAGtG"}
@@ -1,62 +1,106 @@
1
+ /**
2
+ * The indexes createIndex has described in this process, by index name. It
3
+ * is the module's, not an instance's, so a features object made later (or a
4
+ * second one) syncs, rebuilds and queries an index another one created, and
5
+ * each index keeps its own language.
6
+ */
7
+ const INDEXES = new Map();
8
+ const WEIGHTS = new Set(['A', 'B', 'C', 'D']);
1
9
  /**
2
10
  * Postgres full-text search using tsvector columns and GIN indexes.
3
11
  *
4
- * Unlike FTS5 (separate virtual table), Postgres stores the tsvector
5
- * as a column `_tsv` on the content table itself. The `createIndex()`
6
- * call adds the column, creates the GIN index, and backfills existing rows.
12
+ * Unlike FTS5 (separate virtual table), Postgres stores the tsvector as a
13
+ * column `_tsv` on the content table itself. The `createIndex()` call adds the
14
+ * column, creates the GIN index, and backfills existing rows. Queries go
15
+ * through `websearch_to_tsquery`, which reads raw user text without syntax
16
+ * errors: words are ANDed, and `or`, `-word` and quoted phrases work as in a
17
+ * web search box.
7
18
  */
8
19
  export class PostgresFts {
9
- constructor() {
10
- /** The content table is stored during createIndex for use by other methods. */
11
- this._contentTable = '';
12
- this._columns = [];
13
- this._lang = 'english';
14
- }
15
20
  createIndex(config) {
16
- const ct = config.contentTable ?? config.table;
17
- this._contentTable = ct;
18
- this._columns = config.columns;
19
- const colConcat = config.columns.map((c) => `COALESCE(${c}, '')`).join(" || ' ' || ");
20
- const lang = this._tokenizerToLang(config.tokenizer);
21
- this._lang = lang;
21
+ const index = {
22
+ contentTable: config.contentTable ?? config.table,
23
+ columns: config.columns,
24
+ lang: tokenizerToLang(config.tokenizer),
25
+ weights: checkWeights(config.columns, config.weights),
26
+ };
27
+ INDEXES.set(config.table, index);
28
+ const ct = index.contentTable;
22
29
  return [
23
30
  `ALTER TABLE ${ct} ADD COLUMN IF NOT EXISTS _tsv tsvector`,
24
31
  `CREATE INDEX IF NOT EXISTS idx_${config.table}_tsv ON ${ct} USING GIN(_tsv)`,
25
- `UPDATE ${ct} SET _tsv = to_tsvector('${lang}', ${colConcat}) WHERE _tsv IS NULL`,
32
+ `UPDATE ${ct} SET _tsv = ${tsvector(index, index.columns.map((column) => `COALESCE(${column}, '')`))} WHERE _tsv IS NULL`,
26
33
  ].join(';\n');
27
34
  }
28
- matchClause(_indexName, queryPlaceholder) {
29
- return `_tsv @@ plainto_tsquery('${this._lang}', ${queryPlaceholder})`;
35
+ matchClause(indexName, queryPlaceholder) {
36
+ return `_tsv @@ websearch_to_tsquery('${langOf(indexName)}', ${queryPlaceholder})`;
30
37
  }
31
- rankExpression(_indexName, queryPlaceholder) {
38
+ rankExpression(indexName, queryPlaceholder) {
32
39
  const qp = queryPlaceholder ?? '$1';
33
- return `ts_rank(_tsv, plainto_tsquery('${this._lang}', ${qp}))`;
40
+ return `ts_rank(_tsv, websearch_to_tsquery('${langOf(indexName)}', ${qp}))`;
41
+ }
42
+ relevanceOrder(indexName, queryPlaceholder) {
43
+ return `${this.rankExpression(indexName, queryPlaceholder)} DESC`;
34
44
  }
35
- rebuildCommand(_indexName) {
36
- const ct = this._contentTable;
37
- const colConcat = this._columns.map((c) => `COALESCE(${c}, '')`).join(" || ' ' || ");
38
- return `UPDATE ${ct} SET _tsv = to_tsvector('${this._lang}', ${colConcat})`;
45
+ rebuildCommand(indexName) {
46
+ const index = described(indexName);
47
+ return `UPDATE ${index.contentTable} SET _tsv = ${tsvector(index, index.columns.map((column) => `COALESCE(${column}, '')`))}`;
39
48
  }
40
- syncInsert(_indexName, _rowIdExpr, columns) {
41
- const ct = this._contentTable;
42
- const colConcat = columns
43
- .map((_, index) => `COALESCE($${index + 2}, '')`)
44
- .join(" || ' ' || ");
45
- return `UPDATE ${ct} SET _tsv = to_tsvector('${this._lang}', ${colConcat}) WHERE id = $1`;
49
+ syncInsert(indexName, _rowIdExpr, columns) {
50
+ const index = described(indexName);
51
+ const values = columns.map((_, i) => `COALESCE($${i + 2}, '')`);
52
+ return `UPDATE ${index.contentTable} SET _tsv = ${tsvector({ ...index, columns }, values)} WHERE id = $1`;
46
53
  }
47
54
  sanitizeQuery(input) {
48
- return input;
55
+ return input
56
+ .replace(/[*()":^~{}[\]\\-]/g, ' ')
57
+ .split(/\s+/)
58
+ .filter((word) => word.length > 0 && word.toLowerCase() !== 'or')
59
+ .map((word) => `"${word}"`)
60
+ .join(' or ');
49
61
  }
50
62
  joinClause(contentTable, contentAlias, _ftsAlias, _indexName) {
51
63
  return `${contentTable} ${contentAlias}`;
52
64
  }
53
- /** Map FTS5-style tokenizer strings to Postgres text search configurations. */
54
- _tokenizerToLang(tokenizer) {
55
- if (!tokenizer)
56
- return 'english';
57
- if (tokenizer.includes('porter'))
58
- return 'english';
59
- return 'simple';
60
- }
61
65
  }
66
+ /** Map FTS5-style tokenizer strings to Postgres text search configurations. */
67
+ const tokenizerToLang = (tokenizer) => {
68
+ if (!tokenizer)
69
+ return 'english';
70
+ if (tokenizer.includes('porter'))
71
+ return 'english';
72
+ return 'simple';
73
+ };
74
+ const checkWeights = (columns, weights) => {
75
+ if (!weights)
76
+ return undefined;
77
+ for (const [column, weight] of Object.entries(weights)) {
78
+ if (!columns.includes(column))
79
+ throw new Error(`weights names ${JSON.stringify(column)}, which is not one of the indexed columns.`);
80
+ if (!WEIGHTS.has(weight))
81
+ throw new Error(`The weight of ${column} must be 'A', 'B', 'C' or 'D'; got ${JSON.stringify(weight)}.`);
82
+ }
83
+ return weights;
84
+ };
85
+ /** The tsvector expression over `values`, one per indexed column, weighted when the index has weights. */
86
+ const tsvector = (index, values) => {
87
+ if (!index.weights)
88
+ return `to_tsvector('${index.lang}', ${values.join(" || ' ' || ")})`;
89
+ return values
90
+ .map((value, i) => {
91
+ const weight = index.weights[index.columns[i]];
92
+ const vector = `to_tsvector('${index.lang}', ${value})`;
93
+ return weight ? `setweight(${vector}, '${weight}')` : vector;
94
+ })
95
+ .join(' || ');
96
+ };
97
+ const described = (indexName) => {
98
+ const index = INDEXES.get(indexName);
99
+ if (!index) {
100
+ throw new Error(`No PostgreSQL full-text index named ${JSON.stringify(indexName)} has been described in this process: run its createIndex() first (it is idempotent).`);
101
+ }
102
+ return index;
103
+ };
104
+ /** The language of an index, or 'english' for an index this process has not described. */
105
+ const langOf = (indexName) => INDEXES.get(indexName)?.lang ?? 'english';
62
106
  //# sourceMappingURL=PostgresFts.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"PostgresFts.js","sourceRoot":"","sources":["../../src/fts/PostgresFts.ts"],"names":[],"mappings":"AAEA;;;;;;GAMG;AACH,MAAM,OAAO,WAAW;IAAxB;QACE,+EAA+E;QACvE,kBAAa,GAAG,EAAE,CAAC;QACnB,aAAQ,GAAa,EAAE,CAAC;QACxB,UAAK,GAAG,SAAS,CAAC;IAsD5B,CAAC;IApDC,WAAW,CAAC,MAAuF;QACjG,MAAM,EAAE,GAAG,MAAM,CAAC,YAAY,IAAI,MAAM,CAAC,KAAK,CAAC;QAC/C,IAAI,CAAC,aAAa,GAAG,EAAE,CAAC;QACxB,IAAI,CAAC,QAAQ,GAAG,MAAM,CAAC,OAAO,CAAC;QAC/B,MAAM,SAAS,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;QACtF,MAAM,IAAI,GAAG,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QACrD,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;QAElB,OAAO;YACL,eAAe,EAAE,yCAAyC;YAC1D,kCAAkC,MAAM,CAAC,KAAK,WAAW,EAAE,kBAAkB;YAC7E,UAAU,EAAE,4BAA4B,IAAI,MAAM,SAAS,sBAAsB;SAClF,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAChB,CAAC;IAED,WAAW,CAAC,UAAkB,EAAE,gBAAwB;QACtD,OAAO,4BAA4B,IAAI,CAAC,KAAK,MAAM,gBAAgB,GAAG,CAAC;IACzE,CAAC;IAED,cAAc,CAAC,UAAkB,EAAE,gBAAyB;QAC1D,MAAM,EAAE,GAAG,gBAAgB,IAAI,IAAI,CAAC;QACpC,OAAO,kCAAkC,IAAI,CAAC,KAAK,MAAM,EAAE,IAAI,CAAC;IAClE,CAAC;IAED,cAAc,CAAC,UAAkB;QAC/B,MAAM,EAAE,GAAG,IAAI,CAAC,aAAa,CAAC;QAC9B,MAAM,SAAS,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;QACrF,OAAO,UAAU,EAAE,4BAA4B,IAAI,CAAC,KAAK,MAAM,SAAS,GAAG,CAAC;IAC9E,CAAC;IAED,UAAU,CAAC,UAAkB,EAAE,UAAkB,EAAE,OAAiB;QAClE,MAAM,EAAE,GAAG,IAAI,CAAC,aAAa,CAAC;QAC9B,MAAM,SAAS,GAAG,OAAO;aACtB,GAAG,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,CAAC,aAAa,KAAK,GAAG,CAAC,OAAO,CAAC;aAChD,IAAI,CAAC,aAAa,CAAC,CAAC;QACvB,OAAO,UAAU,EAAE,4BAA4B,IAAI,CAAC,KAAK,MAAM,SAAS,iBAAiB,CAAC;IAC5F,CAAC;IAED,aAAa,CAAC,KAAa;QACzB,OAAO,KAAK,CAAC;IACf,CAAC;IAED,UAAU,CAAC,YAAoB,EAAE,YAAoB,EAAE,SAAiB,EAAE,UAAkB;QAC1F,OAAO,GAAG,YAAY,IAAI,YAAY,EAAE,CAAC;IAC3C,CAAC;IAED,+EAA+E;IACvE,gBAAgB,CAAC,SAAkB;QACzC,IAAI,CAAC,SAAS;YAAE,OAAO,SAAS,CAAC;QACjC,IAAI,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC;YAAE,OAAO,SAAS,CAAC;QACnD,OAAO,QAAQ,CAAC;IAClB,CAAC;CACF"}
1
+ {"version":3,"file":"PostgresFts.js","sourceRoot":"","sources":["../../src/fts/PostgresFts.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ import type { IFullTextSearch } from '../core/contracts/fts.js';
2
+ /**
3
+ * SQLite FTS4 full-text search, for sql.js and the IndexedDB adapter: the
4
+ * stock sql.js build compiles SQLite with FTS3 and FTS4 and without FTS5.
5
+ *
6
+ * Uses FTS4 virtual tables with external content, the porter, unicode61 or
7
+ * simple tokenizer, and rowid joins to the content table. FTS4 has no rank
8
+ * column; relevanceOrder orders by the length of `offsets()`, which grows with
9
+ * the number of matching terms, so the best match comes first.
10
+ */
11
+ export declare class SqliteFts4 implements IFullTextSearch {
12
+ createIndex(config: {
13
+ table: string;
14
+ columns: string[];
15
+ contentTable?: string;
16
+ tokenizer?: string;
17
+ }): string;
18
+ matchClause(indexName: string, queryPlaceholder: string): string;
19
+ rankExpression(indexName: string, _queryPlaceholder?: string): string;
20
+ relevanceOrder(indexName: string, _queryPlaceholder?: string): string;
21
+ rebuildCommand(indexName: string): string;
22
+ syncInsert(indexName: string, rowIdExpr: string, columns: string[]): string;
23
+ sanitizeQuery(input: string): string;
24
+ joinClause(contentTable: string, contentAlias: string, ftsAlias: string, indexName: string): string;
25
+ /** An FTS5-style tokenizer string as an FTS4 tokenizer name. */
26
+ private tokenizer;
27
+ }
28
+ //# sourceMappingURL=SqliteFts4.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SqliteFts4.d.ts","sourceRoot":"","sources":["../../src/fts/SqliteFts4.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAEhE;;;;;;;;GAQG;AACH,qBAAa,UAAW,YAAW,eAAe;IAChD,WAAW,CAAC,MAAM,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,EAAE,CAAC;QAAC,YAAY,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,MAAM;IAO5G,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,GAAG,MAAM;IAIhE,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,iBAAiB,CAAC,EAAE,MAAM,GAAG,MAAM;IAIrE,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,iBAAiB,CAAC,EAAE,MAAM,GAAG,MAAM;IAIrE,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM;IAIzC,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,MAAM;IAK3E,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM;IASpC,UAAU,CAAC,YAAY,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM;IAInG,gEAAgE;IAChE,OAAO,CAAC,SAAS;CAMlB"}
@@ -0,0 +1,56 @@
1
+ /**
2
+ * SQLite FTS4 full-text search, for sql.js and the IndexedDB adapter: the
3
+ * stock sql.js build compiles SQLite with FTS3 and FTS4 and without FTS5.
4
+ *
5
+ * Uses FTS4 virtual tables with external content, the porter, unicode61 or
6
+ * simple tokenizer, and rowid joins to the content table. FTS4 has no rank
7
+ * column; relevanceOrder orders by the length of `offsets()`, which grows with
8
+ * the number of matching terms, so the best match comes first.
9
+ */
10
+ export class SqliteFts4 {
11
+ createIndex(config) {
12
+ const parts = [...config.columns];
13
+ if (config.contentTable)
14
+ parts.push(`content="${config.contentTable}"`);
15
+ parts.push(`tokenize=${this.tokenizer(config.tokenizer)}`);
16
+ return `CREATE VIRTUAL TABLE IF NOT EXISTS ${config.table} USING fts4(${parts.join(', ')})`;
17
+ }
18
+ matchClause(indexName, queryPlaceholder) {
19
+ return `${indexName} MATCH ${queryPlaceholder}`;
20
+ }
21
+ rankExpression(indexName, _queryPlaceholder) {
22
+ return `length(offsets(${indexName}))`;
23
+ }
24
+ relevanceOrder(indexName, _queryPlaceholder) {
25
+ return `length(offsets(${indexName})) DESC`;
26
+ }
27
+ rebuildCommand(indexName) {
28
+ return `INSERT INTO ${indexName}(${indexName}) VALUES('rebuild')`;
29
+ }
30
+ syncInsert(indexName, rowIdExpr, columns) {
31
+ const placeholders = columns.map(() => '?').join(', ');
32
+ return `INSERT INTO ${indexName} (docid, ${columns.join(', ')}) VALUES (${rowIdExpr}, ${placeholders})`;
33
+ }
34
+ sanitizeQuery(input) {
35
+ return input
36
+ .replace(/[*()":^~{}[\]\\]/g, '')
37
+ .split(/\s+/)
38
+ .filter((word) => word.length > 0)
39
+ .map((word) => `"${word}"`)
40
+ .join(' OR ');
41
+ }
42
+ joinClause(contentTable, contentAlias, ftsAlias, indexName) {
43
+ return `${indexName} ${ftsAlias} JOIN ${contentTable} ${contentAlias} ON ${contentAlias}.rowid = ${ftsAlias}.docid`;
44
+ }
45
+ /** An FTS5-style tokenizer string as an FTS4 tokenizer name. */
46
+ tokenizer(tokenizer) {
47
+ if (!tokenizer)
48
+ return 'unicode61';
49
+ if (tokenizer.includes('porter'))
50
+ return 'porter';
51
+ if (tokenizer.includes('unicode61'))
52
+ return 'unicode61';
53
+ return 'simple';
54
+ }
55
+ }
56
+ //# sourceMappingURL=SqliteFts4.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SqliteFts4.js","sourceRoot":"","sources":["../../src/fts/SqliteFts4.ts"],"names":[],"mappings":"AAEA;;;;;;;;GAQG;AACH,MAAM,OAAO,UAAU;IACrB,WAAW,CAAC,MAAuF;QACjG,MAAM,KAAK,GAAG,CAAC,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC;QAClC,IAAI,MAAM,CAAC,YAAY;YAAE,KAAK,CAAC,IAAI,CAAC,YAAY,MAAM,CAAC,YAAY,GAAG,CAAC,CAAC;QACxE,KAAK,CAAC,IAAI,CAAC,YAAY,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;QAC3D,OAAO,sCAAsC,MAAM,CAAC,KAAK,eAAe,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC;IAC9F,CAAC;IAED,WAAW,CAAC,SAAiB,EAAE,gBAAwB;QACrD,OAAO,GAAG,SAAS,UAAU,gBAAgB,EAAE,CAAC;IAClD,CAAC;IAED,cAAc,CAAC,SAAiB,EAAE,iBAA0B;QAC1D,OAAO,kBAAkB,SAAS,IAAI,CAAC;IACzC,CAAC;IAED,cAAc,CAAC,SAAiB,EAAE,iBAA0B;QAC1D,OAAO,kBAAkB,SAAS,SAAS,CAAC;IAC9C,CAAC;IAED,cAAc,CAAC,SAAiB;QAC9B,OAAO,eAAe,SAAS,IAAI,SAAS,qBAAqB,CAAC;IACpE,CAAC;IAED,UAAU,CAAC,SAAiB,EAAE,SAAiB,EAAE,OAAiB;QAChE,MAAM,YAAY,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACvD,OAAO,eAAe,SAAS,YAAY,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,SAAS,KAAK,YAAY,GAAG,CAAC;IAC1G,CAAC;IAED,aAAa,CAAC,KAAa;QACzB,OAAO,KAAK;aACT,OAAO,CAAC,mBAAmB,EAAE,EAAE,CAAC;aAChC,KAAK,CAAC,KAAK,CAAC;aACZ,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC;aACjC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,IAAI,GAAG,CAAC;aAC1B,IAAI,CAAC,MAAM,CAAC,CAAC;IAClB,CAAC;IAED,UAAU,CAAC,YAAoB,EAAE,YAAoB,EAAE,QAAgB,EAAE,SAAiB;QACxF,OAAO,GAAG,SAAS,IAAI,QAAQ,SAAS,YAAY,IAAI,YAAY,OAAO,YAAY,YAAY,QAAQ,QAAQ,CAAC;IACtH,CAAC;IAED,gEAAgE;IACxD,SAAS,CAAC,SAAkB;QAClC,IAAI,CAAC,SAAS;YAAE,OAAO,WAAW,CAAC;QACnC,IAAI,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC;YAAE,OAAO,QAAQ,CAAC;QAClD,IAAI,SAAS,CAAC,QAAQ,CAAC,WAAW,CAAC;YAAE,OAAO,WAAW,CAAC;QACxD,OAAO,QAAQ,CAAC;IAClB,CAAC;CACF"}
@@ -14,6 +14,7 @@ export declare class SqliteFts5 implements IFullTextSearch {
14
14
  }): string;
15
15
  matchClause(indexName: string, queryPlaceholder: string): string;
16
16
  rankExpression(indexName: string, _queryPlaceholder?: string): string;
17
+ relevanceOrder(indexName: string, _queryPlaceholder?: string): string;
17
18
  rebuildCommand(indexName: string): string;
18
19
  syncInsert(indexName: string, rowIdExpr: string, columns: string[]): string;
19
20
  sanitizeQuery(input: string): string;
@@ -1 +1 @@
1
- {"version":3,"file":"SqliteFts5.d.ts","sourceRoot":"","sources":["../../src/fts/SqliteFts5.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAEhE;;;;;GAKG;AACH,qBAAa,UAAW,YAAW,eAAe;IAChD,WAAW,CAAC,MAAM,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,EAAE,CAAC;QAAC,YAAY,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,MAAM;IAY5G,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,GAAG,MAAM;IAIhE,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,iBAAiB,CAAC,EAAE,MAAM,GAAG,MAAM;IAIrE,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM;IAIzC,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,MAAM;IAK3E,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM;IASpC,UAAU,CAAC,YAAY,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM;CAGpG"}
1
+ {"version":3,"file":"SqliteFts5.d.ts","sourceRoot":"","sources":["../../src/fts/SqliteFts5.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAEhE;;;;;GAKG;AACH,qBAAa,UAAW,YAAW,eAAe;IAChD,WAAW,CAAC,MAAM,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,EAAE,CAAC;QAAC,YAAY,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,MAAM;IAY5G,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,GAAG,MAAM;IAIhE,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,iBAAiB,CAAC,EAAE,MAAM,GAAG,MAAM;IAIrE,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,iBAAiB,CAAC,EAAE,MAAM,GAAG,MAAM;IAIrE,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM;IAIzC,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,MAAM;IAK3E,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM;IASpC,UAAU,CAAC,YAAY,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM;CAGpG"}
@@ -22,6 +22,9 @@ export class SqliteFts5 {
22
22
  rankExpression(indexName, _queryPlaceholder) {
23
23
  return `${indexName}.rank`;
24
24
  }
25
+ relevanceOrder(indexName, _queryPlaceholder) {
26
+ return `${indexName}.rank`;
27
+ }
25
28
  rebuildCommand(indexName) {
26
29
  return `INSERT INTO ${indexName}(${indexName}) VALUES('rebuild')`;
27
30
  }
@@ -1 +1 @@
1
- {"version":3,"file":"SqliteFts5.js","sourceRoot":"","sources":["../../src/fts/SqliteFts5.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH,MAAM,OAAO,UAAU;IACrB,WAAW,CAAC,MAAuF;QACjG,MAAM,KAAK,GAAG,CAAC,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC;QAClC,IAAI,MAAM,CAAC,YAAY,EAAE,CAAC;YACxB,KAAK,CAAC,IAAI,CAAC,YAAY,MAAM,CAAC,YAAY,GAAG,CAAC,CAAC;YAC/C,KAAK,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAC;QACtC,CAAC;QACD,IAAI,MAAM,CAAC,SAAS,EAAE,CAAC;YACrB,KAAK,CAAC,IAAI,CAAC,aAAa,MAAM,CAAC,SAAS,GAAG,CAAC,CAAC;QAC/C,CAAC;QACD,OAAO,sCAAsC,MAAM,CAAC,KAAK,eAAe,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC;IAC9F,CAAC;IAED,WAAW,CAAC,SAAiB,EAAE,gBAAwB;QACrD,OAAO,GAAG,SAAS,UAAU,gBAAgB,EAAE,CAAC;IAClD,CAAC;IAED,cAAc,CAAC,SAAiB,EAAE,iBAA0B;QAC1D,OAAO,GAAG,SAAS,OAAO,CAAC;IAC7B,CAAC;IAED,cAAc,CAAC,SAAiB;QAC9B,OAAO,eAAe,SAAS,IAAI,SAAS,qBAAqB,CAAC;IACpE,CAAC;IAED,UAAU,CAAC,SAAiB,EAAE,SAAiB,EAAE,OAAiB;QAChE,MAAM,YAAY,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACvD,OAAO,eAAe,SAAS,YAAY,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,SAAS,KAAK,YAAY,GAAG,CAAC;IAC1G,CAAC;IAED,aAAa,CAAC,KAAa;QACzB,OAAO,KAAK;aACT,OAAO,CAAC,mBAAmB,EAAE,EAAE,CAAC;aAChC,KAAK,CAAC,KAAK,CAAC;aACZ,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;aAC3B,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC;aACpB,IAAI,CAAC,MAAM,CAAC,CAAC;IAClB,CAAC;IAED,UAAU,CAAC,YAAoB,EAAE,YAAoB,EAAE,QAAgB,EAAE,SAAiB;QACxF,OAAO,GAAG,SAAS,IAAI,QAAQ,SAAS,YAAY,IAAI,YAAY,OAAO,YAAY,YAAY,QAAQ,QAAQ,CAAC;IACtH,CAAC;CACF"}
1
+ {"version":3,"file":"SqliteFts5.js","sourceRoot":"","sources":["../../src/fts/SqliteFts5.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH,MAAM,OAAO,UAAU;IACrB,WAAW,CAAC,MAAuF;QACjG,MAAM,KAAK,GAAG,CAAC,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC;QAClC,IAAI,MAAM,CAAC,YAAY,EAAE,CAAC;YACxB,KAAK,CAAC,IAAI,CAAC,YAAY,MAAM,CAAC,YAAY,GAAG,CAAC,CAAC;YAC/C,KAAK,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAC;QACtC,CAAC;QACD,IAAI,MAAM,CAAC,SAAS,EAAE,CAAC;YACrB,KAAK,CAAC,IAAI,CAAC,aAAa,MAAM,CAAC,SAAS,GAAG,CAAC,CAAC;QAC/C,CAAC;QACD,OAAO,sCAAsC,MAAM,CAAC,KAAK,eAAe,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC;IAC9F,CAAC;IAED,WAAW,CAAC,SAAiB,EAAE,gBAAwB;QACrD,OAAO,GAAG,SAAS,UAAU,gBAAgB,EAAE,CAAC;IAClD,CAAC;IAED,cAAc,CAAC,SAAiB,EAAE,iBAA0B;QAC1D,OAAO,GAAG,SAAS,OAAO,CAAC;IAC7B,CAAC;IAED,cAAc,CAAC,SAAiB,EAAE,iBAA0B;QAC1D,OAAO,GAAG,SAAS,OAAO,CAAC;IAC7B,CAAC;IAED,cAAc,CAAC,SAAiB;QAC9B,OAAO,eAAe,SAAS,IAAI,SAAS,qBAAqB,CAAC;IACpE,CAAC;IAED,UAAU,CAAC,SAAiB,EAAE,SAAiB,EAAE,OAAiB;QAChE,MAAM,YAAY,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACvD,OAAO,eAAe,SAAS,YAAY,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,SAAS,KAAK,YAAY,GAAG,CAAC;IAC1G,CAAC;IAED,aAAa,CAAC,KAAa;QACzB,OAAO,KAAK;aACT,OAAO,CAAC,mBAAmB,EAAE,EAAE,CAAC;aAChC,KAAK,CAAC,KAAK,CAAC;aACZ,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;aAC3B,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC;aACpB,IAAI,CAAC,MAAM,CAAC,CAAC;IAClB,CAAC;IAED,UAAU,CAAC,YAAoB,EAAE,YAAoB,EAAE,QAAgB,EAAE,SAAiB;QACxF,OAAO,GAAG,SAAS,IAAI,QAAQ,SAAS,YAAY,IAAI,YAAY,OAAO,YAAY,YAAY,QAAQ,QAAQ,CAAC;IACtH,CAAC;CACF"}
package/dist/index.d.ts CHANGED
@@ -13,12 +13,14 @@ export * from './features/migrations/dataExport.js';
13
13
  export * from './features/migrations/dataImport.js';
14
14
  export * from './features/migrations/migration.js';
15
15
  export * from './features/migrations/schemaMigrations.js';
16
+ export * from './features/auth/authJsAdapter.js';
16
17
  export * from './features/sync/syncManager.js';
17
18
  export * from './shared/parameterUtils.js';
18
19
  export { segmentFilePath, segmentName, validateSegment } from './shared/segment.js';
19
20
  export { SqliteDialect } from './dialects/SqliteDialect.js';
20
21
  export { PostgresDialect } from './dialects/PostgresDialect.js';
21
22
  export { SqliteFts5 } from './fts/SqliteFts5.js';
23
+ export { SqliteFts4 } from './fts/SqliteFts4.js';
22
24
  export { PostgresFts } from './fts/PostgresFts.js';
23
25
  export { NodeBlobCodec } from './codecs/NodeBlobCodec.js';
24
26
  export { BrowserBlobCodec } from './codecs/BrowserBlobCodec.js';