@enbox/dwn-sql-store 0.0.9 → 0.0.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE CHANGED
@@ -1,3 +1,4 @@
1
+
1
2
  Apache License
2
3
  Version 2.0, January 2004
3
4
  http://www.apache.org/licenses/
@@ -186,7 +187,7 @@
186
187
  same "printed page" as the copyright notice for easier
187
188
  identification within third-party archives.
188
189
 
189
- Copyright [yyyy] [name of copyright owner]
190
+ Copyright 2025 Liran Cohen
190
191
 
191
192
  Licensed under the Apache License, Version 2.0 (the "License");
192
193
  you may not use this file except in compliance with the License.
@@ -198,4 +199,4 @@
198
199
  distributed under the License is distributed on an "AS IS" BASIS,
199
200
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200
201
  See the License for the specific language governing permissions and
201
- limitations under the License.
202
+ limitations under the License.
@@ -1,4 +1,4 @@
1
- import { DynamicModule } from 'kysely';
1
+ import { DynamicModule, sql } from 'kysely';
2
2
  import { sanitizedValue, sanitizeFiltersAndSeparateTags } from './sanitize.js';
3
3
  /**
4
4
  * Takes multiple Filters and returns a single query.
@@ -36,6 +36,15 @@ function processFilter(eb, andOperands, filter) {
36
36
  andOperands.push(eb(column, 'in', value));
37
37
  }
38
38
  else if (typeof value === 'object') { // RangeFilter
39
+ // Detect prefix-style range filters created by `constructPrefixFilterAsRangeFilter`
40
+ // which uses `{ gte: prefix, lt: prefix + '\uffff' }`. The U+FFFF sentinel does not
41
+ // sort correctly under ICU/libc collation rules (e.g. PostgreSQL's en_US.UTF-8),
42
+ // so we convert these to a collation-safe SQL LIKE expression.
43
+ if (isPrefixRangeFilter(value)) {
44
+ const prefix = escapeLikePattern(value.gte);
45
+ andOperands.push(sql `${sql.ref(property)} LIKE ${prefix + '%'}`);
46
+ continue;
47
+ }
39
48
  if (value.gt) {
40
49
  andOperands.push(eb(column, '>', sanitizedValue(value.gt)));
41
50
  }
@@ -54,6 +63,28 @@ function processFilter(eb, andOperands, filter) {
54
63
  }
55
64
  }
56
65
  }
66
+ /**
67
+ * Returns `true` if the given RangeFilter matches the pattern produced by
68
+ * `constructPrefixFilterAsRangeFilter`: `{ gte: <prefix>, lt: <prefix> + '\uffff' }`.
69
+ */
70
+ function isPrefixRangeFilter(value) {
71
+ if (typeof value.gte !== 'string' || typeof value.lt !== 'string') {
72
+ return false;
73
+ }
74
+ // Only two keys: gte and lt (no gt, lte, or other properties)
75
+ const keys = Object.keys(value);
76
+ if (keys.length !== 2 || !keys.includes('gte') || !keys.includes('lt')) {
77
+ return false;
78
+ }
79
+ return value.lt === value.gte + '\uffff';
80
+ }
81
+ /**
82
+ * Escapes SQL LIKE meta-characters (`%`, `_`) in the given string so that
83
+ * they are matched literally.
84
+ */
85
+ function escapeLikePattern(input) {
86
+ return input.replace(/%/g, '\\%').replace(/_/g, '\\_');
87
+ }
57
88
  /**
58
89
  * Processes each property in the tags filter as an AND operand and adds it to the `andOperands` array.
59
90
  * If a property has an array of values it will treat it as a OneOf (IN) within the overall AND query.
@@ -1 +1 @@
1
- {"version":3,"file":"filter.js","sourceRoot":"","sources":["../../../../src/utils/filter.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"filter.js","sourceRoot":"","sources":["../../../../src/utils/filter.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@enbox/dwn-sql-store",
3
- "version": "0.0.9",
3
+ "version": "0.0.10",
4
4
  "description": "SQL backed implementations of DWN MessageStore, DataStore, and StateIndex",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
@@ -25,7 +25,7 @@
25
25
  "dependencies": {
26
26
  "@aws-sdk/client-s3": "^3.700.0",
27
27
  "@aws-sdk/lib-storage": "^3.700.0",
28
- "@enbox/dwn-sdk-js": "0.1.0",
28
+ "@enbox/dwn-sdk-js": "0.1.1",
29
29
  "@ipld/dag-cbor": "9.0.5",
30
30
  "interface-blockstore": "5.2.3",
31
31
  "interface-store": "5.1.2",
@@ -2,7 +2,7 @@ import type { DwnDatabaseType } from '../types.js';
2
2
  import type { Filter } from '@enbox/dwn-sdk-js';
3
3
  import type { ExpressionBuilder, OperandExpression, SelectQueryBuilder, SqlBool } from 'kysely';
4
4
 
5
- import { DynamicModule } from 'kysely';
5
+ import { DynamicModule, sql } from 'kysely';
6
6
  import { sanitizedValue, sanitizeFiltersAndSeparateTags } from './sanitize.js';
7
7
 
8
8
  /**
@@ -52,6 +52,16 @@ function processFilter<DB = DwnDatabaseType, TB extends keyof DB = keyof DB>(
52
52
  if (Array.isArray(value)) { // OneOfFilter
53
53
  andOperands.push(eb(column, 'in', value));
54
54
  } else if (typeof value === 'object') { // RangeFilter
55
+ // Detect prefix-style range filters created by `constructPrefixFilterAsRangeFilter`
56
+ // which uses `{ gte: prefix, lt: prefix + '\uffff' }`. The U+FFFF sentinel does not
57
+ // sort correctly under ICU/libc collation rules (e.g. PostgreSQL's en_US.UTF-8),
58
+ // so we convert these to a collation-safe SQL LIKE expression.
59
+ if (isPrefixRangeFilter(value)) {
60
+ const prefix = escapeLikePattern(value.gte as string);
61
+ andOperands.push(sql`${sql.ref(property)} LIKE ${prefix + '%'}`);
62
+ continue;
63
+ }
64
+
55
65
  if (value.gt) {
56
66
  andOperands.push(eb(column, '>', sanitizedValue(value.gt)));
57
67
  }
@@ -70,6 +80,30 @@ function processFilter<DB = DwnDatabaseType, TB extends keyof DB = keyof DB>(
70
80
  }
71
81
  }
72
82
 
83
+ /**
84
+ * Returns `true` if the given RangeFilter matches the pattern produced by
85
+ * `constructPrefixFilterAsRangeFilter`: `{ gte: <prefix>, lt: <prefix> + '\uffff' }`.
86
+ */
87
+ function isPrefixRangeFilter(value: Record<string, unknown>): boolean {
88
+ if (typeof value.gte !== 'string' || typeof value.lt !== 'string') {
89
+ return false;
90
+ }
91
+ // Only two keys: gte and lt (no gt, lte, or other properties)
92
+ const keys = Object.keys(value);
93
+ if (keys.length !== 2 || !keys.includes('gte') || !keys.includes('lt')) {
94
+ return false;
95
+ }
96
+ return value.lt === value.gte + '\uffff';
97
+ }
98
+
99
+ /**
100
+ * Escapes SQL LIKE meta-characters (`%`, `_`) in the given string so that
101
+ * they are matched literally.
102
+ */
103
+ function escapeLikePattern(input: string): string {
104
+ return input.replace(/%/g, '\\%').replace(/_/g, '\\_');
105
+ }
106
+
73
107
  /**
74
108
  * Processes each property in the tags filter as an AND operand and adds it to the `andOperands` array.
75
109
  * If a property has an array of values it will treat it as a OneOf (IN) within the overall AND query.