Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 0 additions & 5 deletions .changeset/funny-pianos-allow.md

This file was deleted.

5 changes: 0 additions & 5 deletions .changeset/green-books-shout.md

This file was deleted.

2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ on:

jobs:
test-service-container-build:
name: Build and Test Powersync Service
name: Build and Test PowerSync Service
runs-on: ubuntu-latest
steps:
- name: Checkout
Expand Down
4 changes: 2 additions & 2 deletions DEVELOP.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ pnpm build

## Dependent Services

The PowerSync service requires Postgres and MongoDB server connections. These configuration details can be specified in a `powersync.yaml` (or JSON) configuration file.
The PowerSync Service requires Postgres and MongoDB server connections. These configuration details can be specified in a `powersync.yaml` (or JSON) configuration file.

See the [self-hosting demo](https://github.com/powersync-ja/self-host-demo) for demos of starting these services.

Expand All @@ -36,7 +36,7 @@ One method to obtain access is to add the following to `/etc/hosts` (on Unix-lik
127.0.0.1 mongo
```

This will start all the services defined in the Self hosting demo except for the PowerSync service - which will be started from this repository.
This will start all the services defined in the self-hosting demo except for the PowerSync Service - which will be started from this repository.

## Local Configuration

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<a href="https://www.powersync.com" target="_blank"><img src="https://github.com/powersync-ja/.github/assets/7372448/d2538c43-c1a0-4c47-9a76-41462dba484f"/></a>
</p>

_[PowerSync](https://www.powersync.com) is a sync engine for building local-first apps with instantly-responsive UI/UX and simplified state transfer. Syncs between SQLite on the client-side and Postgres or MongoDB on the server-side (MySQL coming soon)._
_[PowerSync](https://www.powersync.com) is a sync engine for building local-first apps with instantly-responsive UI/UX and simplified state transfer. Syncs between SQLite on the client-side and Postgres, MongoDB or MySQL on the server-side._

# PowerSync Service

Expand Down
7 changes: 3 additions & 4 deletions modules/module-postgres/src/types/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,11 +142,10 @@ export function validatePort(port: string | number): number {
if (typeof port == 'string') {
port = parseInt(port);
}
if (port >= 1024 && port <= 49151) {
return port;
} else {
if (port < 1024) {
throw new Error(`Port ${port} not supported`);
}
}
return port;
}

/**
Expand Down
15 changes: 15 additions & 0 deletions packages/service-core/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,20 @@
# @powersync/service-core

## 0.8.7

### Patch Changes

- 6b72e6c: Improved Postgres connection port restrictions. Connections are now supported on ports >= 1024.

## 0.8.6

### Patch Changes

- 2d3bb6a: Fix "operation exceeded time limit" error
- 17a6db0: Fix storageStats error in metrics endpoint when collections don't exist.
- Updated dependencies [0f90b02]
- @powersync/[email protected]

## 0.8.5

### Patch Changes
Expand Down
4 changes: 2 additions & 2 deletions packages/service-core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@
"publishConfig": {
"access": "public"
},
"version": "0.8.5",
"version": "0.8.7",
"main": "dist/index.js",
"license": "FSL-1.1-Apache-2.0",
"type": "module",
"scripts": {
"build": "tsc -b",
"build:tests": "tsc -b test/tsconfig.json",
"test": "vitest",
"clean": "rm -rf ./lib && tsc -b --clean"
"clean": "rm -rf ./dist && tsc -b --clean"
},
"dependencies": {
"@js-sdsl/ordered-set": "^4.4.2",
Expand Down
6 changes: 6 additions & 0 deletions packages/sync-rules/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# @powersync/service-sync-rules

## 0.20.0

### Minor Changes

- 0f90b02: Support substring and json_keys functions in sync rules

## 0.19.0

### Minor Changes
Expand Down
2 changes: 1 addition & 1 deletion packages/sync-rules/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@powersync/service-sync-rules",
"repository": "https://github.com/powersync-ja/powersync-service",
"version": "0.19.0",
"version": "0.20.0",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"license": "FSL-1.1-Apache-2.0",
Expand Down
83 changes: 83 additions & 0 deletions packages/sync-rules/src/sql_functions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,61 @@ const lower: DocumentedSqlFunction = {
detail: 'Convert text to lower case'
};

const substring: DocumentedSqlFunction = {
debugName: 'substring',
call(value: SqliteValue, start: SqliteValue, length?: SqliteValue) {
const text = castAsText(value);
if (text == null) {
return null;
}
const startIndex = cast(start, 'integer') as bigint | null;
if (startIndex == null) {
return null;
}
if (length === null) {
// Different from undefined in this case, to match SQLite behavior
return null;
}
const castLength = cast(length ?? null, 'integer') as bigint | null;
let realLength: number;
if (castLength == null) {
// undefined (not specified)
realLength = text.length + 1; // +1 to account for the start = 0 special case
} else {
realLength = Number(castLength);
}

let realStart = 0;
if (startIndex < 0n) {
realStart = Math.max(0, text.length + Number(startIndex));
} else if (startIndex == 0n) {
// Weird special case
realStart = 0;
realLength -= 1;
} else {
realStart = Number(startIndex) - 1;
}

if (realLength < 0) {
// Negative length means we return that many characters _before_
// the start index.
return text.substring(realStart + realLength, realStart);
}

return text.substring(realStart, realStart + realLength);
},
parameters: [
{ name: 'value', type: ExpressionType.TEXT, optional: false },
{ name: 'start', type: ExpressionType.INTEGER, optional: false },
{ name: 'length', type: ExpressionType.INTEGER, optional: true }
],
getReturnType(args) {
return ExpressionType.TEXT;
},
detail: 'Compute a substring',
documentation: 'The start index starts at 1. If no length is specified, the remainder of the string is returned.'
};

const hex: DocumentedSqlFunction = {
debugName: 'hex',
call(value: SqliteValue) {
Expand Down Expand Up @@ -235,6 +290,32 @@ const json_valid: DocumentedSqlFunction = {
documentation: 'Returns 1 if valid, 0 if invalid'
};

const json_keys: DocumentedSqlFunction = {
debugName: 'json_keys',
call(json: SqliteValue) {
const jsonString = castAsText(json);
if (jsonString == null) {
return null;
}

const jsonParsed = JSONBig.parse(jsonString);
if (typeof jsonParsed != 'object') {
throw new Error(`Cannot call json_keys on a scalar`);
} else if (Array.isArray(jsonParsed)) {
throw new Error(`Cannot call json_keys on an array`);
}
const keys = Object.keys(jsonParsed as {});
// Keys are always strings, safe to use plain JSON.
return JSON.stringify(keys);
},
parameters: [{ name: 'json', type: ExpressionType.ANY, optional: false }],
getReturnType(args) {
// TODO: proper nullable types
return ExpressionType.TEXT;
},
detail: 'Returns the keys of a JSON object as a JSON array'
};

const unixepoch: DocumentedSqlFunction = {
debugName: 'unixepoch',
call(value?: SqliteValue, specifier?: SqliteValue, specifier2?: SqliteValue) {
Expand Down Expand Up @@ -401,6 +482,7 @@ const st_y: DocumentedSqlFunction = {
export const SQL_FUNCTIONS_NAMED = {
upper,
lower,
substring,
hex,
length,
base64,
Expand All @@ -409,6 +491,7 @@ export const SQL_FUNCTIONS_NAMED = {
json_extract,
json_array_length,
json_valid,
json_keys,
unixepoch,
datetime,
st_asgeojson,
Expand Down
40 changes: 40 additions & 0 deletions packages/sync-rules/test/src/sql_functions.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,30 @@ describe('SQL functions', () => {
expect(fn.json_array_length(`{"a":[1,2,3,4]}`)).toEqual(0n);
});

test('json_keys', () => {
expect(fn.json_keys(`{"a": 1, "b": "2", "0": "test", "c": {"d": "e"}}`)).toEqual(`["0","a","b","c"]`);
expect(fn.json_keys(`{}`)).toEqual(`[]`);
expect(fn.json_keys(null)).toEqual(null);
expect(fn.json_keys()).toEqual(null);
expect(() => fn.json_keys(`{"a": 1, "a": 2}`)).toThrow();
expect(() => fn.json_keys(`[1,2,3]`)).toThrow();
expect(() => fn.json_keys(3)).toThrow();
});

test('json_valid', () => {
expect(fn.json_valid(`{"a": 1, "b": "2", "0": "test", "c": {"d": "e"}}`)).toEqual(1n);
expect(fn.json_valid(`{}`)).toEqual(1n);
expect(fn.json_valid(null)).toEqual(0n);
expect(fn.json_valid()).toEqual(0n);
expect(fn.json_valid(`{"a": 1, "a": 2}`)).toEqual(0n);
expect(fn.json_valid(`[1,2,3]`)).toEqual(1n);
expect(fn.json_valid(3)).toEqual(1n);
expect(fn.json_valid('test')).toEqual(0n);
expect(fn.json_valid('"test"')).toEqual(1n);
expect(fn.json_valid('true')).toEqual(1n);
expect(fn.json_valid('TRUE')).toEqual(0n);
});

test('typeof', () => {
expect(fn.typeof(null)).toEqual('null');
expect(fn.typeof('test')).toEqual('text');
Expand Down Expand Up @@ -101,6 +125,22 @@ describe('SQL functions', () => {
expect(fn.lower(Uint8Array.of(0x61, 0x62, 0x43))).toEqual('abc');
});

test('substring', () => {
expect(fn.substring(null)).toEqual(null);
expect(fn.substring('abc')).toEqual(null);
expect(fn.substring('abcde', 2, 3)).toEqual('bcd');
expect(fn.substring('abcde', 2)).toEqual('bcde');
expect(fn.substring('abcde', 2, null)).toEqual(null);
expect(fn.substring('abcde', 0, 1)).toEqual('');
expect(fn.substring('abcde', 0, 2)).toEqual('a');
expect(fn.substring('abcde', 1, 2)).toEqual('ab');
expect(fn.substring('abcde', -2)).toEqual('de');
expect(fn.substring('abcde', -2, 1)).toEqual('d');
expect(fn.substring('abcde', 6, -5)).toEqual('abcde');
expect(fn.substring('abcde', 5, -2)).toEqual('cd');
expect(fn.substring('2023-06-28 14:12:00.999Z', 1, 10)).toEqual('2023-06-28');
});

test('cast', () => {
expect(cast(null, 'text')).toEqual(null);
expect(cast(null, 'integer')).toEqual(null);
Expand Down
17 changes: 17 additions & 0 deletions service/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,22 @@
# @powersync/service-image

## 0.5.7

### Patch Changes

- Updated dependencies [6b72e6c]
- @powersync/[email protected]

## 0.5.6

### Patch Changes

- Updated dependencies [2d3bb6a]
- Updated dependencies [17a6db0]
- Updated dependencies [0f90b02]
- @powersync/[email protected]
- @powersync/[email protected]

## 0.5.5

### Patch Changes
Expand Down
2 changes: 1 addition & 1 deletion service/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<a href="https://www.powersync.com" target="_blank"><img src="https://github.com/powersync-ja/.github/assets/7372448/d2538c43-c1a0-4c47-9a76-41462dba484f"/></a>
</p>

_[PowerSync](https://www.powersync.com) is a sync engine for building local-first apps with instantly-responsive UI/UX and simplified state transfer. Syncs between SQLite on the client-side and Postgres or MongoDB on the server-side (MySQL coming soon)._
_[PowerSync](https://www.powersync.com) is a sync engine for building local-first apps with instantly-responsive UI/UX and simplified state transfer. Syncs between SQLite on the client-side and Postgres, MongoDB or MySQL on the server-side._

# Quick reference

Expand Down
2 changes: 1 addition & 1 deletion service/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@powersync/service-image",
"version": "0.5.5",
"version": "0.5.7",
"private": true,
"license": "FSL-1.1-Apache-2.0",
"type": "module",
Expand Down
15 changes: 15 additions & 0 deletions test-client/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,20 @@
# test-client

## 0.1.9

### Patch Changes

- Updated dependencies [6b72e6c]
- @powersync/[email protected]

## 0.1.8

### Patch Changes

- Updated dependencies [2d3bb6a]
- Updated dependencies [17a6db0]
- @powersync/[email protected]

## 0.1.7

### Patch Changes
Expand Down
2 changes: 1 addition & 1 deletion test-client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "test-client",
"repository": "https://github.com/powersync-ja/powersync-service",
"private": true,
"version": "0.1.7",
"version": "0.1.9",
"main": "dist/index.js",
"bin": "dist/bin.js",
"license": "Apache-2.0",
Expand Down
Loading